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