From a90774bab393eaaec886fa09d664c9ad81a17414 Mon Sep 17 00:00:00 2001 From: Pavel Brui Date: Fri, 1 Sep 2023 15:15:03 +0200 Subject: [PATCH] crudToIgraphQL --- packages/integrations/gei-crud/package.json | 2 +- .../gei-crud/src/Mutation/create.ts | 8 +-- .../gei-crud/src/Mutation/delete.ts | 62 ++++++++-------- .../gei-crud/src/Mutation/update.ts | 32 +++++---- .../gei-crud/src/Object/oneToMany.ts | 7 +- .../gei-crud/src/Object/oneToOne.ts | 4 +- .../gei-crud/src/Query/objects.ts | 71 ++++++++++--------- .../gei-crud/src/Query/oneById.ts | 4 +- .../integrations/gei-crud/src/db/mongo.ts | 19 ----- packages/integrations/gei-crud/src/db/orm.ts | 16 +++++ 10 files changed, 111 insertions(+), 114 deletions(-) delete mode 100644 packages/integrations/gei-crud/src/db/mongo.ts create mode 100644 packages/integrations/gei-crud/src/db/orm.ts diff --git a/packages/integrations/gei-crud/package.json b/packages/integrations/gei-crud/package.json index c043855..f929ae7 100644 --- a/packages/integrations/gei-crud/package.json +++ b/packages/integrations/gei-crud/package.json @@ -1,6 +1,6 @@ { "name": "gei-crud", - "version": "0.8.6", + "version": "0.8.7", "description": "GraphQL Editor integration for stucco. Allows basic crud operations and relations.", "main": "lib/index.js", "private": false, diff --git a/packages/integrations/gei-crud/src/Mutation/create.ts b/packages/integrations/gei-crud/src/Mutation/create.ts index 6eff68a..ac5a9fe 100644 --- a/packages/integrations/gei-crud/src/Mutation/create.ts +++ b/packages/integrations/gei-crud/src/Mutation/create.ts @@ -1,7 +1,7 @@ import { ObjectId, OptionalId } from 'mongodb'; import { FieldResolveInput } from 'stucco-js'; import { prepareModel, prepareSourceParameters } from '../data.js'; -import { DB } from '../db/mongo.js'; +import { DB } from '../db/orm.js'; import { getReturnTypeName } from '../shared.js'; export const handler = async (input: FieldResolveInput) => @@ -21,8 +21,8 @@ export const handler = async (input: FieldResolveInput) => createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), }; - return db - .collection(prepareModel(input)) - .insertOne(creationInput) + + return db(prepareModel(input)) + .collection.insertOne(creationInput) .then((result) => result.insertedId); }); diff --git a/packages/integrations/gei-crud/src/Mutation/delete.ts b/packages/integrations/gei-crud/src/Mutation/delete.ts index 002b4f4..8e0e8d0 100644 --- a/packages/integrations/gei-crud/src/Mutation/delete.ts +++ b/packages/integrations/gei-crud/src/Mutation/delete.ts @@ -1,11 +1,6 @@ import { FieldResolveInput } from 'stucco-js'; -import { - prepareModel, - prepare_id, - prepareSourceParameters, - prepareRelatedField, -} from '../data.js'; -import { DB } from '../db/mongo.js'; +import { prepareModel, prepare_id, prepareSourceParameters, prepareRelatedField } from '../data.js'; +import { DB } from '../db/orm.js'; import { getResolverData } from '../shared.js'; export const handler = async (input: FieldResolveInput) => { @@ -14,12 +9,12 @@ export const handler = async (input: FieldResolveInput) => { const _id = prepare_id(input) || prepareSourceParameters(input)._id; if (!_id) throw new Error('_id not found'); - const object = await db.collection(prepareModel(input)).findOne({ _id }); + const object = await db(prepareModel(input)).collection.findOne({ _id }); if (!object) { throw new Error('Object with this _id not found'); } - const res = await db.collection(prepareModel(input)).deleteOne({ _id, ...prepareSourceParameters(input) }); + const res = await db(prepareModel(input)).collection.deleteOne({ _id, ...prepareSourceParameters(input) }); if (!res.deletedCount) { throw new Error( `Object not found. Please check parameters: ${JSON.stringify({ _id, ...prepareSourceParameters(input) })}`, @@ -27,35 +22,38 @@ export const handler = async (input: FieldResolveInput) => { } const { data } = getResolverData<{ relatedModel: string }>(input); - const relatedCollectionsField = data?.relatedModel.value; - if (relatedCollectionsField) { + const relatedCollectionsField = data?.relatedModel?.value; + console.log(relatedCollectionsField?.length); + console.log(relatedCollectionsField); - const s = object as Record; - const relatedCollections = relatedCollectionsField.replace(/["' ]/g, '').split(','); - const prepareFields = prepareRelatedField(input)?.replace(/[{ }]/g, '').split(','); - let i = 0; - for (const rC of relatedCollections) { - const prepareField = prepareFields[i]?.split(':') || prepareFields[0]?.split(':'); - i++; - if (prepareField) { - const fieldForFounding = prepareField[0]; - const fieldWithIdOrArray = prepareField[1] || undefined; + if (relatedCollectionsField && relatedCollectionsField?.length > 2) { + console.log('kkdlckm'); + const s = object as Record; + const relatedCollections = relatedCollectionsField.replace(/["' ]/g, '').split(','); + const prepareFields = prepareRelatedField(input)?.replace(/[{ }]/g, '').split(','); + let i = 0; + for (const rC of relatedCollections) { + const prepareField = prepareFields[i]?.split(':') || prepareFields[0]?.split(':'); + i++; + if (prepareField) { + const fieldForFounding = prepareField[0]; + const fieldWithIdOrArray = prepareField[1] || undefined; - if (!fieldWithIdOrArray) { - await db.collection(rC).updateMany({}, { $pull: { [fieldForFounding]: s._id } }); - await db.collection(rC).deleteMany({ [fieldForFounding]: s._id }); - } else if (!s[fieldWithIdOrArray]?.length) { - return !!res.deletedCount; - } else { - if (typeof s[fieldWithIdOrArray] === 'string') { - await db.collection(rC).updateMany({}, { $pull: { [fieldForFounding]: s[fieldWithIdOrArray] } }); - await db.collection(rC).deleteMany({ [fieldForFounding]: s[fieldWithIdOrArray] }); + if (!fieldWithIdOrArray) { + await db(rC).collection.updateMany({}, { $pull: { [fieldForFounding]: s._id } }); + await db(rC).collection.deleteMany({ [fieldForFounding]: s._id }); + } else if (!s[fieldWithIdOrArray]?.length) { + return !!res.deletedCount; } else { - await db.collection(rC).deleteMany({ [fieldForFounding]: { $in: s[fieldWithIdOrArray] } }); + if (typeof s[fieldWithIdOrArray] === 'string') { + await db(rC).collection.updateMany({}, { $pull: { [fieldForFounding]: s[fieldWithIdOrArray] } }); + await db(rC).collection.deleteMany({ [fieldForFounding]: s[fieldWithIdOrArray] }); + } else { + await db(rC).collection.deleteMany({ [fieldForFounding]: { $in: s[fieldWithIdOrArray] } }); + } } } } } -} return !!res.deletedCount; }; diff --git a/packages/integrations/gei-crud/src/Mutation/update.ts b/packages/integrations/gei-crud/src/Mutation/update.ts index d7d8b25..9328282 100644 --- a/packages/integrations/gei-crud/src/Mutation/update.ts +++ b/packages/integrations/gei-crud/src/Mutation/update.ts @@ -1,6 +1,6 @@ import { FieldResolveInput } from 'stucco-js'; import { prepareModel, prepare_id, prepareSourceParameters } from '../data.js'; -import { DB } from '../db/mongo.js'; +import { DB } from '../db/orm.js'; export const handler = async (input: FieldResolveInput) => DB().then(async (db) => { @@ -8,27 +8,29 @@ export const handler = async (input: FieldResolveInput) => if (!_id) throw new Error('_id not found'); const entries = Object.entries(input.arguments || {}); const reconstructedObject: Record = {}; - + const entriesWithOutId = entries.filter((e) => e[0] !== '_id'); if (!entriesWithOutId) { throw new Error(`You need update input argument for this resolver to work`); } - - if (typeof entriesWithOutId[0][1] ==='object' ) { - if(entriesWithOutId[1]) throw new Error( - 'There should be only string arguments or _id argument and one argument of "input" type to update this model', - ) - } else{ - (entriesWithOutId as [string, any][]).forEach((entry: [string, any]) => { + + if (typeof entriesWithOutId[0][1] === 'object') { + if (entriesWithOutId[1]) + throw new Error( + 'There should be only string arguments or _id argument and one argument of "input" type to update this model', + ); + } else { + (entriesWithOutId as [string, any][]).forEach((entry: [string, any]) => { const [key, value] = entry; reconstructedObject[key] = value; }); } - const setter = typeof entriesWithOutId[0][1] ==='object' ? entriesWithOutId[0][1] : reconstructedObject + const setter = typeof entriesWithOutId[0][1] === 'object' ? entriesWithOutId[0][1] : reconstructedObject; const filterInput: Record = { _id, ...prepareSourceParameters(input) }; - const res = await db - .collection(prepareModel(input)) - .updateOne(filterInput, { $set: { ...(setter), updatedAt: new Date().toISOString() } }) - if(res.matchedCount<1) throw new Error(`Object for update not found. Please check parameters: ${ JSON.stringify(filterInput)}`) - return res.modifiedCount>=1 + const res = await db(prepareModel(input)).collection.updateOne(filterInput, { + $set: { ...setter, updatedAt: new Date().toISOString() }, + }); + if (res.matchedCount < 1) + throw new Error(`Object for update not found. Please check parameters: ${JSON.stringify(filterInput)}`); + return res.modifiedCount >= 1; }); diff --git a/packages/integrations/gei-crud/src/Object/oneToMany.ts b/packages/integrations/gei-crud/src/Object/oneToMany.ts index b92f5c6..ebe4e1f 100644 --- a/packages/integrations/gei-crud/src/Object/oneToMany.ts +++ b/packages/integrations/gei-crud/src/Object/oneToMany.ts @@ -1,6 +1,6 @@ import { FieldResolveInput } from 'stucco-js'; import { prepareRelatedField, prepareRelatedModel } from '../data.js'; -import { DB } from '../db/mongo.js'; +import { DB } from '../db/orm.js'; export const handler = async (input: FieldResolveInput) => { return DB().then(async (db) => { @@ -26,9 +26,8 @@ export const handler = async (input: FieldResolveInput) => { } } - return db - .collection(prepareRelatedModel(input)) - .find({ + return db(prepareRelatedModel(input)) + .collection.find({ [fieldForFounding]: fieldWithArray ? { $in: s[fieldWithArray] } : s._id, }) .toArray(); diff --git a/packages/integrations/gei-crud/src/Object/oneToOne.ts b/packages/integrations/gei-crud/src/Object/oneToOne.ts index c4fb3b3..a7d9466 100644 --- a/packages/integrations/gei-crud/src/Object/oneToOne.ts +++ b/packages/integrations/gei-crud/src/Object/oneToOne.ts @@ -1,6 +1,6 @@ import { FieldResolveInput } from 'stucco-js'; import { prepareRelatedField, prepareRelatedModel } from '../data.js'; -import { DB } from '../db/mongo.js'; +import { DB } from '../db/orm.js'; export const handler = async (input: FieldResolveInput) => DB().then(async (db) => { @@ -15,5 +15,5 @@ export const handler = async (input: FieldResolveInput) => const field = prepareField[0]; const objectField = prepareField[1] ? prepareField[1] : undefined; if (objectField && typeof s[objectField] !== 'string') return objectField; - return db.collection(prepareRelatedModel(input)).findOne({ [field]: objectField || s._id }); + return db(prepareRelatedModel(input)).collection.findOne({ [field]: objectField || s._id }); }); diff --git a/packages/integrations/gei-crud/src/Query/objects.ts b/packages/integrations/gei-crud/src/Query/objects.ts index 6e5c56e..e02f73d 100644 --- a/packages/integrations/gei-crud/src/Query/objects.ts +++ b/packages/integrations/gei-crud/src/Query/objects.ts @@ -1,26 +1,35 @@ import { FieldResolveInput } from 'stucco-js'; import { prepareModel, prepareSourceParameters } from '../data.js'; -import { DB } from '../db/mongo.js'; +import { DB } from '../db/orm.js'; export const handler = async (input: FieldResolveInput) => { return DB().then((db) => { - const sortArg = input.arguments?.sortByField || input.arguments?.sort - const sort = (typeof sortArg === 'object') ? sortArg as {field: string, order?: boolean} : undefined - const field = snakeCaseToCamelCase(sort?.field as unknown as string) - const fieldFilter = input.arguments?.fieldFilter - const dateFilter =input.arguments?.dateFilter - const fieldRegexFilter: any = input.arguments?.fieldRegexFilter ? input.arguments?.fieldRegexFilter : fieldFilter ? {} : checkStringFields(input.arguments)? input.arguments : {} - if (fieldRegexFilter?.sortByField) delete fieldRegexFilter?.sortByField - if (fieldRegexFilter?.sort) delete fieldRegexFilter?.sort - if (fieldRegexFilter?.dateFilter) delete fieldRegexFilter?.dateFilter + const sortArg = input.arguments?.sortByField || input.arguments?.sort; + const sort = typeof sortArg === 'object' ? (sortArg as { field: string; order?: boolean }) : undefined; + const field = snakeCaseToCamelCase(sort?.field as unknown as string); + const fieldFilter = input.arguments?.fieldFilter; + const dateFilter = input.arguments?.dateFilter; + const fieldRegexFilter: any = input.arguments?.fieldRegexFilter + ? input.arguments?.fieldRegexFilter + : fieldFilter + ? {} + : checkStringFields(input.arguments) + ? input.arguments + : {}; + if (fieldRegexFilter?.sortByField) delete fieldRegexFilter?.sortByField; + if (fieldRegexFilter?.sort) delete fieldRegexFilter?.sort; + if (fieldRegexFilter?.dateFilter) delete fieldRegexFilter?.dateFilter; const filterInput = { ...prepareSourceParameters(input), ...convertDateFilter(dateFilter as QueryObject), - ...(ifValueIsArray(fieldFilter as QueryObject)), + ...ifValueIsArray(fieldFilter as QueryObject), ...convertObjectToRegexFormat(ifValueIsArray(fieldRegexFilter) as QueryObject), }; - - return db.collection(prepareModel(input)).find(filterInput).sort(field ? { [field]: sort?.order === false ? -1 : 1 } : { _id: 1 }).toArray(); + + return db(prepareModel(input)) + .collection.find(filterInput) + .sort(field ? { [field]: sort?.order === false ? -1 : 1 } : { _id: 1 }) + .toArray(); }); }; @@ -28,49 +37,41 @@ interface QueryObject { [key: string]: unknown; } - // Function to convert the object to the desired format function convertObjectToRegexFormat(obj: QueryObject): QueryObject | undefined { - - for (const key in obj) { - if (Array.isArray(obj[key])) obj[key] = { $regex: { $in: obj[key]}, $options: 'i' } - if (obj[key]&& typeof obj[key] === 'string' ) obj[key] = { $regex: obj[key], $options: 'i' }; + if (Array.isArray(obj[key])) obj[key] = { $regex: { $in: obj[key] }, $options: 'i' }; + if (obj[key] && typeof obj[key] === 'string') obj[key] = { $regex: obj[key], $options: 'i' }; } return obj; } - function ifValueIsArray(obj: QueryObject): QueryObject | undefined { for (const key in obj) { - if (Array.isArray(obj[key]) ) obj[key] = { $in: obj[key]} + if (Array.isArray(obj[key])) obj[key] = { $in: obj[key] }; } return obj; } - -function snakeCaseToCamelCase(input: string | null | undefined) { +function snakeCaseToCamelCase(input: string | null | undefined) { return input?.toLowerCase().replace(/_([a-z])/g, (match, group1) => group1.toUpperCase()); } - function checkStringFields(obj: Record | undefined): boolean { for (const key in obj) { - if (typeof obj[key] === 'string' || Array.isArray(obj[key])) { - return true; + if (typeof obj[key] === 'string' || Array.isArray(obj[key])) { + return true; } } - return false; + return false; } - function convertDateFilter(obj: QueryObject): QueryObject | undefined { - if(!obj) return {} - return { [obj.dateFieldName? obj.dateFieldName as string : 'createdAt'] : { - $gte: obj.from || "", - ...(obj.to ? { $lte: obj.to } : {}), - }} + if (!obj) return {}; + return { + [obj.dateFieldName ? (obj.dateFieldName as string) : 'createdAt']: { + $gte: obj.from || '', + ...(obj.to ? { $lte: obj.to } : {}), + }, + }; } - - - diff --git a/packages/integrations/gei-crud/src/Query/oneById.ts b/packages/integrations/gei-crud/src/Query/oneById.ts index b9ea848..0db57c1 100644 --- a/packages/integrations/gei-crud/src/Query/oneById.ts +++ b/packages/integrations/gei-crud/src/Query/oneById.ts @@ -1,10 +1,10 @@ import { FieldResolveInput } from 'stucco-js'; import { prepareModel, prepareRequired_id, prepareSourceParameters } from '../data.js'; -import { DB } from '../db/mongo.js'; +import { DB } from '../db/orm.js'; export const handler = async (input: FieldResolveInput) => DB().then(async (db) => { const _id = prepareRequired_id(input); const filterInput: Record = { _id, ...prepareSourceParameters(input) }; - return db.collection(prepareModel(input)).findOne(filterInput); + return db(prepareModel(input)).collection.findOne(filterInput); }); diff --git a/packages/integrations/gei-crud/src/db/mongo.ts b/packages/integrations/gei-crud/src/db/mongo.ts deleted file mode 100644 index 85a1e05..0000000 --- a/packages/integrations/gei-crud/src/db/mongo.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { MongoClient, Db } from 'mongodb'; - -let mongoConnection: MongoClient | undefined = undefined; -let mongoDb: Db | undefined = undefined; -async function mongo(): Promise { - if (!mongoDb) { - const mongoUrl = process.env.MONGO_URL ? process.env.MONGO_URL : 'mongodb://localhost:27017/test'; - const client = new MongoClient(mongoUrl); - mongoConnection = await new Promise((resolve, reject) => - client.connect((err, db) => (err ? reject(err) : db ? resolve(db) : reject(`Cannot connect to database`))), - ); - mongoDb = mongoConnection.db(); - } - return mongoDb; -} - -export async function DB() { - return mongo(); -} diff --git a/packages/integrations/gei-crud/src/db/orm.ts b/packages/integrations/gei-crud/src/db/orm.ts new file mode 100644 index 0000000..33b690a --- /dev/null +++ b/packages/integrations/gei-crud/src/db/orm.ts @@ -0,0 +1,16 @@ +import { iGraphQL } from 'i-graphql'; +import { ObjectId } from 'mongodb'; + +export const orm = async () => { + console.log('IGraphQl'); + //const modell = collection.replace("Collection", "Model") + + return iGraphQL, { _id: () => string; createdAt: () => string }>({ + _id: () => new ObjectId().toHexString(), + createdAt: () => new Date().toISOString(), + }); +}; + +export async function DB() { + return orm(); +}