graphile-meta-schema 0.2.5 → 0.2.7

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/index.js ADDED
@@ -0,0 +1,509 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.PgMetaschemaPlugin = void 0;
7
+ const graphile_utils_1 = require("graphile-utils");
8
+ const graphql_1 = require("graphql");
9
+ const belongs_to_1 = __importDefault(require("./belongs-to"));
10
+ const has_1 = __importDefault(require("./has"));
11
+ const many_to_many_1 = __importDefault(require("./many-to-many"));
12
+ const GIS_TYPES = [
13
+ 'Geometry',
14
+ 'Point',
15
+ 'LineString',
16
+ 'Polygon',
17
+ 'MultiPoint',
18
+ 'MultiLineString',
19
+ 'MultiPolygon',
20
+ 'GeometryCollection'
21
+ ];
22
+ const TYPE_ALIASES = {
23
+ int8: 'bigint',
24
+ bool: 'boolean',
25
+ bpchar: 'char',
26
+ float8: 'float',
27
+ float4: 'real',
28
+ int4: 'int',
29
+ int2: 'smallint'
30
+ };
31
+ const aliasTypes = (typeName) => TYPE_ALIASES[typeName] ?? typeName;
32
+ const getTypeName = (graphQLType) => (0, graphql_1.getNamedType)(graphQLType).name;
33
+ const PgMetaschemaPlugin = (0, graphile_utils_1.makeExtendSchemaPlugin)((build, schemaOptions) => {
34
+ const pgBuild = build;
35
+ const pgSchemaOptions = schemaOptions;
36
+ const introspection = pgBuild.pgIntrospectionResultsByKind;
37
+ const inflection = pgBuild.inflection;
38
+ const schemas = pgSchemaOptions.pgSchemas ?? [];
39
+ const pgGetGqlTypeByTypeIdAndModifier = pgBuild.pgGetGqlTypeByTypeIdAndModifier;
40
+ return {
41
+ typeDefs: (0, graphile_utils_1.gql) `
42
+ type MetaschemaType {
43
+ pgAlias: String!
44
+ pgType: String!
45
+ gqlType: String!
46
+ subtype: String
47
+ modifier: Int
48
+ typmod: JSON
49
+ isArray: Boolean!
50
+ }
51
+ type MetaschemaField {
52
+ name: String!
53
+ type: MetaschemaType!
54
+ }
55
+ type MetaschemaTableInflection {
56
+ # https://github.com/graphile/graphile-engine/blob/v4/packages/graphile-build-pg/src/plugins/PgBasicsPlugin.js
57
+ allRows: String!
58
+ allRowsSimple: String!
59
+ tableFieldName: String!
60
+ tableType: String!
61
+ createPayloadType: String!
62
+ orderByType: String!
63
+ filterType: String
64
+ inputType: String!
65
+ patchType: String
66
+ conditionType: String!
67
+ patchField: String!
68
+ edge: String!
69
+ edgeField: String!
70
+ connection: String!
71
+ typeName: String!
72
+ enumType: String!
73
+
74
+ updatePayloadType: String
75
+ deletePayloadType: String!
76
+ deleteByPrimaryKey: String
77
+ updateByPrimaryKey: String
78
+
79
+ createField: String!
80
+ createInputType: String!
81
+ }
82
+ type MetaschemaTableQuery {
83
+ all: String!
84
+ one: String!
85
+ create: String!
86
+ update: String
87
+ delete: String
88
+ }
89
+ type MetaschemaTableManyToManyRelation {
90
+ fieldName: String
91
+ type: String
92
+ leftKeyAttributes: [MetaschemaField]!
93
+ rightKeyAttributes: [MetaschemaField]!
94
+ junctionLeftKeyAttributes: [MetaschemaField]!
95
+ junctionRightKeyAttributes: [MetaschemaField]!
96
+ junctionTable: MetaschemaTable!
97
+ rightTable: MetaschemaTable!
98
+ junctionLeftConstraint: MetaschemaForeignKeyConstraint!
99
+ junctionRightConstraint: MetaschemaForeignKeyConstraint!
100
+ }
101
+ type MetaschemaTableHasRelation {
102
+ fieldName: String
103
+ type: String
104
+ referencedBy: MetaschemaTable!
105
+ isUnique: Boolean!
106
+ keys: [MetaschemaField]
107
+ }
108
+ type MetaschemaTableBelongsToRelation {
109
+ fieldName: String
110
+ type: String
111
+ references: MetaschemaTable!
112
+ isUnique: Boolean!
113
+ keys: [MetaschemaField]
114
+ }
115
+ type MetaschemaTableRelation {
116
+ hasOne: [MetaschemaTableHasRelation]
117
+ hasMany: [MetaschemaTableHasRelation]
118
+ has: [MetaschemaTableHasRelation]
119
+ belongsTo: [MetaschemaTableBelongsToRelation]
120
+ manyToMany: [MetaschemaTableManyToManyRelation]
121
+ }
122
+
123
+ type MetaschemaTable {
124
+ name: String!
125
+ query: MetaschemaTableQuery!
126
+ inflection: MetaschemaTableInflection!
127
+ relations: MetaschemaTableRelation
128
+ fields: [MetaschemaField]
129
+ constraints: [MetaschemaConstraint]
130
+ foreignKeyConstraints: [MetaschemaForeignKeyConstraint]
131
+ primaryKeyConstraints: [MetaschemaPrimaryKeyConstraint]
132
+ uniqueConstraints: [MetaschemaUniqueConstraint]
133
+ checkConstraints: [MetaschemaCheckConstraint]
134
+ exclusionConstraints: [MetaschemaExclusionConstraint]
135
+ }
136
+ union MetaschemaConstraint =
137
+ MetaschemaForeignKeyConstraint
138
+ | MetaschemaUniqueConstraint
139
+ | MetaschemaPrimaryKeyConstraint
140
+ | MetaschemaCheckConstraint
141
+ | MetaschemaExclusionConstraint
142
+ type MetaschemaForeignKeyConstraint {
143
+ name: String!
144
+ fields: [MetaschemaField]
145
+ refTable: MetaschemaTable
146
+ refFields: [MetaschemaField]
147
+ }
148
+ type MetaschemaUniqueConstraint {
149
+ name: String!
150
+ fields: [MetaschemaField]
151
+ }
152
+ type MetaschemaPrimaryKeyConstraint {
153
+ name: String!
154
+ fields: [MetaschemaField]
155
+ }
156
+ type MetaschemaCheckConstraint {
157
+ name: String!
158
+ fields: [MetaschemaField]
159
+ }
160
+ type MetaschemaExclusionConstraint {
161
+ name: String!
162
+ fields: [MetaschemaField]
163
+ }
164
+ type Metaschema {
165
+ tables: [MetaschemaTable]
166
+ }
167
+ extend type Query {
168
+ _meta: Metaschema
169
+ }
170
+ `,
171
+ resolvers: {
172
+ MetaschemaCheckConstraint: {
173
+ fields(constraint) {
174
+ return constraint.keyAttributes;
175
+ }
176
+ },
177
+ MetaschemaExclusionConstraint: {
178
+ fields(constraint) {
179
+ return constraint.keyAttributes;
180
+ }
181
+ },
182
+ MetaschemaUniqueConstraint: {
183
+ fields(constraint) {
184
+ return constraint.keyAttributes;
185
+ }
186
+ },
187
+ MetaschemaPrimaryKeyConstraint: {
188
+ fields(constraint) {
189
+ return constraint.keyAttributes;
190
+ }
191
+ },
192
+ MetaschemaForeignKeyConstraint: {
193
+ fields(constraint) {
194
+ return constraint.keyAttributes;
195
+ },
196
+ refTable(constraint) {
197
+ return constraint.foreignClass;
198
+ },
199
+ refFields(constraint) {
200
+ return constraint.foreignKeyAttributes;
201
+ }
202
+ },
203
+ MetaschemaType: {
204
+ pgType(type) {
205
+ if (type.isPgArray && type.arrayItemType?.name) {
206
+ return type.arrayItemType.name;
207
+ }
208
+ return type.name;
209
+ },
210
+ pgAlias(type) {
211
+ if (type.isPgArray && type.arrayItemType?.name) {
212
+ return aliasTypes(type.arrayItemType.name);
213
+ }
214
+ return aliasTypes(type.name);
215
+ },
216
+ gqlType(type) {
217
+ const gqlType = pgGetGqlTypeByTypeIdAndModifier(type.id, type.attrTypeModifier ?? null);
218
+ const typeName = getTypeName(gqlType);
219
+ switch (typeName) {
220
+ case 'GeometryInterface':
221
+ case 'GeometryPoint':
222
+ case 'GeometryPolygon':
223
+ return 'GeoJSON';
224
+ default:
225
+ return typeName;
226
+ }
227
+ },
228
+ subtype(type) {
229
+ const gqlType = pgGetGqlTypeByTypeIdAndModifier(type.id, type.attrTypeModifier ?? null);
230
+ const typeName = getTypeName(gqlType);
231
+ switch (typeName) {
232
+ case 'GeometryInterface':
233
+ case 'GeometryPoint':
234
+ case 'GeometryPolygon':
235
+ return typeName;
236
+ default:
237
+ return null;
238
+ }
239
+ },
240
+ typmod(type) {
241
+ const modifier = type.attrTypeModifier;
242
+ if (!modifier)
243
+ return null;
244
+ if (type.name === 'geography' || type.name === 'geometry') {
245
+ const srid = ((modifier & 0x0fffff00) - (modifier & 0x10000000)) >> 8;
246
+ const subtype = (modifier & 0x000000fc) >> 2;
247
+ const hasZ = ((modifier & 0x00000002) >> 1) === 1;
248
+ const hasM = (modifier & 0x00000001) === 1;
249
+ if (subtype < GIS_TYPES.length) {
250
+ return {
251
+ srid,
252
+ subtype,
253
+ hasZ,
254
+ hasM,
255
+ gisType: GIS_TYPES[subtype]
256
+ };
257
+ }
258
+ }
259
+ return { modifier };
260
+ },
261
+ modifier(type) {
262
+ return type.attrTypeModifier;
263
+ },
264
+ isArray(type) {
265
+ return type.isPgArray;
266
+ }
267
+ },
268
+ MetaschemaField: {
269
+ name(attr) {
270
+ return inflection.column(attr);
271
+ },
272
+ type(attr) {
273
+ if (attr.typeModifier > 0) {
274
+ return {
275
+ ...attr.type,
276
+ attrTypeModifier: attr.typeModifier
277
+ };
278
+ }
279
+ return attr.type;
280
+ }
281
+ },
282
+ MetaschemaTableInflection: {
283
+ deleteByPrimaryKey(table) {
284
+ if (!table.primaryKeyConstraint?.keyAttributes?.length)
285
+ return null;
286
+ return inflection.deleteByKeys(table.primaryKeyConstraint.keyAttributes, table, table.primaryKeyConstraint);
287
+ },
288
+ updateByPrimaryKey(table) {
289
+ if (!table.primaryKeyConstraint?.keyAttributes?.length)
290
+ return null;
291
+ return inflection.updateByKeys(table.primaryKeyConstraint.keyAttributes, table, table.primaryKeyConstraint);
292
+ },
293
+ createField(table) {
294
+ return inflection.createField(table);
295
+ },
296
+ createInputType(table) {
297
+ return inflection.createInputType(table);
298
+ },
299
+ allRows(table) {
300
+ return inflection.allRows(table);
301
+ },
302
+ allRowsSimple(table) {
303
+ return inflection.allRowsSimple(table);
304
+ },
305
+ tableFieldName(table) {
306
+ return inflection.tableFieldName(table);
307
+ },
308
+ tableType(table) {
309
+ return inflection.tableType(table);
310
+ },
311
+ orderByType(table) {
312
+ return inflection.orderByType(inflection.tableType(table));
313
+ },
314
+ filterType(table) {
315
+ if (typeof inflection.filterType === 'function') {
316
+ return inflection.filterType(inflection.tableType(table)) ?? null;
317
+ }
318
+ return null;
319
+ },
320
+ inputType(table) {
321
+ return inflection.inputType(inflection.tableType(table));
322
+ },
323
+ patchType(table) {
324
+ return inflection.patchType(inflection.tableType(table));
325
+ },
326
+ conditionType(table) {
327
+ return inflection.conditionType(inflection.tableType(table));
328
+ },
329
+ patchField(table) {
330
+ return inflection.patchField(inflection.tableType(table));
331
+ },
332
+ edge(table) {
333
+ return inflection.edge(inflection.tableType(table));
334
+ },
335
+ edgeField(table) {
336
+ return inflection.edgeField(table);
337
+ },
338
+ connection(table) {
339
+ return inflection.connection(inflection.tableType(table));
340
+ },
341
+ typeName(table) {
342
+ return inflection._typeName(table);
343
+ },
344
+ enumType(table) {
345
+ return inflection.enumType(table);
346
+ },
347
+ createPayloadType(table) {
348
+ return inflection.createPayloadType(table);
349
+ },
350
+ updatePayloadType(table) {
351
+ return inflection.updatePayloadType(table);
352
+ },
353
+ deletePayloadType(table) {
354
+ return inflection.deletePayloadType(table);
355
+ }
356
+ },
357
+ MetaschemaTableQuery: {
358
+ delete(table) {
359
+ if (!table.primaryKeyConstraint?.keyAttributes?.length)
360
+ return null;
361
+ return inflection.deleteByKeys(table.primaryKeyConstraint.keyAttributes, table, table.primaryKeyConstraint);
362
+ },
363
+ update(table) {
364
+ if (!table.primaryKeyConstraint?.keyAttributes?.length)
365
+ return null;
366
+ return inflection.updateByKeys(table.primaryKeyConstraint.keyAttributes, table, table.primaryKeyConstraint);
367
+ },
368
+ create(table) {
369
+ return inflection.createField(table);
370
+ },
371
+ all(table) {
372
+ return inflection.allRows(table);
373
+ },
374
+ one(table) {
375
+ return inflection.tableFieldName(table);
376
+ }
377
+ },
378
+ MetaschemaTableRelation: {
379
+ hasOne(table) {
380
+ return (0, has_1.default)(table, pgBuild).filter((relation) => relation.type === 'hasOne');
381
+ },
382
+ hasMany(table) {
383
+ return (0, has_1.default)(table, pgBuild).filter((relation) => relation.type === 'hasMany');
384
+ },
385
+ belongsTo(table) {
386
+ return (0, belongs_to_1.default)(table, pgBuild);
387
+ },
388
+ has(table) {
389
+ return (0, has_1.default)(table, pgBuild);
390
+ },
391
+ manyToMany(table) {
392
+ return (0, many_to_many_1.default)(table, pgBuild);
393
+ }
394
+ },
395
+ MetaschemaTableBelongsToRelation: {
396
+ type() {
397
+ return 'BelongsTo';
398
+ }
399
+ },
400
+ MetaschemaTableManyToManyRelation: {
401
+ type() {
402
+ return 'ManyToMany';
403
+ },
404
+ leftKeyAttributes(relation) {
405
+ return relation.leftKeyAttributes;
406
+ },
407
+ junctionLeftKeyAttributes(relation) {
408
+ return relation.junctionLeftKeyAttributes;
409
+ },
410
+ junctionRightKeyAttributes(relation) {
411
+ return relation.junctionRightKeyAttributes;
412
+ },
413
+ rightKeyAttributes(relation) {
414
+ return relation.rightKeyAttributes;
415
+ },
416
+ junctionTable(relation) {
417
+ return relation.junctionTable;
418
+ },
419
+ rightTable(relation) {
420
+ return relation.rightTable;
421
+ },
422
+ junctionLeftConstraint(relation) {
423
+ return relation.junctionLeftConstraint;
424
+ },
425
+ junctionRightConstraint(relation) {
426
+ return relation.junctionRightConstraint;
427
+ },
428
+ fieldName(relation) {
429
+ if (!inflection.manyToManyRelationByKeys) {
430
+ return null;
431
+ }
432
+ const { leftKeyAttributes, junctionLeftKeyAttributes, junctionRightKeyAttributes, rightKeyAttributes, junctionTable, rightTable, junctionLeftConstraint, junctionRightConstraint } = relation;
433
+ return inflection.manyToManyRelationByKeys(leftKeyAttributes, junctionLeftKeyAttributes, junctionRightKeyAttributes, rightKeyAttributes, junctionTable, rightTable, junctionLeftConstraint, junctionRightConstraint);
434
+ }
435
+ },
436
+ MetaschemaTable: {
437
+ relations(table) {
438
+ return table;
439
+ },
440
+ name(table) {
441
+ return inflection.tableType(table);
442
+ },
443
+ fields(table) {
444
+ return table.attributes.filter((attr) => attr.num >= 1);
445
+ },
446
+ inflection(table) {
447
+ return table;
448
+ },
449
+ query(table) {
450
+ return table;
451
+ },
452
+ constraints(table) {
453
+ return table.constraints;
454
+ },
455
+ foreignKeyConstraints(table) {
456
+ return table.constraints.filter((constraint) => constraint.type === 'f');
457
+ },
458
+ primaryKeyConstraints(table) {
459
+ return table.constraints.filter((constraint) => constraint.type === 'p');
460
+ },
461
+ uniqueConstraints(table) {
462
+ return table.constraints.filter((constraint) => constraint.type === 'u');
463
+ },
464
+ checkConstraints(table) {
465
+ return table.constraints.filter((constraint) => constraint.type === 'c');
466
+ },
467
+ exclusionConstraints(table) {
468
+ return table.constraints.filter((constraint) => constraint.type === 'x');
469
+ }
470
+ },
471
+ MetaschemaConstraint: {
472
+ __resolveType(obj) {
473
+ switch (obj.type) {
474
+ case 'p':
475
+ return 'MetaschemaPrimaryKeyConstraint';
476
+ case 'f':
477
+ return 'MetaschemaForeignKeyConstraint';
478
+ case 'c':
479
+ return 'MetaschemaCheckConstraint';
480
+ case 'u':
481
+ return 'MetaschemaUniqueConstraint';
482
+ case 'x':
483
+ return 'MetaschemaExclusionConstraint';
484
+ default:
485
+ return null;
486
+ }
487
+ }
488
+ },
489
+ Metaschema: {
490
+ tables() {
491
+ return introspection.class.filter((table) => {
492
+ if (!schemas.includes(table.namespaceName))
493
+ return false;
494
+ if (table.classKind !== 'r')
495
+ return false;
496
+ return true;
497
+ });
498
+ }
499
+ },
500
+ Query: {
501
+ _meta() {
502
+ return {};
503
+ }
504
+ }
505
+ }
506
+ };
507
+ });
508
+ exports.PgMetaschemaPlugin = PgMetaschemaPlugin;
509
+ exports.default = PgMetaschemaPlugin;
@@ -0,0 +1,3 @@
1
+ import type { ManyToManyRelation, PgBuild, PgClass } from './types';
2
+ declare const getManyToManyRelations: (leftTable: PgClass, build: PgBuild) => ManyToManyRelation[];
3
+ export default getManyToManyRelations;
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const arraysAreEqual = (array1, array2) => array1.length === array2.length && array1.every((value, index) => array2[index] === value);
4
+ const getManyToManyRelations = (leftTable, build) => {
5
+ const { pgIntrospectionResultsByKind: introspectionResultsByKind, pgOmit: omit } = build;
6
+ return leftTable.foreignConstraints
7
+ .filter((constraint) => constraint.type === 'f')
8
+ .reduce((memoLeft, junctionLeftConstraint) => {
9
+ if (omit(junctionLeftConstraint, 'read') ||
10
+ omit(junctionLeftConstraint, 'manyToMany')) {
11
+ return memoLeft;
12
+ }
13
+ const junctionTable = introspectionResultsByKind.classById[String(junctionLeftConstraint.classId)] ??
14
+ junctionLeftConstraint.foreignClass;
15
+ if (!junctionTable) {
16
+ throw new Error(`Could not find the table that referenced us (constraint: ${junctionLeftConstraint.name})`);
17
+ }
18
+ if (omit(junctionTable, 'read') || omit(junctionTable, 'manyToMany')) {
19
+ return memoLeft;
20
+ }
21
+ const memoRight = junctionTable.constraints
22
+ .filter((constraint) => constraint.id !== junctionLeftConstraint.id &&
23
+ constraint.type === 'f' &&
24
+ !omit(constraint, 'read') &&
25
+ !omit(constraint, 'manyToMany'))
26
+ .reduce((memoRightInner, junctionRightConstraint) => {
27
+ const rightTable = junctionRightConstraint.foreignClass ??
28
+ (junctionRightConstraint.foreignClassId !== undefined
29
+ ? introspectionResultsByKind.classById[String(junctionRightConstraint.foreignClassId)]
30
+ : undefined);
31
+ if (!rightTable || omit(rightTable, 'read') || omit(rightTable, 'manyToMany')) {
32
+ return memoRightInner;
33
+ }
34
+ const leftKeyAttributes = junctionLeftConstraint.foreignKeyAttributes;
35
+ const junctionLeftKeyAttributes = junctionLeftConstraint.keyAttributes;
36
+ const junctionRightKeyAttributes = junctionRightConstraint.keyAttributes;
37
+ const rightKeyAttributes = junctionRightConstraint.foreignKeyAttributes;
38
+ if (!leftKeyAttributes.every(Boolean) ||
39
+ !junctionLeftKeyAttributes.every(Boolean) ||
40
+ !junctionRightKeyAttributes.every(Boolean) ||
41
+ !rightKeyAttributes.every(Boolean)) {
42
+ throw new Error('Could not find key columns!');
43
+ }
44
+ if (leftKeyAttributes.some((attr) => omit(attr, 'read')) ||
45
+ junctionLeftKeyAttributes.some((attr) => omit(attr, 'read')) ||
46
+ junctionRightKeyAttributes.some((attr) => omit(attr, 'read')) ||
47
+ rightKeyAttributes.some((attr) => omit(attr, 'read'))) {
48
+ return memoRightInner;
49
+ }
50
+ if (leftKeyAttributes.length > 1 || rightKeyAttributes.length > 1) {
51
+ return memoRightInner;
52
+ }
53
+ const junctionLeftConstraintIsUnique = junctionTable.constraints.some((constraint) => ['p', 'u'].includes(constraint.type) &&
54
+ arraysAreEqual(constraint.keyAttributeNums, junctionLeftKeyAttributes.map((attr) => attr.num)));
55
+ const junctionRightConstraintIsUnique = junctionTable.constraints.some((constraint) => ['p', 'u'].includes(constraint.type) &&
56
+ arraysAreEqual(constraint.keyAttributeNums, junctionRightKeyAttributes.map((attr) => attr.num)));
57
+ if (junctionLeftConstraintIsUnique || junctionRightConstraintIsUnique) {
58
+ return memoRightInner;
59
+ }
60
+ const allowsMultipleEdgesToNode = !junctionTable.constraints.find((constraint) => ['p', 'u'].includes(constraint.type) &&
61
+ arraysAreEqual(constraint.keyAttributeNums.concat().sort(), [
62
+ ...junctionLeftKeyAttributes.map((attr) => attr.num),
63
+ ...junctionRightKeyAttributes.map((attr) => attr.num)
64
+ ].sort()));
65
+ return [
66
+ ...memoRightInner,
67
+ {
68
+ leftKeyAttributes,
69
+ junctionLeftKeyAttributes,
70
+ junctionRightKeyAttributes,
71
+ rightKeyAttributes,
72
+ junctionTable,
73
+ rightTable,
74
+ junctionLeftConstraint,
75
+ junctionRightConstraint,
76
+ allowsMultipleEdgesToNode
77
+ }
78
+ ];
79
+ }, []);
80
+ return [...memoLeft, ...memoRight];
81
+ }, []);
82
+ };
83
+ exports.default = getManyToManyRelations;