UNPKG

rxdb

Version:

A local-first realtime NoSQL Database for JavaScript applications - https://rxdb.info/

189 lines (162 loc) 6.75 kB
import { GraphQLSchemaFromRxSchemaInputSingleCollection, fillUpOptionals, Prefixes, SPACING } from './graphql-schema-from-rx-schema.ts'; import { ensureNotFalsy, ucfirst } from '../../plugins/utils/index.ts'; import type { RxGraphQLReplicationPullQueryBuilder, RxGraphQLReplicationPullStreamQueryBuilder, RxGraphQLReplicationPushQueryBuilder, RxJsonSchema, TopLevelProperty, WithDeleted } from '../../types/index.d.ts'; export function pullQueryBuilderFromRxSchema( collectionName: string, input: GraphQLSchemaFromRxSchemaInputSingleCollection, ): RxGraphQLReplicationPullQueryBuilder<any> { input = fillUpOptionals(input); const schema = input.schema const prefixes: Prefixes = input.prefixes as any; const ucCollectionName = ucfirst(collectionName); const queryName = prefixes.pull + ucCollectionName; const operationName = ucfirst(queryName); const outputFields = generateGQLOutputFields({ schema, ignoreOutputKeys: input.ignoreOutputKeys }) // outputFields.push(input.deletedField); const checkpointInputName = ucCollectionName + 'Input' + prefixes.checkpoint; const builder: RxGraphQLReplicationPullQueryBuilder<any> = (checkpoint: any, limit: number) => { const query = 'query ' + operationName + '($checkpoint: ' + checkpointInputName + ', $limit: Int!) {\n' + SPACING + SPACING + queryName + '(checkpoint: $checkpoint, limit: $limit) {\n' + SPACING + SPACING + SPACING + 'documents {\n' + outputFields + '\n' + SPACING + SPACING + SPACING + '}\n' + SPACING + SPACING + SPACING + 'checkpoint {\n' + SPACING + SPACING + SPACING + SPACING + input.checkpointFields.join('\n' + SPACING + SPACING + SPACING + SPACING) + '\n' + SPACING + SPACING + SPACING + '}\n' + SPACING + SPACING + '}\n' + '}'; return { query, operationName, variables: { checkpoint, limit } }; }; return builder; } export function pullStreamBuilderFromRxSchema( collectionName: string, input: GraphQLSchemaFromRxSchemaInputSingleCollection, ) { input = fillUpOptionals(input); const schema = input.schema; const prefixes: Prefixes = input.prefixes as any; const ucCollectionName = ucfirst(collectionName); const queryName = prefixes.stream + ucCollectionName; const outputFields = generateGQLOutputFields({ schema, ignoreOutputKeys: input.ignoreOutputKeys }) const headersName = ucCollectionName + 'Input' + prefixes.headers; const query = 'subscription on' + ucfirst(ensureNotFalsy(prefixes.stream)) + '($headers: ' + headersName + ') {\n' + SPACING + queryName + '(headers: $headers) {\n' + SPACING + SPACING + SPACING + 'documents {\n' + outputFields + '\n' + SPACING + SPACING + SPACING + '}\n' + SPACING + SPACING + SPACING + 'checkpoint {\n' + SPACING + SPACING + SPACING + SPACING + input.checkpointFields.join('\n' + SPACING + SPACING + SPACING + SPACING) + '\n' + SPACING + SPACING + SPACING + '}\n' + SPACING + '}' + '}'; const builder: RxGraphQLReplicationPullStreamQueryBuilder = (headers: any) => { return { query, variables: { headers } }; }; return builder; } export function pushQueryBuilderFromRxSchema( collectionName: string, input: GraphQLSchemaFromRxSchemaInputSingleCollection ): RxGraphQLReplicationPushQueryBuilder { input = fillUpOptionals(input); const prefixes: Prefixes = input.prefixes as any; const ucCollectionName = ucfirst(collectionName); const queryName = prefixes.push + ucCollectionName; const operationName = ucfirst(queryName); const variableName = collectionName + prefixes.pushRow; const returnFields = generateGQLOutputFields({ schema: input.schema, spaceCount: 2 }) const builder: RxGraphQLReplicationPushQueryBuilder = (pushRows) => { const query = '' + 'mutation ' + operationName + '($' + variableName + ': [' + ucCollectionName + 'Input' + prefixes.pushRow + '!]) {\n' + SPACING + queryName + '(' + variableName + ': $' + variableName + ') {\n' + returnFields + '\n' + SPACING + '}\n' + '}'; const sendRows: typeof pushRows = []; function transformPushDoc(doc: WithDeleted<any>) { const sendDoc: any = {}; Object.entries(doc).forEach(([k, v]) => { if ( // skip if in ignoreInputKeys list !(input.ignoreInputKeys as string[]).includes(k) && // only use properties that are in the schema input.schema.properties[k] ) { sendDoc[k] = v; } }); return sendDoc; } pushRows.forEach(pushRow => { const newRow: typeof pushRow = { newDocumentState: transformPushDoc(pushRow.newDocumentState), assumedMasterState: pushRow.assumedMasterState ? transformPushDoc(pushRow.assumedMasterState) : undefined }; sendRows.push(newRow); }); const variables = { [variableName]: sendRows }; return { query, operationName, variables }; }; return builder; } type GenerateGQLOutputFieldsOptions = { schema: RxJsonSchema<any> | TopLevelProperty, spaceCount?: number, depth?: number ignoreOutputKeys?: string[] } function generateGQLOutputFields(options: GenerateGQLOutputFieldsOptions) { const { schema, spaceCount = 4, depth = 0, ignoreOutputKeys = [] } = options; const outputFields: string[] = []; const properties = schema.properties const NESTED_SPACING = SPACING.repeat(depth); const LINE_SPACING = SPACING.repeat(spaceCount); for (const key in properties) { //only skipping top level keys that are in ignoreOutputKeys list if (ignoreOutputKeys.includes(key)) { continue; } const value = properties[key]; if (value.type === "object") { outputFields.push( LINE_SPACING + NESTED_SPACING + key + " {", generateGQLOutputFields({ schema: value, spaceCount, depth: depth + 1 }), LINE_SPACING + NESTED_SPACING + "}" ); } else { outputFields.push(LINE_SPACING + NESTED_SPACING + key); } } return outputFields.join('\n'); }