Skip to content

Commit 5cd51b6

Browse files
authored
feat(smart-tags): add support for '@unique' fake constraints (#673)
1 parent 99259f4 commit 5cd51b6

3 files changed

Lines changed: 4540 additions & 18 deletions

File tree

packages/graphile-build-pg/src/plugins/PgIntrospectionPlugin.js

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -301,41 +301,47 @@ function smartCommentConstraints(introspectionResults) {
301301
});
302302
};
303303

304-
// First: primary keys
304+
// First: primary and unique keys
305305
introspectionResults.class.forEach(klass => {
306306
const namespace = introspectionResults.namespace.find(
307307
n => n.id === klass.namespaceId
308308
);
309309
if (!namespace) {
310310
return;
311311
}
312-
if (klass.tags.primaryKey) {
313-
if (typeof klass.tags.primaryKey !== "string") {
312+
function addKey(key: string, isPrimary = false) {
313+
const tag = isPrimary ? "@primaryKey" : "@unique";
314+
if (typeof key !== "string") {
315+
if (isPrimary) {
316+
throw new Error(
317+
`${tag} configuration of '${klass.namespaceName}.${klass.name}' is invalid; please specify just once "${tag} col1,col2"`
318+
);
319+
}
314320
throw new Error(
315-
`@primaryKey configuration of '${klass.namespaceName}.${klass.name}' is invalid; please specify just once "@primaryKey col1,col2"`
321+
`${tag} configuration of '${klass.namespaceName}.${
322+
klass.name
323+
}' is invalid; expected ${
324+
isPrimary ? "a string" : "a string or string array"
325+
} but found ${typeof key}`
316326
);
317327
}
318-
const { spec: pkSpec, tags, description } = parseConstraintSpec(
319-
klass.tags.primaryKey
320-
);
321-
const columns: string[] = parseSqlColumnArray(pkSpec);
322-
const attributes = attributesByNames(
323-
klass,
324-
columns,
325-
`@primaryKey ${klass.tags.primaryKey}`
326-
);
327-
attributes.forEach(attr => {
328-
attr.tags.notNull = true;
329-
});
328+
const { spec: keySpec, tags, description } = parseConstraintSpec(key);
329+
const columns: string[] = parseSqlColumnArray(keySpec);
330+
const attributes = attributesByNames(klass, columns, `${tag} ${key}`);
331+
if (isPrimary) {
332+
attributes.forEach(attr => {
333+
attr.tags.notNull = true;
334+
});
335+
}
330336
const keyAttributeNums = attributes.map(a => a.num);
331337
// Now we need to fake a constraint for this:
332338
const fakeConstraint = {
333339
kind: "constraint",
334340
isFake: true,
335341
isIndexed: true, // otherwise it gets ignored by ignoreIndexes
336342
id: Math.random(),
337-
name: `FAKE_${klass.namespaceName}_${klass.name}_primaryKey`,
338-
type: "p", // primary key
343+
name: `FAKE_${klass.namespaceName}_${klass.name}_${tag}`,
344+
type: isPrimary ? "p" : "u",
339345
classId: klass.id,
340346
foreignClassId: null,
341347
comment: null,
@@ -346,6 +352,16 @@ function smartCommentConstraints(introspectionResults) {
346352
};
347353
introspectionResults.constraint.push(fakeConstraint);
348354
}
355+
if (klass.tags.primaryKey) {
356+
addKey(klass.tags.primaryKey, true);
357+
}
358+
if (klass.tags.unique) {
359+
if (Array.isArray(klass.tags.unique)) {
360+
klass.tags.unique.forEach(key => addKey(key, true));
361+
} else {
362+
addKey(klass.tags.unique);
363+
}
364+
}
349365
});
350366
// Now primary keys are in place, we can apply foreign keys
351367
introspectionResults.class.forEach(klass => {

0 commit comments

Comments
 (0)