@kubun/graphql 0.2.5 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export { GraphQLAttachmentID, GraphQLDocID } from './identifiers.js';
2
2
  export * as scalars from './scalars.js';
3
- export { type DocumentType, PatchOperation, SchemaBuilder, type SchemaBuilderParams, type SharedDefinitions, toList, } from './schema.js';
4
- export { getUniqueDocValue } from './utils.js';
3
+ export type { Context, ReadContext, SchemaBuilderParams, SharedDefinitions, UpdateMutationInput, WriteContext, } from './schema.js';
4
+ export { SchemaBuilder, createSchema } from './schema.js';
5
+ export type * from './types.js';
5
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AACpE,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AACvC,OAAO,EACL,KAAK,YAAY,EACjB,cAAc,EACd,aAAa,EACb,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACtB,MAAM,GACP,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AACpE,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AACvC,YAAY,EACV,OAAO,EACP,WAAW,EACX,mBAAmB,EACnB,iBAAiB,EACjB,mBAAmB,EACnB,YAAY,GACb,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AACzD,mBAAmB,YAAY,CAAA"}
package/lib/index.js CHANGED
@@ -1,4 +1,3 @@
1
1
  export { GraphQLAttachmentID, GraphQLDocID } from './identifiers.js';
2
2
  export * as scalars from './scalars.js';
3
- export { PatchOperation, SchemaBuilder, toList } from './schema.js';
4
- export { getUniqueDocValue } from './utils.js';
3
+ export { SchemaBuilder, createSchema } from './schema.js';
package/lib/schema.d.ts CHANGED
@@ -1,60 +1,90 @@
1
1
  import { AttachmentID, DocumentModelID } from '@kubun/id';
2
- import { type ArrayModel, type DocumentData, type DocumentModel, type DocumentModelSchema, type DocumentModelsRecord, type ObjectModel, type ReferencesRecordModel, type ScalarModel, type StringCustomModel, type StringEnumModel, type StringFormatModel, type StringModel, type TypeModel } from '@kubun/protocol';
3
- import { GraphQLEnumType, type GraphQLFieldConfig, type GraphQLFieldConfigMap, GraphQLInputObjectType, type GraphQLInputType, GraphQLInterfaceType, GraphQLList, GraphQLNonNull, GraphQLObjectType, type GraphQLOutputType, type GraphQLScalarType, GraphQLSchema } from 'graphql';
4
- import { type Connection, type ConnectionArguments } from 'graphql-relay';
2
+ import type { ArrayModel, DocumentData, DocumentFilter, DocumentModel, DocumentModelSchema, DocumentModelsRecord, DocumentNode, DocumentOrderBy, ObjectModel, ReferencesRecordModel, ScalarModel, StringCustomModel, StringEnumModel, StringFormatModel, StringModel, TypeModel } from '@kubun/protocol';
3
+ import { GraphQLEnumType, type GraphQLFieldConfig, type GraphQLFieldConfigMap, GraphQLInputObjectType, type GraphQLInputType, GraphQLInterfaceType, GraphQLList, GraphQLNonNull, GraphQLObjectType, type GraphQLOutputType, type GraphQLResolveInfo, type GraphQLScalarType, GraphQLSchema } from 'graphql';
4
+ import { type Connection, type ConnectionArguments, type Edge } from 'graphql-relay';
5
+ import type { PatchOperation as PatchOperationType } from './types.js';
5
6
  export declare function toDocumentModelID(id: DocumentModelID | string): DocumentModelID;
6
7
  export declare function getGlobalID(id: DocumentModelID | string, globalID: DocumentModelID | string): DocumentModelID;
7
8
  export declare function toList(type: GraphQLInputType): GraphQLList<GraphQLNonNull<GraphQLInputType>>;
8
9
  export declare function toOuputList(type: GraphQLOutputType): GraphQLList<GraphQLNonNull<GraphQLOutputType>>;
9
10
  export declare const PatchOperation: GraphQLInputObjectType;
10
- export type DocumentType = {
11
+ type AllConnectionArguments = ConnectionArguments & {
12
+ filter?: DocumentFilter;
13
+ orderBy?: DocumentOrderBy;
14
+ };
15
+ /**
16
+ * Query and subscription functions requiring server implementation
17
+ */
18
+ export type ReadContext = {
19
+ getViewer(): string | null;
20
+ loadDocument(id: string): Promise<DocumentNode | null>;
21
+ resolveConnection(modelIDs: Array<string>, args: AllConnectionArguments): Promise<Connection<DocumentNode>>;
22
+ resolveList(modelIDs: Array<string>, ids: Array<string>): Promise<Array<DocumentNode>>;
23
+ subscribeToDocumentCreated(modelIDs: Array<string>): AsyncGenerator<DocumentNode>;
24
+ subscribeToDocumentChanged(id: string): AsyncGenerator<DocumentNode>;
25
+ subscribeToDocumentRemoved(): AsyncGenerator<string>;
26
+ subscribeToDocumentEdgeAdded(modelIDs: Array<string>, hasRelation: (data: DocumentData) => boolean): AsyncGenerator<Edge<DocumentNode>>;
27
+ subscribeToDocumentEdgeRemoved(modelIDs: Array<string>, hasRelation: (data: DocumentData) => boolean): AsyncGenerator<string>;
28
+ };
29
+ /**
30
+ * Mutation function requiring client implementation
31
+ */
32
+ export type WriteContext = {
33
+ executeCreateMutation(modelID: string, data: DocumentData, info: GraphQLResolveInfo): Promise<DocumentNode>;
34
+ executeSetMutation(modelID: string, unique: Uint8Array, data: DocumentData, info: GraphQLResolveInfo): Promise<DocumentNode>;
35
+ executeUpdateMutation(input: UpdateMutationInput, info: GraphQLResolveInfo): Promise<DocumentNode>;
36
+ executeRemoveMutation(id: string, info: GraphQLResolveInfo): Promise<void>;
37
+ };
38
+ export type Context = ReadContext & WriteContext;
39
+ export type UpdateMutationInput = {
11
40
  id: string;
12
- model: string;
13
- owner: string;
14
- data: DocumentData | null;
41
+ patch: Array<PatchOperationType>;
42
+ from?: DocumentData;
15
43
  };
16
- export type ContextType = Record<string, unknown>;
17
- export type GraphQLNodeDefinitions<Context extends ContextType = ContextType> = {
44
+ export type GraphQLNodeDefinitions = {
18
45
  nodeInterface: GraphQLInterfaceType;
19
46
  nodeField: GraphQLFieldConfig<unknown, Context>;
20
47
  nodesField: GraphQLFieldConfig<unknown, Context>;
21
48
  };
22
- export type SharedDefinitions<Document extends DocumentType = DocumentType, Context extends ContextType = ContextType> = GraphQLNodeDefinitions<Context> & {
49
+ export type SharedDefinitions = GraphQLNodeDefinitions & {
23
50
  accountObject: GraphQLObjectType<string, Context>;
24
51
  attachmentObject: GraphQLObjectType<AttachmentID, Context>;
25
52
  documentInterface: GraphQLInterfaceType;
26
- documentMetadata: GraphQLObjectType<Document, Context>;
53
+ documentNodeFields: GraphQLFieldConfigMap<DocumentNode, Context>;
27
54
  queryFields: GraphQLFieldConfigMap<unknown, Context>;
28
55
  };
56
+ type RelationField = {
57
+ model: string;
58
+ isList: boolean;
59
+ };
60
+ type RelationFields = Record<string, RelationField>;
29
61
  export type SchemaBuilderParams = {
30
62
  aliases?: Record<string, string>;
31
63
  record: DocumentModelsRecord;
32
64
  };
33
- export declare class SchemaBuilder<Document extends DocumentType = DocumentType, Context extends ContextType = ContextType, Definitions extends SharedDefinitions<Document, Context> = SharedDefinitions<Document, Context>> {
65
+ export declare class SchemaBuilder {
34
66
  _aliases: Record<string, string>;
35
- _definitions: Definitions | undefined;
67
+ _definitions: SharedDefinitions | undefined;
36
68
  _implemented: Record<string, Array<string>>;
37
69
  _inputObjects: Record<string, GraphQLInputObjectType>;
38
- _mutations: Record<string, GraphQLFieldConfig<unknown, Context>>;
70
+ _mutations: GraphQLFieldConfigMap<unknown, Context>;
39
71
  _nodeModelIDs: Array<string>;
40
72
  _record: DocumentModelsRecord;
41
73
  _references: ReferencesRecordModel;
42
- _relationsTo: Record<string, Record<string, string>>;
74
+ _relationsTo: Record<string, RelationFields>;
75
+ _subscriptions: GraphQLFieldConfigMap<unknown, Context>;
43
76
  _types: Record<string, GraphQLOutputType>;
44
77
  constructor(params: SchemaBuilderParams);
45
78
  getModelIDs(id: string | null): Array<string>;
46
- getViewer(ctx: Context): string | null;
47
- loadDocument(id: string, ctx: Context): Promise<Document | null>;
48
- resolveConnection(model: string | null, args: ConnectionArguments, ctx: Context): Promise<Connection<Document>>;
49
- resolveList(model: string | null, ids: Array<string>, ctx: Context): Promise<Array<Document>>;
50
- buildMutations(id: string, definitions: Definitions): void;
51
79
  build(): GraphQLSchema;
52
- _getDefinitions(): Definitions;
80
+ _getDefinitions(): SharedDefinitions;
53
81
  _getReference(path: string, parentName?: string): GraphQLOutputType;
54
82
  _getReferenceSchema(id: string): TypeModel;
55
83
  _getReferenceInput(path: string, isPartial: boolean, parentName?: string): GraphQLInputType;
56
- _buildSharedDefinitions(): Definitions;
57
- _buildDocument(id: string): GraphQLObjectType<Document, Context> | GraphQLInterfaceType;
84
+ _buildSharedDefinitions(): SharedDefinitions;
85
+ _buildDocument(id: string): GraphQLObjectType<DocumentNode, Context> | GraphQLInterfaceType;
86
+ _buildDocumentFields(id: string, model: DocumentModel, name: string): GraphQLFieldConfigMap<DocumentNode, Context>;
87
+ _buildDocumentDataObject(id: string, model: DocumentModel, name: string): GraphQLInterfaceType | GraphQLObjectType<DocumentData, Context>;
58
88
  _buildDocumentInput(id: string, model: DocumentModel): void;
59
89
  _buildReferenceFilterInput(path: string, parentName?: string): GraphQLInputType;
60
90
  _buildReferenceOrderByInput(path: string, parentName?: string): GraphQLInputType | null;
@@ -65,10 +95,14 @@ export declare class SchemaBuilder<Document extends DocumentType = DocumentType,
65
95
  _buildScalar(id: string, schema: ScalarModel, asInput?: boolean): GraphQLScalarType;
66
96
  _buildArray(schema: ArrayModel, parentName?: string): GraphQLList<GraphQLNonNull<GraphQLOutputType>>;
67
97
  _buildObject(id: string, schema: ObjectModel, parentName?: string): GraphQLObjectType;
68
- _buildObjectFields(id: string, schema: DocumentModelSchema | ObjectModel, model?: DocumentModel): Record<string, GraphQLFieldConfig<Document, Context>>;
98
+ _buildObjectFields(id: string, schema: DocumentModelSchema | ObjectModel): GraphQLFieldConfigMap<Record<string, unknown>, Context>;
99
+ _buildRelationFields(fields: GraphQLFieldConfigMap<DocumentNode, Context>, fieldName: string, relation: RelationField): void;
100
+ _buildRelationSubscriptions(fields: GraphQLFieldConfigMap<unknown, Context>, modelID: string, fieldName: string, relation: RelationField): void;
69
101
  _buildString(schema: StringModel, asInput: boolean): GraphQLEnumType | GraphQLObjectType | GraphQLScalarType;
70
102
  _buildCustomString(schema: StringCustomModel, asInput: boolean): GraphQLScalarType<unknown, unknown> | GraphQLObjectType<string, Context> | GraphQLObjectType<AttachmentID, Context>;
71
103
  _buildEnumString(schema: StringEnumModel): GraphQLEnumType;
72
104
  _buildFormatString(schema: StringFormatModel): GraphQLScalarType<unknown, unknown>;
73
105
  }
106
+ export declare function createSchema(record: DocumentModelsRecord, aliases?: Record<string, string>): GraphQLSchema;
107
+ export {};
74
108
  //# sourceMappingURL=schema.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"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"}
package/lib/schema.js CHANGED
@@ -2,8 +2,8 @@ import { AttachmentID, DocumentID, DocumentModelID, decodeID } from '@kubun/id';
2
2
  import { REFERENCE_PREFIX } from '@kubun/protocol';
3
3
  import { pascalCase } from 'change-case';
4
4
  import { GraphQLBoolean, GraphQLEnumType, GraphQLFloat, GraphQLID, GraphQLInputObjectType, GraphQLInt, GraphQLInterfaceType, GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLSchema, GraphQLString, isEnumType, isListType, isNonNullType } from 'graphql';
5
- import { connectionArgs, connectionDefinitions, nodeDefinitions } from 'graphql-relay';
6
- import { GraphQLDID, GraphQLDuration, GraphQLJSON, GraphQLJSONObject, GraphQLURL } from 'graphql-scalars';
5
+ import { connectionArgs, connectionDefinitions, mutationWithClientMutationId, nodeDefinitions } from 'graphql-relay';
6
+ import { GraphQLDID, GraphQLDateTimeISO, GraphQLDuration, GraphQLJSON, GraphQLJSONObject, GraphQLURL } from 'graphql-scalars';
7
7
  import { GraphQLAttachmentID, GraphQLDocID } from './identifiers.js';
8
8
  import { getUniqueDocValue } from './utils.js';
9
9
  const STRING_FORMATS = {
@@ -224,6 +224,7 @@ export class SchemaBuilder {
224
224
  _record;
225
225
  _references = {};
226
226
  _relationsTo = {};
227
+ _subscriptions = {};
227
228
  _types = {
228
229
  OrderByDirection
229
230
  };
@@ -246,9 +247,14 @@ export class SchemaBuilder {
246
247
  // Extract inverse relations
247
248
  for (const [fieldName, meta] of Object.entries(model.fieldsMeta)){
248
249
  if (meta.relationModel != null) {
250
+ const relationRefID = getReferenceID(model.schema.properties[fieldName]?.$ref);
251
+ const isList = this._getReferenceSchema(relationRefID).type === 'array';
249
252
  const relationID = getGlobalID(meta.relationModel, modelID).toString();
250
253
  this._relationsTo[relationID] ??= {};
251
- this._relationsTo[relationID][fieldName] = modelIDstring;
254
+ this._relationsTo[relationID][fieldName] = {
255
+ model: modelIDstring,
256
+ isList
257
+ };
252
258
  }
253
259
  }
254
260
  }
@@ -269,21 +275,6 @@ export class SchemaBuilder {
269
275
  id
270
276
  ];
271
277
  }
272
- getViewer(ctx) {
273
- throw new Error('Must be implemented');
274
- }
275
- async loadDocument(id, ctx) {
276
- throw new Error('Must be implemented');
277
- }
278
- async resolveConnection(model, args, ctx) {
279
- throw new Error('Must be implemented');
280
- }
281
- async resolveList(model, ids, ctx) {
282
- throw new Error('Must be implemented');
283
- }
284
- buildMutations(id, definitions) {
285
- throw new Error('Must be implemented');
286
- }
287
278
  build() {
288
279
  const definitions = this._buildSharedDefinitions();
289
280
  this._definitions = definitions;
@@ -293,25 +284,25 @@ export class SchemaBuilder {
293
284
  };
294
285
  for (const id of Object.keys(this._record)){
295
286
  this._buildDocument(id);
296
- this.buildMutations(id, definitions);
297
287
  const name = this._aliases[id];
288
+ const filterArg = {
289
+ type: this._inputObjects[`${id}-filter`]
290
+ };
298
291
  queryFields[`all${name}`] = {
299
292
  type: this._types[`${id}-connection`],
300
293
  args: {
301
294
  ...connectionArgs,
302
- filter: {
303
- type: this._inputObjects[`${id}-filter`]
304
- },
295
+ filter: filterArg,
305
296
  orderBy: {
306
297
  type: toList(this._inputObjects[`${id}-order`])
307
298
  }
308
299
  },
309
300
  resolve: async (_, args, ctx)=>{
310
- return await this.resolveConnection(id, args, ctx);
301
+ return await ctx.resolveConnection(this.getModelIDs(id), args);
311
302
  }
312
303
  };
313
304
  }
314
- const schemaFields = {
305
+ return new GraphQLSchema({
315
306
  query: new GraphQLObjectType({
316
307
  name: 'Query',
317
308
  fields: queryFields
@@ -319,9 +310,54 @@ export class SchemaBuilder {
319
310
  mutation: new GraphQLObjectType({
320
311
  name: 'Mutation',
321
312
  fields: this._mutations
313
+ }),
314
+ subscription: new GraphQLObjectType({
315
+ name: 'Subscription',
316
+ fields: ()=>{
317
+ const fields = {
318
+ documentChanged: {
319
+ type: new GraphQLNonNull(definitions.documentInterface),
320
+ args: {
321
+ id: {
322
+ type: new GraphQLNonNull(GraphQLID)
323
+ }
324
+ },
325
+ resolve: (doc)=>doc,
326
+ subscribe: (_, args, ctx)=>{
327
+ return ctx.subscribeToDocumentChanged(args.id);
328
+ }
329
+ },
330
+ documentRemoved: {
331
+ type: new GraphQLNonNull(GraphQLID),
332
+ resolve: (id)=>id,
333
+ subscribe: (_src, _args, ctx)=>{
334
+ return ctx.subscribeToDocumentRemoved();
335
+ }
336
+ }
337
+ };
338
+ for (const [id, model] of Object.entries(this._record)){
339
+ const name = this._aliases[id];
340
+ fields[`new${name}Created`] = {
341
+ type: new GraphQLNonNull(this._types[id]),
342
+ resolve: (doc)=>doc,
343
+ subscribe: (_src, _args, ctx)=>{
344
+ return ctx.subscribeToDocumentCreated(this.getModelIDs(id));
345
+ }
346
+ };
347
+ for (const iid of model.interfaces ?? []){
348
+ const interfaceID = getGlobalID(iid, id).toString();
349
+ for (const [fieldName, relationID] of Object.entries(this._relationsTo[interfaceID] ?? {})){
350
+ this._buildRelationSubscriptions(fields, interfaceID, fieldName, relationID);
351
+ }
352
+ }
353
+ for (const [fieldName, relationID] of Object.entries(this._relationsTo[id] ?? {})){
354
+ this._buildRelationSubscriptions(fields, id, fieldName, relationID);
355
+ }
356
+ }
357
+ return fields;
358
+ }
322
359
  })
323
- };
324
- return new GraphQLSchema(schemaFields);
360
+ });
325
361
  }
326
362
  _getDefinitions() {
327
363
  if (this._definitions == null) {
@@ -385,7 +421,7 @@ export class SchemaBuilder {
385
421
  return decoded;
386
422
  }
387
423
  if (decoded instanceof DocumentID) {
388
- return await this.loadDocument(id, ctx);
424
+ return await ctx.loadDocument(id);
389
425
  }
390
426
  throw new Error(`Unsupported node ID: ${id}`);
391
427
  }, (node)=>{
@@ -406,7 +442,7 @@ export class SchemaBuilder {
406
442
  isViewer: {
407
443
  type: new GraphQLNonNull(GraphQLBoolean),
408
444
  description: 'Whether the authenticated request issuer is this account or not',
409
- resolve: (did, _, ctx)=>this.getViewer(ctx) === did
445
+ resolve: (did, _, ctx)=>ctx.getViewer() === did
410
446
  }
411
447
  };
412
448
  for (const [id, model] of Object.entries(this._record)){
@@ -428,10 +464,10 @@ export class SchemaBuilder {
428
464
  }
429
465
  },
430
466
  resolve: async (owner, args, ctx)=>{
431
- return await this.resolveConnection(id, {
467
+ return await ctx.resolveConnection(this.getModelIDs(id), {
432
468
  ...args,
433
469
  owner
434
- }, ctx);
470
+ });
435
471
  }
436
472
  };
437
473
  break;
@@ -449,7 +485,7 @@ export class SchemaBuilder {
449
485
  resolve: async (owner, args, ctx)=>{
450
486
  const unique = getUniqueDocValue(model.uniqueFields, args.with);
451
487
  const docID = await DocumentID.create(id, owner, unique);
452
- return await this.loadDocument(docID.toString(), ctx);
488
+ return await ctx.loadDocument(docID.toString());
453
489
  }
454
490
  };
455
491
  }
@@ -476,40 +512,38 @@ export class SchemaBuilder {
476
512
  }
477
513
  }
478
514
  });
479
- const documentMetadata = new GraphQLObjectType({
480
- name: 'DocumentMetadata',
481
- fields: {
482
- model: {
483
- type: new GraphQLNonNull(GraphQLString),
484
- resolve: (doc)=>doc.model
485
- },
486
- owner: {
487
- type: new GraphQLNonNull(accountObject),
488
- resolve: (doc)=>doc.owner
489
- }
515
+ const documentNodeFields = {
516
+ // Node interface
517
+ id: {
518
+ type: new GraphQLNonNull(GraphQLID)
519
+ },
520
+ // Metadata
521
+ model: {
522
+ type: new GraphQLNonNull(GraphQLString)
523
+ },
524
+ owner: {
525
+ type: new GraphQLNonNull(accountObject)
526
+ },
527
+ createdAt: {
528
+ type: new GraphQLNonNull(GraphQLDateTimeISO)
529
+ },
530
+ updatedAt: {
531
+ type: GraphQLDateTimeISO
490
532
  }
491
- });
533
+ };
492
534
  const documentInterface = new GraphQLInterfaceType({
493
535
  name: 'DocumentNode',
494
536
  interfaces: [
495
537
  nodeDefs.nodeInterface
496
538
  ],
497
- fields: {
498
- // Node interface
499
- id: {
500
- type: new GraphQLNonNull(GraphQLID)
501
- },
502
- _doc_metadata: {
503
- type: new GraphQLNonNull(documentMetadata)
504
- }
505
- }
539
+ fields: documentNodeFields
506
540
  });
507
541
  const queryFields = {
508
542
  node: nodeDefs.nodeField,
509
543
  viewer: {
510
544
  type: accountObject,
511
545
  description: 'Account issuing the request, if authenticated',
512
- resolve: (_self, _args, ctx)=>this.getViewer(ctx)
546
+ resolve: (_self, _args, ctx)=>ctx.getViewer()
513
547
  }
514
548
  };
515
549
  return {
@@ -517,7 +551,7 @@ export class SchemaBuilder {
517
551
  accountObject,
518
552
  attachmentObject,
519
553
  documentInterface,
520
- documentMetadata,
554
+ documentNodeFields,
521
555
  queryFields
522
556
  };
523
557
  }
@@ -531,8 +565,9 @@ export class SchemaBuilder {
531
565
  }
532
566
  const definitions = this._getDefinitions();
533
567
  this._aliases[id] ??= pascalCase(model.name);
568
+ const name = this._aliases[id];
534
569
  const config = {
535
- name: this._aliases[id],
570
+ name,
536
571
  interfaces: ()=>{
537
572
  return [
538
573
  definitions.documentInterface,
@@ -541,22 +576,194 @@ export class SchemaBuilder {
541
576
  return this._types[getGlobalID(interfaceID, id).toString()];
542
577
  }));
543
578
  },
544
- fields: ()=>this._buildObjectFields(id, model.schema, model),
545
- isTypeOf: (doc)=>DocumentID.fromString(doc.id).model.toString() === id
579
+ fields: ()=>this._buildDocumentFields(id, model, name)
546
580
  };
547
581
  const isInterface = model.behavior === 'interface';
548
- const nodeType = isInterface ? new GraphQLInterfaceType(config) : new GraphQLObjectType(config);
582
+ const nodeType = isInterface ? new GraphQLInterfaceType({
583
+ ...config,
584
+ resolveType: (doc)=>this._aliases[doc.model]
585
+ }) : new GraphQLObjectType(config);
549
586
  const { connectionType, edgeType } = connectionDefinitions({
550
587
  nodeType
551
588
  });
552
589
  this._types[id] = nodeType;
553
590
  this._types[`${id}-connection`] = connectionType;
554
591
  this._types[`${id}-edge`] = edgeType;
592
+ this._buildDocumentDataObject(id, model, name);
555
593
  this._buildDocumentInput(id, model);
556
- this._buildObjectFilterInput(id, model.schema, model.name, true);
557
- this._buildObjectOrderByInput(id, model.schema, model.name, true);
594
+ this._buildObjectFilterInput(id, model.schema, name, true);
595
+ this._buildObjectOrderByInput(id, model.schema, name, true);
596
+ // TODO: move to dedicated method
597
+ if (!isInterface) {
598
+ if (model.behavior === 'default') {
599
+ this._mutations[`create${name}`] = mutationWithClientMutationId({
600
+ name: `Create${name}`,
601
+ inputFields: ()=>({
602
+ data: {
603
+ type: new GraphQLNonNull(this._inputObjects[id])
604
+ }
605
+ }),
606
+ outputFields: ()=>({
607
+ ...definitions.queryFields,
608
+ document: {
609
+ type: this._types[id]
610
+ }
611
+ }),
612
+ mutateAndGetPayload: async (input, ctx, info)=>{
613
+ const document = await ctx.executeCreateMutation(id, input.data, info);
614
+ return {
615
+ document
616
+ };
617
+ }
618
+ });
619
+ } else if (model.behavior === 'unique') {
620
+ this._mutations[`set${name}`] = mutationWithClientMutationId({
621
+ name: `Set${name}`,
622
+ inputFields: ()=>({
623
+ data: {
624
+ type: new GraphQLNonNull(this._inputObjects[id])
625
+ }
626
+ }),
627
+ outputFields: ()=>({
628
+ ...definitions.queryFields,
629
+ document: {
630
+ type: this._types[id]
631
+ }
632
+ }),
633
+ mutateAndGetPayload: async (input, ctx, info)=>{
634
+ const unique = getUniqueDocValue(model.uniqueFields, input.data);
635
+ const document = await ctx.executeSetMutation(id, unique, input.data, info);
636
+ return {
637
+ document
638
+ };
639
+ }
640
+ });
641
+ }
642
+ this._mutations[`update${name}`] = mutationWithClientMutationId({
643
+ name: `Update${name}`,
644
+ inputFields: ()=>({
645
+ id: {
646
+ type: new GraphQLNonNull(GraphQLID)
647
+ },
648
+ patch: {
649
+ type: new GraphQLNonNull(toList(PatchOperation))
650
+ },
651
+ from: {
652
+ type: this._inputObjects[`${id}-update`]
653
+ }
654
+ }),
655
+ outputFields: ()=>({
656
+ ...definitions.queryFields,
657
+ document: {
658
+ type: this._types[id]
659
+ }
660
+ }),
661
+ mutateAndGetPayload: async (input, ctx, info)=>{
662
+ const document = await ctx.executeUpdateMutation(input, info);
663
+ return {
664
+ document
665
+ };
666
+ }
667
+ });
668
+ this._mutations[`remove${name}`] = mutationWithClientMutationId({
669
+ name: `Remove${name}`,
670
+ inputFields: ()=>({
671
+ id: {
672
+ type: new GraphQLNonNull(GraphQLID)
673
+ }
674
+ }),
675
+ outputFields: ()=>definitions.queryFields,
676
+ mutateAndGetPayload: async (input, ctx, info)=>{
677
+ await ctx.executeRemoveMutation(input.id, info);
678
+ return {};
679
+ }
680
+ });
681
+ }
558
682
  return nodeType;
559
683
  }
684
+ _buildDocumentFields(id, model, name) {
685
+ const dataObject = this._buildDocumentDataObject(id, model, name);
686
+ const definitions = this._getDefinitions();
687
+ const fields = {
688
+ ...definitions.documentNodeFields,
689
+ data: {
690
+ type: new GraphQLNonNull(dataObject)
691
+ }
692
+ };
693
+ for (const [key, field] of Object.entries(dataObject.getFields())){
694
+ const relationModel = model.fieldsMeta[key]?.relationModel;
695
+ if (typeof relationModel !== 'undefined') {
696
+ let relationModelID;
697
+ let relationType;
698
+ if (relationModel === null) {
699
+ relationModelID = null;
700
+ relationType = definitions.documentInterface;
701
+ } else {
702
+ relationModelID = getGlobalID(relationModel, id).toString();
703
+ relationType = this._buildDocument(relationModelID);
704
+ }
705
+ if (isList(field.type)) {
706
+ // TODO: add suport for filters?
707
+ fields[`${key}Documents`] = {
708
+ type: new GraphQLNonNull(toOuputList(relationType)),
709
+ resolve: async (doc, _args, ctx)=>{
710
+ const relationIDs = doc.data?.[key] ?? [];
711
+ return relationIDs.length ? await ctx.resolveList(this.getModelIDs(relationModelID), relationIDs) : [];
712
+ }
713
+ };
714
+ } else {
715
+ fields[`${key}Document`] = {
716
+ type: relationType,
717
+ resolve: async (doc, _args, ctx)=>{
718
+ const relationID = doc.data?.[key];
719
+ return relationID ? await ctx.loadDocument(relationID) : null;
720
+ }
721
+ };
722
+ }
723
+ }
724
+ for (const iid of model.interfaces ?? []){
725
+ const interfaceID = getGlobalID(iid, id).toString();
726
+ for (const [fieldName, relation] of Object.entries(this._relationsTo[interfaceID] ?? {})){
727
+ this._buildRelationFields(fields, fieldName, relation);
728
+ }
729
+ }
730
+ for (const [fieldName, relation] of Object.entries(this._relationsTo[id] ?? {})){
731
+ this._buildRelationFields(fields, fieldName, relation);
732
+ }
733
+ }
734
+ return fields;
735
+ }
736
+ _buildDocumentDataObject(id, model, name) {
737
+ const typeID = `${id}-data`;
738
+ if (this._types[typeID] != null) {
739
+ return this._types[typeID];
740
+ }
741
+ const required = model.schema.required ?? [];
742
+ const fields = {};
743
+ for (const [key, value] of Object.entries(model.schema.properties ?? {})){
744
+ const fieldRef = value.$ref;
745
+ if (fieldRef == null) {
746
+ throw new Error(`Missing ref for field ${key} of object ${id}`);
747
+ }
748
+ const type = this._getReference(fieldRef);
749
+ fields[key] = {
750
+ type: required.includes(key) ? new GraphQLNonNull(type) : type
751
+ };
752
+ }
753
+ const config = {
754
+ name: `${name}Data`,
755
+ interfaces: ()=>{
756
+ return model.interfaces.map((interfaceID)=>{
757
+ const typeID = `${getGlobalID(interfaceID, id).toString()}-data`;
758
+ return this._types[typeID];
759
+ });
760
+ },
761
+ fields
762
+ };
763
+ const object = model.behavior === 'interface' ? new GraphQLInterfaceType(config) : new GraphQLObjectType(config);
764
+ this._types[typeID] = object;
765
+ return object;
766
+ }
560
767
  _buildDocumentInput(id, model) {
561
768
  if (model.behavior === 'interface') {
562
769
  // No mutations for interfaces
@@ -580,11 +787,11 @@ export class SchemaBuilder {
580
787
  }
581
788
  const name = this._aliases[id];
582
789
  this._inputObjects[id] = new GraphQLInputObjectType({
583
- name: model.behavior === 'default' ? `Create${name}` : `Set${name}`,
790
+ name: `${name}Input`,
584
791
  fields: setFields
585
792
  });
586
793
  this._inputObjects[`${id}-update`] = new GraphQLInputObjectType({
587
- name: `Update${name}`,
794
+ name: `Partial${name}Input`,
588
795
  fields: updateFields
589
796
  });
590
797
  }
@@ -596,17 +803,14 @@ export class SchemaBuilder {
596
803
  }
597
804
  if (schema.type === 'array') {
598
805
  const name = this._aliases[id] ?? pascalCase(parentName + schema.title);
599
- const itemType = this._buildReferenceFilterInput(schema.items.$ref, schema.title);
806
+ // const itemType = this._buildReferenceFilterInput(schema.items.$ref, schema.title)
600
807
  return new GraphQLInputObjectType({
601
808
  name: `${name}Filter`,
602
809
  isOneOf: true,
603
810
  fields: {
604
- contains: {
605
- type: toList(itemType)
606
- },
607
- isEmpty: {
608
- type: GraphQLBoolean
609
- },
811
+ // DB does not support filtering on array values
812
+ // contains: { type: toList(itemType) },
813
+ // isEmpty: { type: GraphQLBoolean },
610
814
  isNull: {
611
815
  type: GraphQLBoolean
612
816
  }
@@ -644,7 +848,7 @@ export class SchemaBuilder {
644
848
  }
645
849
  const name = this._aliases[id] ?? pascalCase(parentName + (schema.title ?? ''));
646
850
  const fields = isDocument ? {
647
- _doc_owner: {
851
+ _owner: {
648
852
  type: this._inputObjects.AccountValueFilter
649
853
  }
650
854
  } : {};
@@ -687,10 +891,10 @@ export class SchemaBuilder {
687
891
  }
688
892
  const name = this._aliases[id] ?? pascalCase(parentName + (schema.title ?? ''));
689
893
  const fields = isDocument ? {
690
- _doc_owner: {
894
+ _docOwner: {
691
895
  type: OrderByDirection
692
896
  },
693
- _doc_created_at: {
897
+ _createdAt: {
694
898
  type: OrderByDirection
695
899
  }
696
900
  } : {};
@@ -781,19 +985,9 @@ export class SchemaBuilder {
781
985
  fields
782
986
  });
783
987
  }
784
- _buildObjectFields(id, schema, model) {
785
- const definitions = this._getDefinitions();
988
+ _buildObjectFields(id, schema) {
786
989
  const required = schema.required ?? [];
787
- const fields = model ? {
788
- id: {
789
- type: new GraphQLNonNull(GraphQLID),
790
- resolve: (doc)=>doc.id
791
- },
792
- _doc_metadata: {
793
- type: new GraphQLNonNull(definitions.documentMetadata),
794
- resolve: (doc)=>doc
795
- }
796
- } : {};
990
+ const fields = {};
797
991
  for (const [key, value] of Object.entries(schema.properties ?? {})){
798
992
  const fieldRef = value.$ref;
799
993
  if (fieldRef == null) {
@@ -803,63 +997,82 @@ export class SchemaBuilder {
803
997
  fields[key] = {
804
998
  type: required.includes(key) ? new GraphQLNonNull(type) : type
805
999
  };
806
- if (model == null) {
807
- continue;
808
- }
809
- fields[key].resolve = (doc)=>doc.data?.[key];
810
- const relationModel = model.fieldsMeta[key]?.relationModel;
811
- if (typeof relationModel !== 'undefined') {
812
- let relationModelID;
813
- let relationType;
814
- if (relationModel === null) {
815
- relationModelID = null;
816
- relationType = definitions.documentInterface;
817
- } else {
818
- relationModelID = getGlobalID(relationModel, id).toString();
819
- relationType = this._buildDocument(relationModelID);
1000
+ }
1001
+ return fields;
1002
+ }
1003
+ _buildRelationFields(fields, fieldName, relation) {
1004
+ if (relation.isList) {
1005
+ // DB does not support matches for array containing values
1006
+ return;
1007
+ }
1008
+ const relationID = relation.model;
1009
+ const relationName = `${pascalCase(fieldName)}Of${this._aliases[relationID]}`;
1010
+ fields[`in${relationName}`] = {
1011
+ type: new GraphQLNonNull(this._types[`${relationID}-connection`]),
1012
+ args: {
1013
+ ...connectionArgs,
1014
+ filter: {
1015
+ type: this._inputObjects[`${relationID}-filter`]
1016
+ },
1017
+ orderBy: {
1018
+ type: toList(this._inputObjects[`${relationID}-order`])
820
1019
  }
821
- if (isList(type)) {
822
- // TODO: add suport for filters?
823
- fields[`_${key}_documents`] = {
824
- type: new GraphQLNonNull(toOuputList(relationType)),
825
- resolve: async (doc, _args, ctx)=>{
826
- const relationIDs = doc.data?.[key] ?? [];
827
- return relationIDs.length ? await this.resolveList(relationModelID, relationIDs, ctx) : [];
828
- }
829
- };
830
- } else {
831
- fields[`_${key}_document`] = {
832
- type: relationType,
833
- resolve: async (doc, _args, ctx)=>{
834
- const relationID = doc.data?.[key];
835
- return relationID ? await this.loadDocument(relationID, ctx) : null;
1020
+ },
1021
+ resolve: (doc, args, ctx)=>{
1022
+ const docFilter = {
1023
+ where: {
1024
+ [fieldName]: {
1025
+ equalTo: doc.id
836
1026
  }
837
- };
838
- }
1027
+ }
1028
+ };
1029
+ const filter = args.filter ? {
1030
+ and: [
1031
+ args.filter,
1032
+ docFilter
1033
+ ]
1034
+ } : docFilter;
1035
+ return ctx.resolveConnection(this.getModelIDs(relationID), {
1036
+ ...args,
1037
+ filter
1038
+ });
839
1039
  }
840
- for (const iid of model.interfaces ?? []){
841
- const interfaceID = getGlobalID(iid, id).toString();
842
- for (const [fieldName, relationID] of Object.entries(this._relationsTo[interfaceID] ?? {})){
843
- const relationName = this._aliases[relationID];
844
- fields[`_${fieldName}_of_${relationName}_list`] = {
845
- type: new GraphQLNonNull(this._types[`${relationID}-connection`])
846
- };
847
- fields[`_${fieldName}_of_${relationName}_count`] = {
848
- type: new GraphQLNonNull(GraphQLInt)
849
- };
1040
+ };
1041
+ // TODO: add support for count relation
1042
+ // fields[`_${fieldName}_of_${relationName}_count`] = {
1043
+ // type: new GraphQLNonNull(GraphQLInt),
1044
+ // }
1045
+ }
1046
+ _buildRelationSubscriptions(fields, modelID, fieldName, relation) {
1047
+ if (relation.isList) {
1048
+ // Inverse relations to list fields are not supported in connections so we skip them for subscriptions as well
1049
+ return;
1050
+ }
1051
+ const relationName = `${pascalCase(fieldName)}Of${this._aliases[relation.model]}`;
1052
+ fields[`edgeAddedTo${relationName}`] = {
1053
+ type: new GraphQLNonNull(this._types[`${modelID}-edge`]),
1054
+ args: {
1055
+ id: {
1056
+ type: new GraphQLNonNull(GraphQLID)
850
1057
  }
1058
+ },
1059
+ resolve: (edge)=>edge,
1060
+ subscribe: (_src, args, ctx)=>{
1061
+ return ctx.subscribeToDocumentEdgeAdded(this.getModelIDs(modelID), (data)=>data[fieldName] === args.id);
851
1062
  }
852
- for (const [fieldName, relationID] of Object.entries(this._relationsTo[id] ?? {})){
853
- const relationName = this._aliases[relationID];
854
- fields[`_${fieldName}_of_${relationName}_list`] = {
855
- type: new GraphQLNonNull(this._types[`${relationID}-connection`])
856
- };
857
- fields[`_${fieldName}_of_${relationName}_count`] = {
858
- type: new GraphQLNonNull(GraphQLInt)
859
- };
1063
+ };
1064
+ fields[`edgeRemovedFrom${relationName}`] = {
1065
+ type: new GraphQLNonNull(GraphQLID),
1066
+ args: {
1067
+ id: {
1068
+ type: new GraphQLNonNull(GraphQLID)
1069
+ }
1070
+ },
1071
+ resolve: (id)=>id,
1072
+ subscribe: (_src, args, ctx)=>{
1073
+ return ctx.subscribeToDocumentEdgeRemoved(this.getModelIDs(modelID), (data)=>data[fieldName] === args.id);
860
1074
  }
861
- }
862
- return fields;
1075
+ };
863
1076
  }
864
1077
  _buildString(schema, asInput) {
865
1078
  if (schema.const != null) {
@@ -912,3 +1125,9 @@ export class SchemaBuilder {
912
1125
  return scalar;
913
1126
  }
914
1127
  }
1128
+ export function createSchema(record, aliases) {
1129
+ return new SchemaBuilder({
1130
+ record,
1131
+ aliases
1132
+ }).build();
1133
+ }
package/lib/types.d.ts ADDED
@@ -0,0 +1,26 @@
1
+ export type PatchAddOperation = {
2
+ op: 'add';
3
+ path: string;
4
+ value: unknown;
5
+ };
6
+ export type PatchRemoveOperation = {
7
+ op: 'remove';
8
+ path: string;
9
+ };
10
+ export type PatchReplaceOperation = {
11
+ op: 'replace';
12
+ path: string;
13
+ value: unknown;
14
+ };
15
+ export type PatchMoveOperation = {
16
+ op: 'move';
17
+ from: string;
18
+ path: string;
19
+ };
20
+ export type PatchCopyOperation = {
21
+ op: 'copy';
22
+ from: string;
23
+ path: string;
24
+ };
25
+ export type PatchOperation = PatchAddOperation | PatchCopyOperation | PatchMoveOperation | PatchRemoveOperation | PatchReplaceOperation;
26
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,iBAAiB,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAAA;AAC3E,MAAM,MAAM,oBAAoB,GAAG;IAAE,EAAE,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAA;AACjE,MAAM,MAAM,qBAAqB,GAAG;IAAE,EAAE,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAAA;AACnF,MAAM,MAAM,kBAAkB,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAA;AAC3E,MAAM,MAAM,kBAAkB,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAA;AAC3E,MAAM,MAAM,cAAc,GACtB,iBAAiB,GACjB,kBAAkB,GAClB,kBAAkB,GAClB,oBAAoB,GACpB,qBAAqB,CAAA"}
package/lib/types.js ADDED
@@ -0,0 +1 @@
1
+ export { };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kubun/graphql",
3
- "version": "0.2.5",
3
+ "version": "0.3.1",
4
4
  "license": "see LICENSE.md",
5
5
  "keywords": [],
6
6
  "type": "module",
@@ -15,14 +15,14 @@
15
15
  ],
16
16
  "sideEffects": false,
17
17
  "dependencies": {
18
- "@enkaku/codec": "^0.11.0",
18
+ "@enkaku/codec": "^0.12.0",
19
19
  "change-case": "^5.4.4",
20
20
  "graphql": "^16.9.0",
21
21
  "graphql-relay": "^0.10.2",
22
22
  "graphql-scalars": "^1.24.2",
23
23
  "multiformats": "^13.3.2",
24
- "@kubun/id": "^0.2.0",
25
- "@kubun/protocol": "^0.2.5"
24
+ "@kubun/id": "^0.3.0",
25
+ "@kubun/protocol": "^0.3.1"
26
26
  },
27
27
  "devDependencies": {
28
28
  "json-schema-typed": "^8.0.1"