@clivly/core 0.7.4 → 0.9.0

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/dist/drizzle.cjs CHANGED
@@ -1,7 +1,83 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  let drizzle_orm = require("drizzle-orm");
3
+ let drizzle_orm_pg_core = require("drizzle-orm/pg-core");
3
4
  //#region src/drizzle.ts
4
5
  /**
6
+ * Every unique key on a table, as DB column-name tuples. Primary keys count —
7
+ * fan-out detection asks "do these join columns cover a unique key?", and a PK
8
+ * answers that as well as any explicit unique constraint.
9
+ *
10
+ * Returns `undefined` if reflection fails (non-pg table, or a drizzle version
11
+ * without config access), meaning "unknown, cannot determine". Returns `[]`
12
+ * when reflection succeeds and the table genuinely has none. That distinction
13
+ * is load-bearing: `hasRichMeta` uses it to tell "metadata unavailable" from
14
+ * "confirmed no constraints", and projection validation fails closed on the
15
+ * former.
16
+ */
17
+ function buildUniqueConstraints(table) {
18
+ const keys = [];
19
+ try {
20
+ const config = (0, drizzle_orm_pg_core.getTableConfig)(table);
21
+ for (const column of config.columns ?? []) if (column.isUnique || column.primary) keys.push([column.name]);
22
+ for (const pk of config.primaryKeys ?? []) keys.push(pk.columns.map((c) => c.name));
23
+ for (const constraint of config.uniqueConstraints ?? []) keys.push(constraint.columns.map((c) => c.name));
24
+ for (const index of config.indexes ?? []) {
25
+ if (!index.config?.unique) continue;
26
+ const columns = (index.config.columns ?? []).map((c) => c?.name).filter((name) => Boolean(name));
27
+ if (columns.length > 0) keys.push(columns);
28
+ }
29
+ } catch {
30
+ return;
31
+ }
32
+ const seen = /* @__PURE__ */ new Set();
33
+ return keys.filter((key) => {
34
+ const id = [...key].sort().join("\0");
35
+ if (seen.has(id) || key.length === 0) return false;
36
+ seen.add(id);
37
+ return true;
38
+ });
39
+ }
40
+ /**
41
+ * Per-column metadata (type, PK, nullability, FK edges) for a Drizzle table.
42
+ * Structural only — no DB round-trip, so it is safe to recompute on every
43
+ * heartbeat. FK reflection is best-effort; a non-Postgres table still gets
44
+ * name/type/PK/nullable.
45
+ */
46
+ function buildColumnsMeta(table) {
47
+ const columns = (0, drizzle_orm.getTableColumns)(table);
48
+ const fkByColumn = /* @__PURE__ */ new Map();
49
+ try {
50
+ for (const fk of (0, drizzle_orm_pg_core.getTableConfig)(table).foreignKeys) {
51
+ const ref = fk.reference();
52
+ const foreignTable = (0, drizzle_orm.getTableName)(ref.foreignTable);
53
+ ref.columns.forEach((col, index) => {
54
+ const foreignCol = ref.foreignColumns[index];
55
+ if (foreignCol) fkByColumn.set(col.name, {
56
+ table: foreignTable,
57
+ column: foreignCol.name
58
+ });
59
+ });
60
+ }
61
+ } catch {}
62
+ return Object.values(columns).map((col) => {
63
+ const references = fkByColumn.get(col.name);
64
+ let type;
65
+ try {
66
+ type = col.getSQLType();
67
+ } catch {
68
+ type = void 0;
69
+ }
70
+ return {
71
+ name: col.name,
72
+ type,
73
+ nullable: !col.notNull,
74
+ isPrimaryKey: Boolean(col.primary),
75
+ isForeignKey: references !== void 0,
76
+ ...references ? { references } : {}
77
+ };
78
+ });
79
+ }
80
+ /**
5
81
  * Derive Clivly's discovery shape (table + column names) from a Drizzle schema
6
82
  * object — the `* as schema` you pass to `drizzle(client, { schema })`. This
7
83
  * delivers the "reads your schema" promise for Drizzle hosts: no hand-authored
@@ -21,12 +97,17 @@ function discoverFromDrizzle(schema) {
21
97
  for (const value of Object.values(schema)) {
22
98
  if (!(0, drizzle_orm.is)(value, drizzle_orm.Table)) continue;
23
99
  const columns = (0, drizzle_orm.getTableColumns)(value);
100
+ const uniqueConstraints = buildUniqueConstraints(value);
24
101
  tables.push({
25
102
  name: (0, drizzle_orm.getTableName)(value),
26
- columns: Object.values(columns).map((column) => column.name)
103
+ columns: Object.values(columns).map((column) => column.name),
104
+ columnsMeta: buildColumnsMeta(value),
105
+ ...uniqueConstraints === void 0 ? {} : { uniqueConstraints }
27
106
  });
28
107
  }
29
108
  return tables;
30
109
  }
31
110
  //#endregion
111
+ exports.buildColumnsMeta = buildColumnsMeta;
112
+ exports.buildUniqueConstraints = buildUniqueConstraints;
32
113
  exports.discoverFromDrizzle = discoverFromDrizzle;
@@ -1,5 +1,26 @@
1
- import { DiscoveredSchemaTable } from "./entity-config.cjs";
1
+ import { DiscoveredColumnMeta, DiscoveredSchemaTable } from "./entity-config.cjs";
2
+ import { Table } from "drizzle-orm";
2
3
  //#region src/drizzle.d.ts
4
+ /**
5
+ * Every unique key on a table, as DB column-name tuples. Primary keys count —
6
+ * fan-out detection asks "do these join columns cover a unique key?", and a PK
7
+ * answers that as well as any explicit unique constraint.
8
+ *
9
+ * Returns `undefined` if reflection fails (non-pg table, or a drizzle version
10
+ * without config access), meaning "unknown, cannot determine". Returns `[]`
11
+ * when reflection succeeds and the table genuinely has none. That distinction
12
+ * is load-bearing: `hasRichMeta` uses it to tell "metadata unavailable" from
13
+ * "confirmed no constraints", and projection validation fails closed on the
14
+ * former.
15
+ */
16
+ declare function buildUniqueConstraints(table: unknown): string[][] | undefined;
17
+ /**
18
+ * Per-column metadata (type, PK, nullability, FK edges) for a Drizzle table.
19
+ * Structural only — no DB round-trip, so it is safe to recompute on every
20
+ * heartbeat. FK reflection is best-effort; a non-Postgres table still gets
21
+ * name/type/PK/nullable.
22
+ */
23
+ declare function buildColumnsMeta(table: Table): DiscoveredColumnMeta[];
3
24
  /**
4
25
  * Derive Clivly's discovery shape (table + column names) from a Drizzle schema
5
26
  * object — the `* as schema` you pass to `drizzle(client, { schema })`. This
@@ -17,4 +38,4 @@ import { DiscoveredSchemaTable } from "./entity-config.cjs";
17
38
  */
18
39
  declare function discoverFromDrizzle(schema: Record<string, unknown>): DiscoveredSchemaTable[];
19
40
  //#endregion
20
- export { discoverFromDrizzle };
41
+ export { buildColumnsMeta, buildUniqueConstraints, discoverFromDrizzle };
@@ -1,5 +1,26 @@
1
- import { DiscoveredSchemaTable } from "./entity-config.mjs";
1
+ import { DiscoveredColumnMeta, DiscoveredSchemaTable } from "./entity-config.mjs";
2
+ import { Table } from "drizzle-orm";
2
3
  //#region src/drizzle.d.ts
4
+ /**
5
+ * Every unique key on a table, as DB column-name tuples. Primary keys count —
6
+ * fan-out detection asks "do these join columns cover a unique key?", and a PK
7
+ * answers that as well as any explicit unique constraint.
8
+ *
9
+ * Returns `undefined` if reflection fails (non-pg table, or a drizzle version
10
+ * without config access), meaning "unknown, cannot determine". Returns `[]`
11
+ * when reflection succeeds and the table genuinely has none. That distinction
12
+ * is load-bearing: `hasRichMeta` uses it to tell "metadata unavailable" from
13
+ * "confirmed no constraints", and projection validation fails closed on the
14
+ * former.
15
+ */
16
+ declare function buildUniqueConstraints(table: unknown): string[][] | undefined;
17
+ /**
18
+ * Per-column metadata (type, PK, nullability, FK edges) for a Drizzle table.
19
+ * Structural only — no DB round-trip, so it is safe to recompute on every
20
+ * heartbeat. FK reflection is best-effort; a non-Postgres table still gets
21
+ * name/type/PK/nullable.
22
+ */
23
+ declare function buildColumnsMeta(table: Table): DiscoveredColumnMeta[];
3
24
  /**
4
25
  * Derive Clivly's discovery shape (table + column names) from a Drizzle schema
5
26
  * object — the `* as schema` you pass to `drizzle(client, { schema })`. This
@@ -17,4 +38,4 @@ import { DiscoveredSchemaTable } from "./entity-config.mjs";
17
38
  */
18
39
  declare function discoverFromDrizzle(schema: Record<string, unknown>): DiscoveredSchemaTable[];
19
40
  //#endregion
20
- export { discoverFromDrizzle };
41
+ export { buildColumnsMeta, buildUniqueConstraints, discoverFromDrizzle };
package/dist/drizzle.mjs CHANGED
@@ -1,6 +1,82 @@
1
1
  import { Table, getTableColumns, getTableName, is } from "drizzle-orm";
2
+ import { getTableConfig } from "drizzle-orm/pg-core";
2
3
  //#region src/drizzle.ts
3
4
  /**
5
+ * Every unique key on a table, as DB column-name tuples. Primary keys count —
6
+ * fan-out detection asks "do these join columns cover a unique key?", and a PK
7
+ * answers that as well as any explicit unique constraint.
8
+ *
9
+ * Returns `undefined` if reflection fails (non-pg table, or a drizzle version
10
+ * without config access), meaning "unknown, cannot determine". Returns `[]`
11
+ * when reflection succeeds and the table genuinely has none. That distinction
12
+ * is load-bearing: `hasRichMeta` uses it to tell "metadata unavailable" from
13
+ * "confirmed no constraints", and projection validation fails closed on the
14
+ * former.
15
+ */
16
+ function buildUniqueConstraints(table) {
17
+ const keys = [];
18
+ try {
19
+ const config = getTableConfig(table);
20
+ for (const column of config.columns ?? []) if (column.isUnique || column.primary) keys.push([column.name]);
21
+ for (const pk of config.primaryKeys ?? []) keys.push(pk.columns.map((c) => c.name));
22
+ for (const constraint of config.uniqueConstraints ?? []) keys.push(constraint.columns.map((c) => c.name));
23
+ for (const index of config.indexes ?? []) {
24
+ if (!index.config?.unique) continue;
25
+ const columns = (index.config.columns ?? []).map((c) => c?.name).filter((name) => Boolean(name));
26
+ if (columns.length > 0) keys.push(columns);
27
+ }
28
+ } catch {
29
+ return;
30
+ }
31
+ const seen = /* @__PURE__ */ new Set();
32
+ return keys.filter((key) => {
33
+ const id = [...key].sort().join("\0");
34
+ if (seen.has(id) || key.length === 0) return false;
35
+ seen.add(id);
36
+ return true;
37
+ });
38
+ }
39
+ /**
40
+ * Per-column metadata (type, PK, nullability, FK edges) for a Drizzle table.
41
+ * Structural only — no DB round-trip, so it is safe to recompute on every
42
+ * heartbeat. FK reflection is best-effort; a non-Postgres table still gets
43
+ * name/type/PK/nullable.
44
+ */
45
+ function buildColumnsMeta(table) {
46
+ const columns = getTableColumns(table);
47
+ const fkByColumn = /* @__PURE__ */ new Map();
48
+ try {
49
+ for (const fk of getTableConfig(table).foreignKeys) {
50
+ const ref = fk.reference();
51
+ const foreignTable = getTableName(ref.foreignTable);
52
+ ref.columns.forEach((col, index) => {
53
+ const foreignCol = ref.foreignColumns[index];
54
+ if (foreignCol) fkByColumn.set(col.name, {
55
+ table: foreignTable,
56
+ column: foreignCol.name
57
+ });
58
+ });
59
+ }
60
+ } catch {}
61
+ return Object.values(columns).map((col) => {
62
+ const references = fkByColumn.get(col.name);
63
+ let type;
64
+ try {
65
+ type = col.getSQLType();
66
+ } catch {
67
+ type = void 0;
68
+ }
69
+ return {
70
+ name: col.name,
71
+ type,
72
+ nullable: !col.notNull,
73
+ isPrimaryKey: Boolean(col.primary),
74
+ isForeignKey: references !== void 0,
75
+ ...references ? { references } : {}
76
+ };
77
+ });
78
+ }
79
+ /**
4
80
  * Derive Clivly's discovery shape (table + column names) from a Drizzle schema
5
81
  * object — the `* as schema` you pass to `drizzle(client, { schema })`. This
6
82
  * delivers the "reads your schema" promise for Drizzle hosts: no hand-authored
@@ -20,12 +96,15 @@ function discoverFromDrizzle(schema) {
20
96
  for (const value of Object.values(schema)) {
21
97
  if (!is(value, Table)) continue;
22
98
  const columns = getTableColumns(value);
99
+ const uniqueConstraints = buildUniqueConstraints(value);
23
100
  tables.push({
24
101
  name: getTableName(value),
25
- columns: Object.values(columns).map((column) => column.name)
102
+ columns: Object.values(columns).map((column) => column.name),
103
+ columnsMeta: buildColumnsMeta(value),
104
+ ...uniqueConstraints === void 0 ? {} : { uniqueConstraints }
26
105
  });
27
106
  }
28
107
  return tables;
29
108
  }
30
109
  //#endregion
31
- export { discoverFromDrizzle };
110
+ export { buildColumnsMeta, buildUniqueConstraints, discoverFromDrizzle };