diff --git a/src/graphql/query-builder.ts b/src/graphql/query-builder.ts index c0c0c25..7404299 100644 --- a/src/graphql/query-builder.ts +++ b/src/graphql/query-builder.ts @@ -1,4 +1,5 @@ import {EnumType, jsonToGraphQLQuery} from 'json-to-graphql-query'; +import {isNil} from 'lodash'; import {ConflictClause, Mutation, MutationObject} from './types'; @@ -8,7 +9,9 @@ type MutationFieldValue = | boolean | any[] | {category: string; detail: string} - | Ref; + | Ref + | undefined + | null; interface MutationFields { [field: string]: MutationFieldValue; @@ -57,13 +60,14 @@ export class QueryBuilder { */ private mutationObj(model: FarosModel, ref = false): MutationObject { const [modelName, fields] = Object.entries(model)[0]; - const cleanObj = removeUndefinedProperties(fields ?? {}); const mutObj: any = {}; const mask = ['refreshedAt']; - for (const [k, v] of Object.entries(cleanObj)) { + for (const [k, v] of Object.entries(fields ?? {})) { let maskKey = k; - if (v instanceof Ref) { + if (isNil(v)) { + mutObj[k] = null; + } else if (v instanceof Ref) { mutObj[k] = this.mutationObj(v.model, true); // ref's key should be suffixed with Id for onConflict field maskKey += 'Id'; @@ -112,15 +116,7 @@ export class QueryBuilder { } export function mask(object: any): string[] { - return Object.keys(removeUndefinedProperties(object)); -} - -function removeUndefinedProperties(object: MutationFields): MutationFields { - const result = {...object}; - Object.keys(result).forEach( - (key) => result[key] === undefined && delete result[key] - ); - return result; + return Object.keys(object); } /** diff --git a/test/__snapshots__/query-builder.test.ts.snap b/test/__snapshots__/query-builder.test.ts.snap index e32ac4d..adeaeb0 100644 --- a/test/__snapshots__/query-builder.test.ts.snap +++ b/test/__snapshots__/query-builder.test.ts.snap @@ -3,3 +3,5 @@ exports[`query builder creates mutations 1`] = `"mutation { m0: insert_compute_Application_one (object: {name: \\"\\", platform: \\"\\", origin: \\"test-origin\\"}, on_conflict: {constraint: compute_Application_pkey, update_columns: [refreshedAt, name, platform, origin]}) { id } m1: insert_cicd_Organization_one (object: {uid: \\"\\", source: \\"\\", origin: \\"test-origin\\"}, on_conflict: {constraint: cicd_Organization_pkey, update_columns: [refreshedAt, uid, source, origin]}) { id } m2: insert_cicd_Pipeline_one (object: {uid: \\"\\", organization: {data: {uid: \\"\\", source: \\"\\"}, on_conflict: {constraint: cicd_Organization_pkey, update_columns: [refreshedAt]}}, origin: \\"test-origin\\"}, on_conflict: {constraint: cicd_Pipeline_pkey, update_columns: [refreshedAt, uid, organizationId, origin]}) { id } m3: insert_cicd_Build_one (object: {uid: \\"\\", pipeline: {data: {uid: \\"\\", organization: {data: {uid: \\"\\", source: \\"\\"}, on_conflict: {constraint: cicd_Organization_pkey, update_columns: [refreshedAt]}}}, on_conflict: {constraint: cicd_Pipeline_pkey, update_columns: [refreshedAt]}}, name: \\"\\", origin: \\"test-origin\\"}, on_conflict: {constraint: cicd_Build_pkey, update_columns: [refreshedAt, uid, pipelineId, name, origin]}) { id } m4: insert_cicd_Deployment_one (object: {uid: \\"\\", application: {data: {name: \\"\\", platform: \\"\\"}, on_conflict: {constraint: compute_Application_pkey, update_columns: [refreshedAt]}}, build: {data: {uid: \\"\\", pipeline: {data: {uid: \\"\\", organization: {data: {uid: \\"\\", source: \\"\\"}, on_conflict: {constraint: cicd_Organization_pkey, update_columns: [refreshedAt]}}}, on_conflict: {constraint: cicd_Pipeline_pkey, update_columns: [refreshedAt]}}, name: \\"\\"}, on_conflict: {constraint: cicd_Build_pkey, update_columns: [refreshedAt]}}, status: {category: \\"Success\\", detail: \\"\\"}, origin: \\"test-origin\\"}, on_conflict: {constraint: cicd_Deployment_pkey, update_columns: [refreshedAt, uid, source, applicationId, buildId, status, origin]}) { id } }"`; exports[`query builder creates mutations with non-model objects 1`] = `"mutation { m0: insert_qa_TestCase_one (object: {uid: \\"\\", source: \\"\\", name: \\"\\", before: [{description: \\"\\", condition: \\"\\"}], after: [{description: \\"\\", condition: \\"\\"}], tags: \\"{tag1,tag2}\\", origin: \\"test-origin\\"}, on_conflict: {constraint: qa_TestCase_pkey, update_columns: [refreshedAt, uid, source, name, before, after, tags, origin]}) { id } }"`; + +exports[`query builder creates mutations with undefined and null fields 1`] = `"mutation { m0: insert_qa_TestCase_one (object: {uid: \\"\\", source: \\"\\", name: \\"\\", before: null, after: null, tags: \\"{tag1,tag2}\\", origin: \\"test-origin\\"}, on_conflict: {constraint: qa_TestCase_pkey, update_columns: [refreshedAt, uid, source, name, before, after, tags, origin]}) { id } }"`; diff --git a/test/query-builder.test.ts b/test/query-builder.test.ts index ca34b1e..c0887cb 100644 --- a/test/query-builder.test.ts +++ b/test/query-builder.test.ts @@ -61,4 +61,21 @@ describe('query builder', () => { const queryString = sut.batchMutation(mutations); expect(queryString).toMatchSnapshot(); }); + + test('creates mutations with undefined and null fields', () => { + const qb = new sut.QueryBuilder(ORIGIN); + + const qa_TestCase = { + uid: '', + source: '', + name: '', + before: null, + after: undefined, + tags: ['tag1', 'tag2'], + }; + + const mutations = [qb.upsert({qa_TestCase})]; + const queryString = sut.batchMutation(mutations); + expect(queryString).toMatchSnapshot(); + }); });