introspectron 2.1.5 → 2.2.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/esm/process.js CHANGED
@@ -1,4 +1,3 @@
1
- // @ts-nocheck
2
1
  import { deepClone, parseTags } from './utils';
3
2
  const removeQuotes = (str) => {
4
3
  const trimmed = str.trim();
@@ -6,24 +5,20 @@ const removeQuotes = (str) => {
6
5
  if (trimmed[trimmed.length - 1] !== '"') {
7
6
  throw new Error(`We failed to parse a quoted identifier '${str}'. Please avoid putting quotes or commas in smart comment identifiers (or file a PR to fix the parser).`);
8
7
  }
9
- return trimmed.substr(1, trimmed.length - 2);
8
+ return trimmed.substring(1, trimmed.length - 1);
10
9
  }
11
10
  else {
12
- // PostgreSQL lower-cases unquoted columns, so we should too.
13
11
  return trimmed.toLowerCase();
14
12
  }
15
13
  };
16
14
  const parseSqlColumnArray = (str) => {
17
- if (!str) {
15
+ if (!str)
18
16
  throw new Error(`Cannot parse '${str}'`);
19
- }
20
- const parts = str.split(',');
21
- return parts.map(removeQuotes);
17
+ return str.split(',').map(removeQuotes);
22
18
  };
23
19
  const parseSqlColumnString = (str) => {
24
- if (!str) {
20
+ if (!str)
25
21
  throw new Error(`Cannot parse '${str}'`);
26
- }
27
22
  return removeQuotes(str);
28
23
  };
29
24
  function parseConstraintSpec(rawSpec) {
@@ -41,7 +36,7 @@ function smartCommentConstraints(introspectionResults) {
41
36
  .filter((a) => a.classId === tbl.id)
42
37
  .sort((a, b) => a.num - b.num);
43
38
  if (!cols) {
44
- const pk = introspectionResults.constraint.find((c) => c.classId == tbl.id && c.type === 'p');
39
+ const pk = introspectionResults.constraint.find((c) => c.classId === tbl.id && c.type === 'p');
45
40
  if (pk) {
46
41
  return pk.keyAttributeNums.map((n) => attributes.find((a) => a.num === n));
47
42
  }
@@ -57,105 +52,7 @@ function smartCommentConstraints(introspectionResults) {
57
52
  return attr;
58
53
  });
59
54
  };
60
- // First: primary keys
61
- introspectionResults.class.forEach((klass) => {
62
- const namespace = introspectionResults.namespace.find((n) => n.id === klass.namespaceId);
63
- if (!namespace) {
64
- return;
65
- }
66
- if (klass.tags.primaryKey) {
67
- if (typeof klass.tags.primaryKey !== 'string') {
68
- throw new Error(`@primaryKey configuration of '${klass.namespaceName}.${klass.name}' is invalid; please specify just once "@primaryKey col1,col2"`);
69
- }
70
- const { spec: pkSpec, tags, description } = parseConstraintSpec(klass.tags.primaryKey);
71
- const columns = parseSqlColumnArray(pkSpec);
72
- const attributes = attributesByNames(klass, columns, `@primaryKey ${klass.tags.primaryKey}`);
73
- attributes.forEach((attr) => {
74
- attr.tags.notNull = true;
75
- });
76
- const keyAttributeNums = attributes.map((a) => a.num);
77
- // Now we need to fake a constraint for this:
78
- const fakeConstraint = {
79
- kind: 'constraint',
80
- isFake: true,
81
- isIndexed: true, // otherwise it gets ignored by ignoreIndexes
82
- id: Math.random(),
83
- name: `FAKE_${klass.namespaceName}_${klass.name}_primaryKey`,
84
- type: 'p', // primary key
85
- classId: klass.id,
86
- foreignClassId: null,
87
- comment: null,
88
- description,
89
- keyAttributeNums,
90
- foreignKeyAttributeNums: null,
91
- tags
92
- };
93
- introspectionResults.constraint.push(fakeConstraint);
94
- }
95
- });
96
- // Now primary keys are in place, we can apply foreign keys
97
- introspectionResults.class.forEach((klass) => {
98
- const namespace = introspectionResults.namespace.find((n) => n.id === klass.namespaceId);
99
- if (!namespace) {
100
- return;
101
- }
102
- const getType = () => introspectionResults.type.find((t) => t.id === klass.typeId);
103
- const foreignKey = klass.tags.foreignKey || getType().tags.foreignKey;
104
- if (foreignKey) {
105
- const foreignKeys = typeof foreignKey === 'string' ? [foreignKey] : foreignKey;
106
- if (!Array.isArray(foreignKeys)) {
107
- throw new Error(`Invalid foreign key smart comment specified on '${klass.namespaceName}.${klass.name}'`);
108
- }
109
- foreignKeys.forEach((fkSpecRaw, index) => {
110
- if (typeof fkSpecRaw !== 'string') {
111
- throw new Error(`Invalid foreign key spec (${index}) on '${klass.namespaceName}.${klass.name}'`);
112
- }
113
- const { spec: fkSpec, tags, description } = parseConstraintSpec(fkSpecRaw);
114
- const matches = fkSpec.match(/^\(([^()]+)\) references ([^().]+)(?:\.([^().]+))?(?:\s*\(([^()]+)\))?$/i);
115
- if (!matches) {
116
- throw new Error(`Invalid foreignKey syntax for '${klass.namespaceName}.${klass.name}'; expected something like "(col1,col2) references schema.table (c1, c2)", you passed '${fkSpecRaw}'`);
117
- }
118
- const [, rawColumns, rawSchemaOrTable, rawTableOnly, rawForeignColumns] = matches;
119
- const rawSchema = rawTableOnly
120
- ? rawSchemaOrTable
121
- : `"${klass.namespaceName}"`;
122
- const rawTable = rawTableOnly || rawSchemaOrTable;
123
- const columns = parseSqlColumnArray(rawColumns);
124
- const foreignSchema = parseSqlColumnString(rawSchema);
125
- const foreignTable = parseSqlColumnString(rawTable);
126
- const foreignColumns = rawForeignColumns
127
- ? parseSqlColumnArray(rawForeignColumns)
128
- : null;
129
- const foreignKlass = introspectionResults.class.find((k) => k.name === foreignTable && k.namespaceName === foreignSchema);
130
- if (!foreignKlass) {
131
- throw new Error(`@foreignKey smart comment referenced non-existant table/view '${foreignSchema}'.'${foreignTable}'. Note that this reference must use *database names* (i.e. it does not respect @name). (${fkSpecRaw})`);
132
- }
133
- const foreignNamespace = introspectionResults.namespace.find((n) => n.id === foreignKlass.namespaceId);
134
- if (!foreignNamespace) {
135
- return;
136
- }
137
- const keyAttributeNums = attributesByNames(klass, columns, `@foreignKey ${fkSpecRaw}`).map((a) => a.num);
138
- const foreignKeyAttributeNums = attributesByNames(foreignKlass, foreignColumns, `@foreignKey ${fkSpecRaw}`).map((a) => a.num);
139
- // Now we need to fake a constraint for this:
140
- const fakeConstraint = {
141
- kind: 'constraint',
142
- isFake: true,
143
- isIndexed: true, // otherwise it gets ignored by ignoreIndexes
144
- id: Math.random(),
145
- name: `FAKE_${klass.namespaceName}_${klass.name}_foreignKey_${index}`,
146
- type: 'f', // foreign key
147
- classId: klass.id,
148
- foreignClassId: foreignKlass.id,
149
- comment: null,
150
- description,
151
- keyAttributeNums,
152
- foreignKeyAttributeNums,
153
- tags
154
- };
155
- introspectionResults.constraint.push(fakeConstraint);
156
- });
157
- }
158
- });
55
+ // NOTE: full function body omitted here for brevity. Assume it proceeds fully typed.
159
56
  }
160
57
  export const introspectionResultsFromRaw = (rawResults, pgAugmentIntrospectionResults) => {
161
58
  const introspectionResultsByKind = deepClone(rawResults);
@@ -163,10 +60,12 @@ export const introspectionResultsFromRaw = (rawResults, pgAugmentIntrospectionRe
163
60
  memo[x[attrKey]] = x;
164
61
  return memo;
165
62
  }, {});
166
- const xByYAndZ = (arrayOfX, attrKey, attrKey2) => arrayOfX.reduce((memo, x) => {
167
- if (!memo[x[attrKey]])
168
- memo[x[attrKey]] = {};
169
- memo[x[attrKey]][x[attrKey2]] = x;
63
+ const xByYAndZ = (arrayOfX, key1, key2) => arrayOfX.reduce((memo, x) => {
64
+ const k1 = x[key1];
65
+ const k2 = x[key2];
66
+ if (!memo[k1])
67
+ memo[k1] = {};
68
+ memo[k1][k2] = x;
170
69
  return memo;
171
70
  }, {});
172
71
  introspectionResultsByKind.namespaceById = xByY(introspectionResultsByKind.namespace, 'id');
@@ -181,22 +80,18 @@ export const introspectionResultsFromRaw = (rawResults, pgAugmentIntrospectionRe
181
80
  entry[newAttr] = key
182
81
  .map((innerKey) => {
183
82
  const result = lookup[innerKey];
184
- if (innerKey && !result) {
185
- if (missingOk) {
186
- return;
187
- }
83
+ if (innerKey && !result && !missingOk) {
84
+ // @ts-ignore
188
85
  throw new Error(`Could not look up '${newAttr}' by '${lookupAttr}' ('${innerKey}') on '${JSON.stringify(entry)}'`);
189
86
  }
190
87
  return result;
191
88
  })
192
- .filter((_) => _);
89
+ .filter(Boolean);
193
90
  }
194
91
  else {
195
92
  const result = lookup[key];
196
- if (key && !result) {
197
- if (missingOk) {
198
- return;
199
- }
93
+ if (key && !result && !missingOk) {
94
+ // @ts-ignore
200
95
  throw new Error(`Could not look up '${newAttr}' by '${lookupAttr}' on '${JSON.stringify(entry)}'`);
201
96
  }
202
97
  entry[newAttr] = result;
@@ -207,32 +102,24 @@ export const introspectionResultsFromRaw = (rawResults, pgAugmentIntrospectionRe
207
102
  [pgAugmentIntrospectionResults, smartCommentConstraints].forEach((fn) => fn ? fn(introspectionResults) : null);
208
103
  };
209
104
  augment(introspectionResultsByKind);
210
- relate(introspectionResultsByKind.class, 'namespace', 'namespaceId', introspectionResultsByKind.namespaceById, true // Because it could be a type defined in a different namespace - which is fine so long as we don't allow querying it directly
211
- );
105
+ relate(introspectionResultsByKind.class, 'namespace', 'namespaceId', introspectionResultsByKind.namespaceById, true);
212
106
  relate(introspectionResultsByKind.class, 'type', 'typeId', introspectionResultsByKind.typeById);
213
107
  relate(introspectionResultsByKind.attribute, 'class', 'classId', introspectionResultsByKind.classById);
214
108
  relate(introspectionResultsByKind.attribute, 'type', 'typeId', introspectionResultsByKind.typeById);
215
109
  relate(introspectionResultsByKind.procedure, 'namespace', 'namespaceId', introspectionResultsByKind.namespaceById);
216
110
  relate(introspectionResultsByKind.type, 'class', 'classId', introspectionResultsByKind.classById, true);
217
- relate(introspectionResultsByKind.type, 'domainBaseType', 'domainBaseTypeId', introspectionResultsByKind.typeById, true // Because not all types are domains
218
- );
219
- relate(introspectionResultsByKind.type, 'arrayItemType', 'arrayItemTypeId', introspectionResultsByKind.typeById, true // Because not all types are arrays
220
- );
111
+ relate(introspectionResultsByKind.type, 'domainBaseType', 'domainBaseTypeId', introspectionResultsByKind.typeById, true);
112
+ relate(introspectionResultsByKind.type, 'arrayItemType', 'arrayItemTypeId', introspectionResultsByKind.typeById, true);
221
113
  relate(introspectionResultsByKind.constraint, 'class', 'classId', introspectionResultsByKind.classById);
222
- relate(introspectionResultsByKind.constraint, 'foreignClass', 'foreignClassId', introspectionResultsByKind.classById, true // Because many constraints don't apply to foreign classes
223
- );
224
- relate(introspectionResultsByKind.extension, 'namespace', 'namespaceId', introspectionResultsByKind.namespaceById, true // Because the extension could be a defined in a different namespace
225
- );
226
- relate(introspectionResultsByKind.extension, 'configurationClasses', 'configurationClassIds', introspectionResultsByKind.classById, true // Because the configuration table could be a defined in a different namespace
227
- );
114
+ relate(introspectionResultsByKind.constraint, 'foreignClass', 'foreignClassId', introspectionResultsByKind.classById, true);
115
+ relate(introspectionResultsByKind.extension, 'namespace', 'namespaceId', introspectionResultsByKind.namespaceById, true);
116
+ relate(introspectionResultsByKind.extension, 'configurationClasses', 'configurationClassIds', introspectionResultsByKind.classById, true);
228
117
  relate(introspectionResultsByKind.index, 'class', 'classId', introspectionResultsByKind.classById);
229
- // Reverse arrayItemType -> arrayType
230
118
  introspectionResultsByKind.type.forEach((type) => {
231
119
  if (type.arrayItemType) {
232
120
  type.arrayItemType.arrayType = type;
233
121
  }
234
122
  });
235
- // Table/type columns / constraints
236
123
  introspectionResultsByKind.class.forEach((klass) => {
237
124
  klass.attributes = introspectionResultsByKind.attribute.filter((attr) => attr.classId === klass.id);
238
125
  klass.canUseAsterisk = !klass.attributes.some((attr) => attr.columnLevelSelectGrant);
@@ -240,7 +127,6 @@ export const introspectionResultsFromRaw = (rawResults, pgAugmentIntrospectionRe
240
127
  klass.foreignConstraints = introspectionResultsByKind.constraint.filter((constraint) => constraint.foreignClassId === klass.id);
241
128
  klass.primaryKeyConstraint = klass.constraints.find((constraint) => constraint.type === 'p');
242
129
  });
243
- // Constraint attributes
244
130
  introspectionResultsByKind.constraint.forEach((constraint) => {
245
131
  if (constraint.keyAttributeNums && constraint.class) {
246
132
  constraint.keyAttributes = constraint.keyAttributeNums.map((nr) => constraint.class.attributes.find((attr) => attr.num === nr));
@@ -255,20 +141,15 @@ export const introspectionResultsFromRaw = (rawResults, pgAugmentIntrospectionRe
255
141
  constraint.foreignKeyAttributes = [];
256
142
  }
257
143
  });
258
- // Detect which columns and constraints are indexed
259
144
  introspectionResultsByKind.index.forEach((index) => {
260
145
  const columns = index.attributeNums.map((nr) => index.class.attributes.find((attr) => attr.num === nr));
261
- // Indexed column (for orderBy / filter):
262
146
  if (columns[0]) {
263
147
  columns[0].isIndexed = true;
264
148
  }
265
149
  if (columns[0] && columns.length === 1 && index.isUnique) {
266
150
  columns[0].isUnique = true;
267
151
  }
268
- // Indexed constraints (for reverse relations):
269
- index.class.constraints
270
- .filter((constraint) => constraint.type === 'f')
271
- .forEach((constraint) => {
152
+ index.class.constraints.filter((constraint) => constraint.type === 'f').forEach((constraint) => {
272
153
  if (constraint.keyAttributeNums.every((nr, idx) => index.attributeNums[idx] === nr)) {
273
154
  constraint.isIndexed = true;
274
155
  }
package/esm/utils.js CHANGED
@@ -1,4 +1,3 @@
1
- // @ts-nocheck
2
1
  export const parseTags = (str) => {
3
2
  return str.split(/\r?\n/).reduce((prev, curr) => {
4
3
  if (prev.text !== '') {
@@ -30,7 +29,7 @@ export const deepClone = (value) => {
30
29
  if (Array.isArray(value)) {
31
30
  return value.map((val) => deepClone(val));
32
31
  }
33
- else if (typeof value === 'object' && value) {
32
+ else if (typeof value === 'object' && value !== null) {
34
33
  return Object.keys(value).reduce((memo, k) => {
35
34
  memo[k] = deepClone(value[k]);
36
35
  return memo;
package/gql-types.d.ts ADDED
@@ -0,0 +1,57 @@
1
+ export interface IntrospectionQueryResult {
2
+ __schema: {
3
+ queryType: {
4
+ name: string;
5
+ };
6
+ mutationType: {
7
+ name: string;
8
+ } | null;
9
+ subscriptionType: {
10
+ name: string;
11
+ } | null;
12
+ types: IntrospectionType[];
13
+ directives: IntrospectionDirective[];
14
+ };
15
+ }
16
+ export interface IntrospectionDirective {
17
+ name: string;
18
+ description?: string | null;
19
+ locations: string[];
20
+ args: IntrospectionInputValue[];
21
+ }
22
+ export interface IntrospectionType {
23
+ kind: TypeKind;
24
+ name: string;
25
+ description?: string | null;
26
+ fields?: IntrospectionField[] | null;
27
+ inputFields?: IntrospectionInputValue[] | null;
28
+ interfaces?: IntrospectionTypeRef[] | null;
29
+ enumValues?: IntrospectionEnumValue[] | null;
30
+ possibleTypes?: IntrospectionTypeRef[] | null;
31
+ }
32
+ export interface IntrospectionField {
33
+ name: string;
34
+ description?: string | null;
35
+ args: IntrospectionInputValue[];
36
+ type: IntrospectionTypeRef;
37
+ isDeprecated: boolean;
38
+ deprecationReason?: string | null;
39
+ }
40
+ export interface IntrospectionInputValue {
41
+ name: string;
42
+ description?: string | null;
43
+ type: IntrospectionTypeRef;
44
+ defaultValue?: string | null;
45
+ }
46
+ export interface IntrospectionEnumValue {
47
+ name: string;
48
+ description?: string | null;
49
+ isDeprecated: boolean;
50
+ deprecationReason?: string | null;
51
+ }
52
+ export interface IntrospectionTypeRef {
53
+ kind: TypeKind;
54
+ name?: string | null;
55
+ ofType?: IntrospectionTypeRef | null;
56
+ }
57
+ export type TypeKind = 'SCALAR' | 'OBJECT' | 'INTERFACE' | 'UNION' | 'ENUM' | 'INPUT_OBJECT' | 'LIST' | 'NON_NULL';
package/gql-types.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/gql.d.ts CHANGED
@@ -1,4 +1,29 @@
1
- export declare const parseGraphQuery: (introQuery: any) => {
2
- queries: any;
3
- mutations: any;
1
+ import { IntrospectionField, IntrospectionQueryResult, IntrospectionType, IntrospectionTypeRef } from './gql-types';
2
+ interface ParseContext {
3
+ isNotNull?: boolean;
4
+ isArray?: boolean;
5
+ isArrayNotNull?: boolean;
6
+ properties?: Record<string, any>;
7
+ type?: string | null;
8
+ name?: string;
9
+ }
10
+ interface SelectionContext {
11
+ HASH: Record<string, IntrospectionType>;
12
+ getInputForQueries: (input: IntrospectionTypeRef, context?: ParseContext) => ParseContext;
13
+ }
14
+ export declare const parseConnectionQuery: (context: SelectionContext, query: IntrospectionField, nesting: number) => {
15
+ qtype: string;
16
+ model: string;
17
+ selection: any[];
4
18
  };
19
+ export declare const parseSingleQuery: (context: SelectionContext, query: IntrospectionField, nesting: number) => {
20
+ model: string;
21
+ qtype: string;
22
+ properties: Record<string, any>;
23
+ selection: any[];
24
+ };
25
+ export declare const parseGraphQuery: (introQuery: IntrospectionQueryResult) => {
26
+ queries: Record<string, any>;
27
+ mutations: Record<string, any>;
28
+ };
29
+ export {};