From 21b6e952580574dda89881930a7db909448bdc56 Mon Sep 17 00:00:00 2001 From: yargyropoulos Date: Mon, 18 Dec 2023 14:49:12 +0000 Subject: [PATCH 1/2] allow any type for mutation and subscription adapters --- src/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/index.ts b/src/index.ts index 6fb3dcf..0f543c4 100644 --- a/src/index.ts +++ b/src/index.ts @@ -31,7 +31,7 @@ function queryOperation( function mutationOperation( options: IQueryBuilderOptions | IQueryBuilderOptions[], - adapter?: IMutationAdapter, + adapter?: any, config?: any ) { let customAdapter: IMutationAdapter; @@ -56,7 +56,7 @@ function mutationOperation( function subscriptionOperation( options: IQueryBuilderOptions | IQueryBuilderOptions[], - adapter?: ISubscriptionAdapter + adapter?: any ) { let customAdapter: ISubscriptionAdapter; let defaultAdapter: ISubscriptionAdapter; From ad693eaaa4d5105312d01cd2ca9444be1aea8184 Mon Sep 17 00:00:00 2001 From: yargyropoulos Date: Mon, 18 Dec 2023 15:32:21 +0000 Subject: [PATCH 2/2] export Utils functions separately instead of exporting a class with static methods --- src/Utils.ts | 292 +++++++++--------- src/adapters/DefaultAppSyncMutationAdapter.ts | 10 +- src/adapters/DefaultAppSyncQueryAdapter.ts | 8 +- src/adapters/DefaultMutationAdapter.ts | 25 +- src/adapters/DefaultQueryAdapter.ts | 21 +- src/adapters/DefaultSubscriptionAdapter.ts | 10 +- 6 files changed, 185 insertions(+), 181 deletions(-) diff --git a/src/Utils.ts b/src/Utils.ts index 678b6e9..513e0e0 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -3,183 +3,175 @@ import IQueryBuilderOptions from "./IQueryBuilderOptions"; import NestedField, { isNestedField } from "./NestedField"; import VariableOptions from "./VariableOptions"; -export default class Utils { - public static resolveVariables(operations: IQueryBuilderOptions[]): any { - let ret: any = {}; - - for (const { variables, fields } of operations) { - ret = { - ...ret, - ...variables, - ...((fields && Utils.getNestedVariables(fields)) || {}), - }; - } - return ret; +export function resolveVariables(operations: IQueryBuilderOptions[]): any { + let ret: any = {}; + + for (const { variables, fields } of operations) { + ret = { + ...ret, + ...variables, + ...((fields && getNestedVariables(fields)) || {}), + }; } + return ret; +} - // Convert object to name and argument map. eg: (id: $id) - public static queryDataNameAndArgumentMap(variables: VariableOptions) { - return variables && Object.keys(variables).length - ? `(${Object.entries(variables).reduce((dataString, [key, value], i) => { - return `${dataString}${i !== 0 ? ", " : ""}${ - value && value.name ? value.name : key - }: $${key}`; - }, "")})` - : ""; - } +// Convert object to name and argument map. eg: (id: $id) +export function queryDataNameAndArgumentMap(variables: VariableOptions) { + return variables && Object.keys(variables).length + ? `(${Object.entries(variables).reduce((dataString, [key, value], i) => { + return `${dataString}${i !== 0 ? ", " : ""}${ + value && value.name ? value.name : key + }: $${key}`; + }, "")})` + : ""; +} - public static queryFieldsMap(fields?: Fields): string { - return fields - ? fields - .map((field) => { - if (isNestedField(field)) { - return Utils.queryNestedFieldMap(field); - } else if (typeof field === "object") { - let result = ""; - - Object.entries(field as Record).forEach( - ([key, values], index, array) => { - result += `${key} ${ - values.length > 0 - ? "{ " + this.queryFieldsMap(values) + " }" - : "" - }`; - - // If it's not the last item in array, join with comma - if (index < array.length - 1) { - result += ", "; - } +export function queryFieldsMap(fields?: Fields): string { + return fields + ? fields + .map((field) => { + if (isNestedField(field)) { + return queryNestedFieldMap(field); + } else if (typeof field === "object") { + let result = ""; + + Object.entries(field as Record).forEach( + ([key, values], index, array) => { + result += `${key} ${ + values.length > 0 ? "{ " + queryFieldsMap(values) + " }" : "" + }`; + + // If it's not the last item in array, join with comma + if (index < array.length - 1) { + result += ", "; } - ); - - return result; - } else { - return `${field}`; - } - }) - .join(", ") - : ""; - } + } + ); - public static operationOrAlias( - operation: IQueryBuilderOptions["operation"] - ): string { - return typeof operation === "string" - ? operation - : `${operation.alias}: ${operation.name}`; - } + return result; + } else { + return `${field}`; + } + }) + .join(", ") + : ""; +} - public static isFragment(field: NestedField): boolean { - return field?.fragment === true ?? false; - } +function operationOrAlias( + operation: IQueryBuilderOptions["operation"] +): string { + return typeof operation === "string" + ? operation + : `${operation.alias}: ${operation.name}`; +} - public static operationOrFragment(field: NestedField): string { - return Utils.isFragment(field) - ? field.operation - : Utils.operationOrAlias(field.operation); - } +function isFragment(field: NestedField): boolean { + return field?.fragment === true ?? false; +} - public static getFragment(field: NestedField): string { - return Utils.isFragment(field) ? "... on " : ""; - } +function operationOrFragment(field: NestedField): string { + return isFragment(field) + ? field.operation + : operationOrAlias(field.operation); +} - public static queryNestedFieldMap(field: NestedField) { - return `${Utils.getFragment(field)}${Utils.operationOrFragment(field)} ${ - this.isFragment(field) - ? "" - : this.queryDataNameAndArgumentMap(field.variables) - } ${ - field.fields.length > 0 - ? "{ " + this.queryFieldsMap(field.fields) + " }" - : "" - }`; - } +function getFragment(field: NestedField): string { + return isFragment(field) ? "... on " : ""; +} - // Variables map. eg: { "id": 1, "name": "Jon Doe" } - public static queryVariablesMap(variables: any, fields?: Fields) { - const variablesMapped: { [key: string]: unknown } = {}; - const update = (vars: any) => { - if (vars) { - Object.keys(vars).map((key) => { - variablesMapped[key] = - typeof vars[key] === "object" ? vars[key].value : vars[key]; - }); - } - }; +export function queryNestedFieldMap(field: NestedField) { + return `${getFragment(field)}${operationOrFragment(field)} ${ + isFragment(field) ? "" : queryDataNameAndArgumentMap(field.variables) + } ${ + field.fields.length > 0 ? "{ " + queryFieldsMap(field.fields) + " }" : "" + }`; +} - update(variables); - if (fields && typeof fields === "object") { - update(Utils.getNestedVariables(fields)); +// Variables map. eg: { "id": 1, "name": "Jon Doe" } +export function queryVariablesMap(variables: any, fields?: Fields) { + const variablesMapped: { [key: string]: unknown } = {}; + const update = (vars: any) => { + if (vars) { + Object.keys(vars).map((key) => { + variablesMapped[key] = + typeof vars[key] === "object" ? vars[key].value : vars[key]; + }); } - return variablesMapped; + }; + + update(variables); + if (fields && typeof fields === "object") { + update(getNestedVariables(fields)); } + return variablesMapped; +} - public static getNestedVariables(fields: Fields) { - let variables = {}; - - function getDeepestVariables(innerFields: Fields) { - innerFields?.forEach((field: string | object | NestedField) => { - if (isNestedField(field)) { - variables = { - ...field.variables, - ...variables, - ...(field.fields && getDeepestVariables(field.fields)), - }; - } else { - if (typeof field === "object") { - for (const [, value] of Object.entries(field)) { - getDeepestVariables(value); - } +export function getNestedVariables(fields: Fields) { + let variables = {}; + + function getDeepestVariables(innerFields: Fields) { + innerFields?.forEach((field: string | object | NestedField) => { + if (isNestedField(field)) { + variables = { + ...field.variables, + ...variables, + ...(field.fields && getDeepestVariables(field.fields)), + }; + } else { + if (typeof field === "object") { + for (const [, value] of Object.entries(field)) { + getDeepestVariables(value); } } - }); - - return variables; - } - - getDeepestVariables(fields); + } + }); return variables; } - public static queryDataType(variable: any) { - let type = "String"; + getDeepestVariables(fields); - const value = typeof variable === "object" ? variable.value : variable; + return variables; +} - if (variable?.type != null) { - type = variable.type; - } else { - // TODO: Should handle the undefined value (either in array value or single value) - const candidateValue = Array.isArray(value) ? value[0] : value; - switch (typeof candidateValue) { - case "object": - type = "Object"; - break; +export function queryDataType(variable: any) { + let type = "String"; - case "boolean": - type = "Boolean"; - break; + const value = typeof variable === "object" ? variable.value : variable; - case "number": - type = candidateValue % 1 === 0 ? "Int" : "Float"; - break; - } - } + if (variable?.type != null) { + type = variable.type; + } else { + // TODO: Should handle the undefined value (either in array value or single value) + const candidateValue = Array.isArray(value) ? value[0] : value; + switch (typeof candidateValue) { + case "object": + type = "Object"; + break; - // set object based variable properties - if (typeof variable === "object") { - if (variable.list === true) { - type = `[${type}]`; - } else if (Array.isArray(variable.list)) { - type = `[${type}${variable.list[0] ? "!" : ""}]`; - } + case "boolean": + type = "Boolean"; + break; - if (variable.required) { - type += "!"; - } + case "number": + type = candidateValue % 1 === 0 ? "Int" : "Float"; + break; } + } - return type; + // set object based variable properties + if (typeof variable === "object") { + if (variable.list === true) { + type = `[${type}]`; + } else if (Array.isArray(variable.list)) { + type = `[${type}${variable.list[0] ? "!" : ""}]`; + } + + if (variable.required) { + type += "!"; + } } + + return type; } diff --git a/src/adapters/DefaultAppSyncMutationAdapter.ts b/src/adapters/DefaultAppSyncMutationAdapter.ts index ceffbf6..ac9ce78 100644 --- a/src/adapters/DefaultAppSyncMutationAdapter.ts +++ b/src/adapters/DefaultAppSyncMutationAdapter.ts @@ -6,8 +6,8 @@ import Fields from "../Fields"; import IQueryBuilderOptions, { IOperation } from "../IQueryBuilderOptions"; import OperationType from "../OperationType"; -import Utils from "../Utils"; import IMutationAdapter from "./IMutationAdapter"; +import { queryDataType, queryVariablesMap, resolveVariables } from "../Utils"; export default class DefaultAppSyncMutationAdapter implements IMutationAdapter { private variables: any | undefined; @@ -16,7 +16,7 @@ export default class DefaultAppSyncMutationAdapter implements IMutationAdapter { constructor(options: IQueryBuilderOptions | IQueryBuilderOptions[]) { if (Array.isArray(options)) { - this.variables = Utils.resolveVariables(options); + this.variables = resolveVariables(options); } else { this.variables = options.variables; this.fields = options.fields; @@ -39,7 +39,7 @@ export default class DefaultAppSyncMutationAdapter implements IMutationAdapter { return this.operationTemplate(opts.operation); }); return this.operationWrapperTemplate( - Utils.resolveVariables(mutations), + resolveVariables(mutations), content.join("\n ") ); } @@ -58,7 +58,7 @@ export default class DefaultAppSyncMutationAdapter implements IMutationAdapter { return Object.keys(variables).length ? `(${Object.keys(variables).reduce( (dataString, key, i) => - `${dataString}${i !== 0 ? ", " : ""}$${key}: ${Utils.queryDataType( + `${dataString}${i !== 0 ? ", " : ""}$${key}: ${queryDataType( variables[key] )}`, "" @@ -77,7 +77,7 @@ export default class DefaultAppSyncMutationAdapter implements IMutationAdapter { } ${this.queryDataArgumentAndTypeMap(variables)} { ${content} }`, - variables: Utils.queryVariablesMap(variables), + variables: queryVariablesMap(variables), }; } diff --git a/src/adapters/DefaultAppSyncQueryAdapter.ts b/src/adapters/DefaultAppSyncQueryAdapter.ts index 1bce531..b4f45eb 100644 --- a/src/adapters/DefaultAppSyncQueryAdapter.ts +++ b/src/adapters/DefaultAppSyncQueryAdapter.ts @@ -6,8 +6,8 @@ import Fields from "../Fields"; import IQueryBuilderOptions, { IOperation } from "../IQueryBuilderOptions"; import OperationType from "../OperationType"; -import Utils from "../Utils"; import IQueryAdapter from "./IQueryAdapter"; +import { queryFieldsMap, queryVariablesMap, resolveVariables } from "../Utils"; export default class DefaultAppSyncQueryAdapter implements IQueryAdapter { private variables!: any | undefined; @@ -16,7 +16,7 @@ export default class DefaultAppSyncQueryAdapter implements IQueryAdapter { constructor(options: IQueryBuilderOptions | IQueryBuilderOptions[]) { if (Array.isArray(options)) { - this.variables = Utils.resolveVariables(options); + this.variables = resolveVariables(options); } else { this.variables = options.variables; this.fields = options.fields || []; @@ -111,7 +111,7 @@ export default class DefaultAppSyncQueryAdapter implements IQueryAdapter { .toUpperCase()}${operation.slice( 1 )} ${this.queryDataArgumentAndTypeMap()} { ${content} }`, - variables: Utils.queryVariablesMap(this.variables), + variables: queryVariablesMap(this.variables), }; } // query @@ -121,7 +121,7 @@ export default class DefaultAppSyncQueryAdapter implements IQueryAdapter { ? this.operation : `${this.operation.alias}: ${this.operation.name}`; - return `${operation} ${this.queryDataNameAndArgumentMap()} { nodes { ${Utils.queryFieldsMap( + return `${operation} ${this.queryDataNameAndArgumentMap()} { nodes { ${queryFieldsMap( this.fields )} } }`; } diff --git a/src/adapters/DefaultMutationAdapter.ts b/src/adapters/DefaultMutationAdapter.ts index 1d82583..5e069c6 100644 --- a/src/adapters/DefaultMutationAdapter.ts +++ b/src/adapters/DefaultMutationAdapter.ts @@ -6,8 +6,15 @@ import Fields from "../Fields"; import IQueryBuilderOptions, { IOperation } from "../IQueryBuilderOptions"; import OperationType from "../OperationType"; -import Utils from "../Utils"; import IMutationAdapter from "./IMutationAdapter"; +import { + getNestedVariables, + queryDataNameAndArgumentMap, + queryDataType, + queryFieldsMap, + queryVariablesMap, + resolveVariables, +} from "../Utils"; export default class DefaultMutationAdapter implements IMutationAdapter { private variables: any | undefined; @@ -20,7 +27,7 @@ export default class DefaultMutationAdapter implements IMutationAdapter { configuration?: { [key: string]: unknown } ) { if (Array.isArray(options)) { - this.variables = Utils.resolveVariables(options); + this.variables = resolveVariables(options); } else { this.variables = options.variables; this.fields = options.fields; @@ -55,7 +62,7 @@ export default class DefaultMutationAdapter implements IMutationAdapter { }); return this.operationWrapperTemplate( OperationType.Mutation, - Utils.resolveVariables(mutations), + resolveVariables(mutations), content.join("\n ") ); } @@ -63,14 +70,14 @@ export default class DefaultMutationAdapter implements IMutationAdapter { private queryDataArgumentAndTypeMap(variablesUsed: any): string { if (this.fields && typeof this.fields === "object") { variablesUsed = { - ...Utils.getNestedVariables(this.fields), + ...getNestedVariables(this.fields), ...variablesUsed, }; } return variablesUsed && Object.keys(variablesUsed).length > 0 ? `(${Object.keys(variablesUsed).reduce( (dataString, key, i) => - `${dataString}${i !== 0 ? ", " : ""}$${key}: ${Utils.queryDataType( + `${dataString}${i !== 0 ? ", " : ""}$${key}: ${queryDataType( variablesUsed[key] )}`, "" @@ -97,7 +104,7 @@ export default class DefaultMutationAdapter implements IMutationAdapter { return { query, - variables: Utils.queryVariablesMap(variables, this.fields), + variables: queryVariablesMap(variables, this.fields), }; } @@ -107,12 +114,10 @@ export default class DefaultMutationAdapter implements IMutationAdapter { ? operation : `${operation.alias}: ${operation.name}`; - return `${operationName} ${Utils.queryDataNameAndArgumentMap( - this.variables - )} ${ + return `${operationName} ${queryDataNameAndArgumentMap(this.variables)} ${ this.fields && this.fields.length > 0 ? `{ - ${Utils.queryFieldsMap(this.fields)} + ${queryFieldsMap(this.fields)} }` : "" }`; diff --git a/src/adapters/DefaultQueryAdapter.ts b/src/adapters/DefaultQueryAdapter.ts index 7c08ec0..ef62dd8 100644 --- a/src/adapters/DefaultQueryAdapter.ts +++ b/src/adapters/DefaultQueryAdapter.ts @@ -6,9 +6,16 @@ import Fields from "../Fields"; import IQueryBuilderOptions, { IOperation } from "../IQueryBuilderOptions"; import OperationType from "../OperationType"; -import Utils from "../Utils"; import IQueryAdapter from "./IQueryAdapter"; import VariableOptions from "../VariableOptions"; +import { + getNestedVariables, + queryDataNameAndArgumentMap, + queryDataType, + queryFieldsMap, + queryVariablesMap, + resolveVariables, +} from "../Utils"; export default class DefaultQueryAdapter implements IQueryAdapter { private variables!: any | undefined; @@ -31,7 +38,7 @@ export default class DefaultQueryAdapter implements IQueryAdapter { } if (Array.isArray(options)) { - this.variables = Utils.resolveVariables(options); + this.variables = resolveVariables(options); } else { this.variables = options.variables; this.fields = options.fields || []; @@ -66,14 +73,14 @@ export default class DefaultQueryAdapter implements IQueryAdapter { if (this.fields && typeof this.fields === "object") { variablesUsed = { - ...Utils.getNestedVariables(this.fields), + ...getNestedVariables(this.fields), ...variablesUsed, }; } return variablesUsed && Object.keys(variablesUsed).length > 0 ? `(${Object.keys(variablesUsed).reduce( (dataString, key, i) => - `${dataString}${i !== 0 ? ", " : ""}$${key}: ${Utils.queryDataType( + `${dataString}${i !== 0 ? ", " : ""}$${key}: ${queryDataType( variablesUsed[key] )}`, "" @@ -96,7 +103,7 @@ export default class DefaultQueryAdapter implements IQueryAdapter { ); return { query, - variables: Utils.queryVariablesMap(this.variables, this.fields), + variables: queryVariablesMap(this.variables, this.fields), }; } // query @@ -107,10 +114,10 @@ export default class DefaultQueryAdapter implements IQueryAdapter { : `${this.operation.alias}: ${this.operation.name}`; return `${operation} ${ - variables ? Utils.queryDataNameAndArgumentMap(variables) : "" + variables ? queryDataNameAndArgumentMap(variables) : "" } ${ this.fields && this.fields.length > 0 - ? "{ " + Utils.queryFieldsMap(this.fields) + " }" + ? "{ " + queryFieldsMap(this.fields) + " }" : "" }`; } diff --git a/src/adapters/DefaultSubscriptionAdapter.ts b/src/adapters/DefaultSubscriptionAdapter.ts index d40c5de..1f92b41 100644 --- a/src/adapters/DefaultSubscriptionAdapter.ts +++ b/src/adapters/DefaultSubscriptionAdapter.ts @@ -6,8 +6,8 @@ import Fields from "../Fields"; import IQueryBuilderOptions, { IOperation } from "../IQueryBuilderOptions"; import OperationType from "../OperationType"; -import Utils from "../Utils"; import ISubscriptionAdapter from "./ISubscriptionAdapter"; +import { queryDataType, queryVariablesMap, resolveVariables } from "../Utils"; export default class DefaultSubscriptionAdapter implements ISubscriptionAdapter @@ -18,7 +18,7 @@ export default class DefaultSubscriptionAdapter constructor(options: IQueryBuilderOptions | IQueryBuilderOptions[]) { if (Array.isArray(options)) { - this.variables = Utils.resolveVariables(options); + this.variables = resolveVariables(options); } else { this.variables = options.variables; this.fields = options.fields; @@ -43,7 +43,7 @@ export default class DefaultSubscriptionAdapter }); return this.operationWrapperTemplate( OperationType.Subscription, - Utils.resolveVariables(subscriptions), + resolveVariables(subscriptions), content.join("\n ") ); } @@ -62,7 +62,7 @@ export default class DefaultSubscriptionAdapter return Object.keys(variables).length ? `(${Object.keys(variables).reduce( (dataString, key, i) => - `${dataString}${i !== 0 ? ", " : ""}$${key}: ${Utils.queryDataType( + `${dataString}${i !== 0 ? ", " : ""}$${key}: ${queryDataType( variables[key] )}`, "" @@ -80,7 +80,7 @@ export default class DefaultSubscriptionAdapter query: `${type} ${this.queryDataArgumentAndTypeMap(variables)} { ${content} }`, - variables: Utils.queryVariablesMap(variables), + variables: queryVariablesMap(variables), }; }