@casekit/orm-migrate 0.0.1-release-candidate

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.
Files changed (55) hide show
  1. package/build/drop.d.ts +2 -0
  2. package/build/drop.js +12 -0
  3. package/build/index.d.ts +7 -0
  4. package/build/index.js +8 -0
  5. package/build/pull/getColumns.d.ts +34 -0
  6. package/build/pull/getColumns.js +83 -0
  7. package/build/pull/getColumns.test.d.ts +1 -0
  8. package/build/pull/getColumns.test.js +320 -0
  9. package/build/pull/getForeignKeys.d.ts +18 -0
  10. package/build/pull/getForeignKeys.js +72 -0
  11. package/build/pull/getForeignKeys.test.d.ts +1 -0
  12. package/build/pull/getForeignKeys.test.js +86 -0
  13. package/build/pull/getPrimaryKeys.d.ts +14 -0
  14. package/build/pull/getPrimaryKeys.js +30 -0
  15. package/build/pull/getPrimaryKeys.test.d.ts +1 -0
  16. package/build/pull/getPrimaryKeys.test.js +87 -0
  17. package/build/pull/getUniqueConstraints.d.ts +14 -0
  18. package/build/pull/getUniqueConstraints.js +27 -0
  19. package/build/pull/getUniqueConstraints.test.d.ts +1 -0
  20. package/build/pull/getUniqueConstraints.test.js +99 -0
  21. package/build/pull/index.d.ts +4 -0
  22. package/build/pull/index.js +1 -0
  23. package/build/pull/pullDefault.d.ts +6 -0
  24. package/build/pull/pullDefault.js +44 -0
  25. package/build/pull/pullDefault.test.d.ts +1 -0
  26. package/build/pull/pullDefault.test.js +82 -0
  27. package/build/pull.d.ts +14 -0
  28. package/build/pull.js +56 -0
  29. package/build/push/arrayToSqlArray.d.ts +1 -0
  30. package/build/push/arrayToSqlArray.js +6 -0
  31. package/build/push/arrayToSqlArray.test.d.ts +1 -0
  32. package/build/push/arrayToSqlArray.test.js +29 -0
  33. package/build/push/createExtensionSql.d.ts +2 -0
  34. package/build/push/createExtensionSql.js +4 -0
  35. package/build/push/createExtensionSql.test.d.ts +1 -0
  36. package/build/push/createExtensionSql.test.js +20 -0
  37. package/build/push/createForeignKeyConstraintSql.d.ts +3 -0
  38. package/build/push/createForeignKeyConstraintSql.js +17 -0
  39. package/build/push/createForeignKeyConstraintSql.test.d.ts +1 -0
  40. package/build/push/createForeignKeyConstraintSql.test.js +142 -0
  41. package/build/push/createSchemaSql.d.ts +1 -0
  42. package/build/push/createSchemaSql.js +7 -0
  43. package/build/push/createSchemaSql.test.d.ts +1 -0
  44. package/build/push/createSchemaSql.test.js +26 -0
  45. package/build/push/createTableSql.d.ts +3 -0
  46. package/build/push/createTableSql.js +38 -0
  47. package/build/push/createTableSql.test.d.ts +1 -0
  48. package/build/push/createTableSql.test.js +110 -0
  49. package/build/push/createUniqueConstraintSql.d.ts +2 -0
  50. package/build/push/createUniqueConstraintSql.js +17 -0
  51. package/build/push/createUniqueConstraintSql.test.d.ts +1 -0
  52. package/build/push/createUniqueConstraintSql.test.js +105 -0
  53. package/build/push.d.ts +2 -0
  54. package/build/push.js +38 -0
  55. package/package.json +59 -0
@@ -0,0 +1,2 @@
1
+ import { Orm } from "@casekit/orm";
2
+ export declare const drop: (db: Orm) => Promise<void>;
package/build/drop.js ADDED
@@ -0,0 +1,12 @@
1
+ import { sql } from "@casekit/orm";
2
+ export const drop = async (db) => {
3
+ const schemas = new Set(Object.values(db.config.models).map((model) => model.schema));
4
+ await db.transact(async (db) => {
5
+ for (const schema of schemas.values()) {
6
+ console.log(` - Dropping schema ${schema}`);
7
+ await db.query `
8
+ DROP SCHEMA IF EXISTS ${sql.ident(schema)} CASCADE;
9
+ `;
10
+ }
11
+ });
12
+ };
@@ -0,0 +1,7 @@
1
+ export declare const migrate: {
2
+ drop: (db: import("@casekit/orm").Orm) => Promise<void>;
3
+ push: (db: import("@casekit/orm").Orm) => Promise<void>;
4
+ pull: (db: import("@casekit/orm").Orm, schemas: string[]) => Promise<import("#pull.js").Table[]>;
5
+ };
6
+ export type { Table } from "#pull.js";
7
+ export type { Column, ForeignKey, PrimaryKey, UniqueConstraint, } from "#pull/index.js";
package/build/index.js ADDED
@@ -0,0 +1,8 @@
1
+ import { drop } from "#drop.js";
2
+ import { pull } from "#pull.js";
3
+ import { push } from "#push.js";
4
+ export const migrate = {
5
+ drop,
6
+ push,
7
+ pull,
8
+ };
@@ -0,0 +1,34 @@
1
+ import { z } from "zod";
2
+ export declare const ColumnSchema: z.ZodObject<{
3
+ schema: z.ZodString;
4
+ table: z.ZodString;
5
+ column: z.ZodString;
6
+ ordinalPosition: z.ZodNullable<z.ZodNumber>;
7
+ type: z.ZodString;
8
+ default: z.ZodNullable<z.ZodString>;
9
+ nullable: z.ZodBoolean;
10
+ udtSchema: z.ZodString;
11
+ udt: z.ZodString;
12
+ elementType: z.ZodNullable<z.ZodString>;
13
+ elementTypeSchema: z.ZodNullable<z.ZodString>;
14
+ cardinality: z.ZodNumber;
15
+ size: z.ZodNullable<z.ZodNumber>;
16
+ isSerial: z.ZodBoolean;
17
+ }, z.core.$strip>;
18
+ export type Column = z.infer<typeof ColumnSchema>;
19
+ export declare const getColumns: (schemas: string[]) => import("@casekit/orm").SQLStatement<{
20
+ schema: string;
21
+ table: string;
22
+ column: string;
23
+ ordinalPosition: number | null;
24
+ type: string;
25
+ default: string | null;
26
+ nullable: boolean;
27
+ udtSchema: string;
28
+ udt: string;
29
+ elementType: string | null;
30
+ elementTypeSchema: string | null;
31
+ cardinality: number;
32
+ size: number | null;
33
+ isSerial: boolean;
34
+ }>;
@@ -0,0 +1,83 @@
1
+ import { z } from "zod";
2
+ import { sql } from "@casekit/orm";
3
+ export const ColumnSchema = z.object({
4
+ schema: z.string(),
5
+ table: z.string(),
6
+ column: z.string(),
7
+ ordinalPosition: z.number().nullable(),
8
+ type: z.string(),
9
+ default: z.string().nullable(),
10
+ nullable: z.boolean(),
11
+ udtSchema: z.string(),
12
+ udt: z.string(),
13
+ elementType: z.string().nullable(),
14
+ elementTypeSchema: z.string().nullable(),
15
+ cardinality: z.number(),
16
+ size: z.number().nullable(),
17
+ isSerial: z.boolean(),
18
+ });
19
+ export const getColumns = (schemas) => sql(ColumnSchema) `
20
+ SELECT
21
+ c.table_schema AS "schema",
22
+ c.table_name AS "table",
23
+ c.column_name AS "column",
24
+ c.ordinal_position AS "ordinalPosition",
25
+ CASE
26
+ WHEN c.udt_name = 'int2vector' THEN 'int2vector'
27
+ WHEN c.udt_name = 'oidvector' THEN 'oidvector'
28
+ WHEN c.data_type = 'ARRAY' AND c.udt_name LIKE '\_int2vector' THEN 'int2vector[]'
29
+ ELSE c.data_type
30
+ END AS "type",
31
+ c.column_default AS "default",
32
+ c.is_nullable = 'YES' AS "nullable",
33
+ c.udt_schema AS "udtSchema",
34
+ c.udt_name AS "udt",
35
+ e.data_type AS "elementType",
36
+ e.udt_schema AS "elementTypeSchema",
37
+ pa.attndims AS cardinality,
38
+ c.character_maximum_length AS "size",
39
+ COALESCE(seq_owned.is_serial, false) AS "isSerial"
40
+ FROM
41
+ information_schema.tables t
42
+ JOIN information_schema.columns c ON t.table_name = c.table_name
43
+ AND t.table_schema = c.table_schema
44
+ AND t.table_catalog = c.table_catalog
45
+ JOIN pg_catalog.pg_class pc ON pc.relname = c.table_name
46
+ JOIN pg_catalog.pg_namespace pn ON pn.oid = pc.relnamespace
47
+ AND pn.nspname = c.table_schema
48
+ JOIN pg_catalog.pg_attribute pa ON pa.attrelid = pc.oid
49
+ AND pa.attname = c.column_name
50
+ LEFT JOIN information_schema.element_types e ON c.table_catalog = e.object_catalog
51
+ AND c.table_schema = e.object_schema
52
+ AND c.table_name = e.object_name
53
+ AND e.object_type = 'TABLE'
54
+ AND e.collection_type_identifier = c.dtd_identifier
55
+ AND c.data_type = 'ARRAY'
56
+ LEFT JOIN (
57
+ SELECT
58
+ pn.nspname AS schema_name,
59
+ pc.relname AS table_name,
60
+ pa.attname AS column_name,
61
+ true AS is_serial
62
+ FROM
63
+ pg_depend pd
64
+ JOIN pg_class pc ON pd.refobjid = pc.oid AND pc.relkind = 'r'
65
+ JOIN pg_attribute pa ON pd.refobjid = pa.attrelid AND pd.refobjsubid = pa.attnum
66
+ JOIN pg_namespace pn ON pc.relnamespace = pn.oid
67
+ JOIN pg_class seq ON pd.objid = seq.oid AND seq.relkind = 'S'
68
+ WHERE
69
+ pd.deptype = 'a'
70
+ AND pd.classid = 'pg_class'::regclass
71
+ AND pd.refclassid = 'pg_class'::regclass
72
+ AND pn.nspname IN (${schemas})
73
+ ) seq_owned ON seq_owned.schema_name = c.table_schema
74
+ AND seq_owned.table_name = c.table_name
75
+ AND seq_owned.column_name = c.column_name
76
+ WHERE
77
+ t.table_schema IN (${schemas})
78
+ AND t.table_type = 'BASE TABLE'
79
+ AND pa.attnum > 0
80
+ ORDER BY
81
+ t.table_name,
82
+ c.ordinal_position
83
+ `;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,320 @@
1
+ import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, test, } from "vitest";
2
+ import { orm, sql } from "@casekit/orm";
3
+ import { getColumns } from "./getColumns.js";
4
+ describe("getColumns", () => {
5
+ const db = orm({
6
+ schema: "migrate-get-tables-test",
7
+ models: {},
8
+ });
9
+ beforeAll(async () => {
10
+ await db.connect();
11
+ });
12
+ afterAll(async () => {
13
+ await db.close();
14
+ });
15
+ beforeEach(async () => {
16
+ await db.query `DROP SCHEMA IF EXISTS "migrate-get-tables-test" CASCADE;`;
17
+ await db.query `CREATE SCHEMA IF NOT EXISTS "migrate-get-tables-test";`;
18
+ });
19
+ afterEach(async () => {
20
+ await db.query `DROP SCHEMA IF EXISTS "migrate-get-tables-test" CASCADE;`;
21
+ });
22
+ test("with an empty database it returns no tables or columns", async () => {
23
+ const statement = getColumns(["migrate-get-tables-test"]);
24
+ const result = await db.query(statement);
25
+ expect(result).toEqual([]);
26
+ });
27
+ test.for([
28
+ [
29
+ "handles uuid columns",
30
+ sql `
31
+ CREATE TABLE "migrate-get-tables-test"."uuid_test" (
32
+ "uuid_col" UUID DEFAULT gen_random_uuid(),
33
+ "uuid_col_notnull" UUID NOT NULL
34
+ );
35
+ `,
36
+ [
37
+ expect.objectContaining({
38
+ type: "uuid",
39
+ default: "gen_random_uuid()",
40
+ nullable: true,
41
+ }),
42
+ expect.objectContaining({
43
+ type: "uuid",
44
+ nullable: false,
45
+ }),
46
+ ],
47
+ ],
48
+ [
49
+ "handles serial columns",
50
+ sql `
51
+ CREATE TABLE "migrate-get-tables-test"."serial_test" (
52
+ "smallserial_col" SMALLSERIAL,
53
+ "serial_col" SERIAL,
54
+ "bigserial_col" BIGSERIAL
55
+ );
56
+ `,
57
+ [
58
+ expect.objectContaining({
59
+ type: "smallint",
60
+ default: expect.stringContaining("nextval"),
61
+ nullable: false,
62
+ isSerial: true,
63
+ }),
64
+ expect.objectContaining({
65
+ type: "integer",
66
+ default: expect.stringContaining("nextval"),
67
+ nullable: false,
68
+ isSerial: true,
69
+ }),
70
+ expect.objectContaining({
71
+ type: "bigint",
72
+ default: expect.stringContaining("nextval"),
73
+ nullable: false,
74
+ isSerial: true,
75
+ }),
76
+ ],
77
+ ],
78
+ [
79
+ "handles boolean columns",
80
+ sql `
81
+ CREATE TABLE "migrate-get-tables-test"."boolean_test" (
82
+ "bool_col" BOOLEAN DEFAULT true
83
+ );
84
+ `,
85
+ [
86
+ expect.objectContaining({
87
+ type: "boolean",
88
+ default: "true",
89
+ }),
90
+ ],
91
+ ],
92
+ [
93
+ "handles numeric columns",
94
+ sql `
95
+ CREATE TABLE "migrate-get-tables-test"."numeric_test" (
96
+ "numeric_col" NUMERIC(10,2)
97
+ );
98
+ `,
99
+ [
100
+ expect.objectContaining({
101
+ type: "numeric",
102
+ udt: "numeric",
103
+ }),
104
+ ],
105
+ ],
106
+ [
107
+ "handles various numeric and decimal types",
108
+ sql `
109
+ CREATE TABLE "migrate-get-tables-test"."number_test" (
110
+ "smallint_col" SMALLINT,
111
+ "integer_col" INTEGER,
112
+ "bigint_col" BIGINT,
113
+ "decimal_col" DECIMAL(10,2),
114
+ "real_col" REAL,
115
+ "double_col" DOUBLE PRECISION
116
+ );
117
+ `,
118
+ [
119
+ expect.objectContaining({ type: "smallint", udt: "int2" }),
120
+ expect.objectContaining({ type: "integer", udt: "int4" }),
121
+ expect.objectContaining({ type: "bigint", udt: "int8" }),
122
+ expect.objectContaining({ type: "numeric", udt: "numeric" }),
123
+ expect.objectContaining({ type: "real", udt: "float4" }),
124
+ expect.objectContaining({
125
+ type: "double precision",
126
+ udt: "float8",
127
+ }),
128
+ ],
129
+ ],
130
+ [
131
+ "handles character types",
132
+ sql `
133
+ CREATE TABLE "migrate-get-tables-test"."char_test" (
134
+ "char_col" CHAR(10),
135
+ "varchar_col" VARCHAR(50),
136
+ "text_col" TEXT,
137
+ "name_col" NAME
138
+ );
139
+ `,
140
+ [
141
+ expect.objectContaining({ type: "character", size: 10 }),
142
+ expect.objectContaining({
143
+ type: "character varying",
144
+ size: 50,
145
+ }),
146
+ expect.objectContaining({ type: "text" }),
147
+ expect.objectContaining({ type: "name" }),
148
+ ],
149
+ ],
150
+ [
151
+ "handles date and time types",
152
+ sql `
153
+ CREATE TABLE "migrate-get-tables-test"."datetime_test" (
154
+ "date_col" DATE,
155
+ "time_col" TIME,
156
+ "timetz_col" TIME WITH TIME ZONE,
157
+ "timestamp_col" TIMESTAMP,
158
+ "timestamptz_col" TIMESTAMP WITH TIME ZONE,
159
+ "interval_col" INTERVAL
160
+ );
161
+ `,
162
+ [
163
+ expect.objectContaining({ type: "date" }),
164
+ expect.objectContaining({ type: "time without time zone" }),
165
+ expect.objectContaining({ type: "time with time zone" }),
166
+ expect.objectContaining({
167
+ type: "timestamp without time zone",
168
+ }),
169
+ expect.objectContaining({ type: "timestamp with time zone" }),
170
+ expect.objectContaining({ type: "interval" }),
171
+ ],
172
+ ],
173
+ [
174
+ "handles array columns",
175
+ sql `
176
+ CREATE TABLE "migrate-get-tables-test"."array_test" (
177
+ "array_col" INTEGER[]
178
+ );
179
+ `,
180
+ [
181
+ expect.objectContaining({
182
+ type: "ARRAY",
183
+ elementType: "integer",
184
+ cardinality: 1,
185
+ }),
186
+ ],
187
+ ],
188
+ [
189
+ "handles multi-dimensional array columns",
190
+ sql `
191
+ CREATE TABLE "migrate-get-tables-test"."array_test" (
192
+ "multi_dim_array_col" TEXT[][][] NOT NULL DEFAULT ARRAY[ARRAY[ARRAY['a']]]
193
+ );
194
+ `,
195
+ [
196
+ expect.objectContaining({
197
+ type: "ARRAY",
198
+ elementType: "text",
199
+ cardinality: 3,
200
+ nullable: false,
201
+ default: "ARRAY[ARRAY[ARRAY['a'::text]]]",
202
+ }),
203
+ ],
204
+ ],
205
+ [
206
+ "handles json columns",
207
+ sql `
208
+ CREATE TABLE "migrate-get-tables-test"."json_test" (
209
+ "json_col" JSON
210
+ );
211
+ `,
212
+ [
213
+ expect.objectContaining({
214
+ type: "json",
215
+ }),
216
+ ],
217
+ ],
218
+ [
219
+ "handles enum columns",
220
+ sql `
221
+ CREATE TYPE "migrate-get-tables-test"."mood" AS ENUM ('happy', 'sad');
222
+ CREATE TABLE "migrate-get-tables-test"."enum_test" (
223
+ "enum_col" "migrate-get-tables-test"."mood"
224
+ );
225
+ `,
226
+ [
227
+ expect.objectContaining({
228
+ type: "USER-DEFINED",
229
+ udtSchema: "migrate-get-tables-test",
230
+ udt: "mood",
231
+ }),
232
+ ],
233
+ ],
234
+ [
235
+ "handles composite type columns",
236
+ sql `
237
+ CREATE TYPE "migrate-get-tables-test"."complex" AS (x double precision, y double precision);
238
+ CREATE TABLE "migrate-get-tables-test"."composite_test" (
239
+ "complex_col" "migrate-get-tables-test"."complex"
240
+ );
241
+ `,
242
+ [
243
+ expect.objectContaining({
244
+ type: "USER-DEFINED",
245
+ udtSchema: "migrate-get-tables-test",
246
+ udt: "complex",
247
+ }),
248
+ ],
249
+ ],
250
+ [
251
+ "handles currency columns",
252
+ sql `
253
+ CREATE TABLE "migrate-get-tables-test"."currency_test" (
254
+ "money_col" MONEY DEFAULT 42.42
255
+ );
256
+ `,
257
+ [
258
+ expect.objectContaining({
259
+ type: "money",
260
+ default: "42.42",
261
+ }),
262
+ ],
263
+ ],
264
+ [
265
+ "handles geometric columns",
266
+ sql `
267
+ CREATE TABLE "migrate-get-tables-test"."geometry_test" (
268
+ "point_col" POINT,
269
+ "line_col" LINE,
270
+ "polygon_col" POLYGON
271
+ );
272
+ `,
273
+ [
274
+ expect.objectContaining({ type: "point" }),
275
+ expect.objectContaining({ type: "line" }),
276
+ expect.objectContaining({ type: "polygon" }),
277
+ ],
278
+ ],
279
+ [
280
+ "handles network address columns",
281
+ sql `
282
+ CREATE TABLE "migrate-get-tables-test"."network_test" (
283
+ "inet_col" INET,
284
+ "cidr_col" CIDR,
285
+ "macaddr_col" MACADDR
286
+ );
287
+ `,
288
+ [
289
+ expect.objectContaining({ type: "inet" }),
290
+ expect.objectContaining({ type: "cidr" }),
291
+ expect.objectContaining({ type: "macaddr" }),
292
+ ],
293
+ ],
294
+ [
295
+ "handles sql now() default values correctly",
296
+ sql `
297
+ CREATE TABLE "migrate-get-tables-test"."timestamp_defaults_test" (
298
+ "created_at" TIMESTAMP DEFAULT now(),
299
+ "updated_at" TIMESTAMP WITH TIME ZONE DEFAULT now()
300
+ );
301
+ `,
302
+ [
303
+ expect.objectContaining({
304
+ type: "timestamp without time zone",
305
+ default: "now()",
306
+ }),
307
+ expect.objectContaining({
308
+ type: "timestamp with time zone",
309
+ default: "now()",
310
+ }),
311
+ ],
312
+ ],
313
+ ])("%s", async ([_, query, expected]) => {
314
+ await db.transact(async (db) => {
315
+ await db.query(query);
316
+ const result = await db.query(getColumns(["migrate-get-tables-test"]));
317
+ expect(result).toEqual(expected);
318
+ }, { rollback: true });
319
+ });
320
+ });
@@ -0,0 +1,18 @@
1
+ import { z } from "zod";
2
+ export declare const ForeignKeySchema: z.ZodObject<{
3
+ schema: z.ZodString;
4
+ constraintName: z.ZodString;
5
+ tableFrom: z.ZodString;
6
+ columnsFrom: z.ZodArray<z.ZodString>;
7
+ tableTo: z.ZodString;
8
+ columnsTo: z.ZodArray<z.ZodString>;
9
+ }, z.core.$strip>;
10
+ export type ForeignKey = z.infer<typeof ForeignKeySchema>;
11
+ export declare const getForeignKeys: (schemas: string[]) => import("@casekit/orm").SQLStatement<{
12
+ schema: string;
13
+ constraintName: string;
14
+ tableFrom: string;
15
+ columnsFrom: string[];
16
+ tableTo: string;
17
+ columnsTo: string[];
18
+ }>;
@@ -0,0 +1,72 @@
1
+ import { z } from "zod";
2
+ import { sql } from "@casekit/orm";
3
+ export const ForeignKeySchema = z.object({
4
+ schema: z.string(),
5
+ constraintName: z.string(),
6
+ tableFrom: z.string(),
7
+ columnsFrom: z.array(z.string()),
8
+ tableTo: z.string(),
9
+ columnsTo: z.array(z.string()),
10
+ });
11
+ export const getForeignKeys = (schemas) => sql(ForeignKeySchema) `
12
+ SELECT
13
+ nspname AS "schema",
14
+ conname AS "constraintName",
15
+ table_from AS "tableFrom",
16
+ array_agg(columns_from::text ORDER BY ordinality) AS "columnsFrom",
17
+ table_to AS "tableTo",
18
+ array_agg(columns_to::text ORDER BY ordinality) AS "columnsTo"
19
+ FROM (
20
+ SELECT
21
+ conname,
22
+ c.relname AS table_from,
23
+ a.attname AS columns_from,
24
+ cf.relname AS table_to,
25
+ af.attname AS columns_to,
26
+ n.nspname,
27
+ ss2.ordinality
28
+ FROM
29
+ pg_attribute AS af,
30
+ pg_attribute AS a,
31
+ pg_class c,
32
+ pg_class cf,
33
+ pg_namespace n,
34
+ (
35
+ SELECT
36
+ conname,
37
+ conrelid,
38
+ confrelid,
39
+ conkey[i] AS conkey,
40
+ confkey[i] AS confkey,
41
+ i AS ordinality
42
+ FROM (
43
+ SELECT
44
+ conname,
45
+ conrelid,
46
+ confrelid,
47
+ conkey,
48
+ confkey,
49
+ generate_series(1, array_upper(conkey, 1)) AS i
50
+ FROM
51
+ pg_constraint
52
+ WHERE
53
+ contype = 'f') AS ss) AS ss2
54
+ WHERE
55
+ af.attnum = confkey
56
+ AND af.attrelid = confrelid
57
+ AND a.attnum = conkey
58
+ AND a.attrelid = conrelid
59
+ AND a.attrelid = c.oid
60
+ AND af.attrelid = cf.oid
61
+ AND c.relnamespace = n.oid
62
+ AND n.nspname IN (${schemas})) AS ss3
63
+ GROUP BY
64
+ nspname,
65
+ conname,
66
+ table_to,
67
+ table_from
68
+ ORDER BY
69
+ nspname,
70
+ table_from,
71
+ conname
72
+ `;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,86 @@
1
+ import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, test, } from "vitest";
2
+ import { orm, sql } from "@casekit/orm";
3
+ import { getForeignKeys } from "./getForeignKeys.js";
4
+ describe("getForeignKeys", () => {
5
+ const db = orm({
6
+ schema: "migrate-get-foreign-keys-test",
7
+ models: {},
8
+ });
9
+ beforeAll(async () => {
10
+ await db.connect();
11
+ });
12
+ afterAll(async () => {
13
+ await db.close();
14
+ });
15
+ beforeEach(async () => {
16
+ await db.query `DROP SCHEMA IF EXISTS "migrate-get-foreign-keys-test" CASCADE;`;
17
+ await db.query `CREATE SCHEMA IF NOT EXISTS "migrate-get-foreign-keys-test";`;
18
+ });
19
+ afterEach(async () => {
20
+ await db.query `DROP SCHEMA IF EXISTS "migrate-get-foreign-keys-test" CASCADE;`;
21
+ });
22
+ test("with an empty database it returns no foreign keys", async () => {
23
+ const statement = getForeignKeys(["migrate-get-foreign-keys-test"]);
24
+ const result = await db.query(statement);
25
+ expect(result).toEqual([]);
26
+ });
27
+ test("returns foreign key relationships", async () => {
28
+ await db.transact(async (db) => {
29
+ await db.query(sql `
30
+ CREATE TABLE "migrate-get-foreign-keys-test"."users" (
31
+ "id" SERIAL PRIMARY KEY,
32
+ "name" TEXT NOT NULL
33
+ );
34
+ `);
35
+ await db.query(sql `
36
+ CREATE TABLE "migrate-get-foreign-keys-test"."posts" (
37
+ "id" SERIAL PRIMARY KEY,
38
+ "title" TEXT NOT NULL,
39
+ "user_id" INTEGER NOT NULL,
40
+ CONSTRAINT "fk_posts_user_id" FOREIGN KEY ("user_id") REFERENCES "migrate-get-foreign-keys-test"."users" ("id")
41
+ );
42
+ `);
43
+ const result = await db.query(getForeignKeys(["migrate-get-foreign-keys-test"]));
44
+ expect(result).toEqual([
45
+ expect.objectContaining({
46
+ schema: "migrate-get-foreign-keys-test",
47
+ constraintName: "fk_posts_user_id",
48
+ tableFrom: "posts",
49
+ columnsFrom: ["user_id"],
50
+ tableTo: "users",
51
+ columnsTo: ["id"],
52
+ }),
53
+ ]);
54
+ }, { rollback: true });
55
+ });
56
+ test("handles composite foreign keys", async () => {
57
+ await db.transact(async (db) => {
58
+ await db.query(sql `
59
+ CREATE TABLE "migrate-get-foreign-keys-test"."companies" (
60
+ "id" INTEGER NOT NULL,
61
+ "code" TEXT NOT NULL,
62
+ PRIMARY KEY ("id", "code")
63
+ );
64
+ `);
65
+ await db.query(sql `
66
+ CREATE TABLE "migrate-get-foreign-keys-test"."employees" (
67
+ "id" SERIAL PRIMARY KEY,
68
+ "company_id" INTEGER NOT NULL,
69
+ "company_code" TEXT NOT NULL,
70
+ CONSTRAINT "fk_employees_company" FOREIGN KEY ("company_id", "company_code") REFERENCES "migrate-get-foreign-keys-test"."companies" ("id", "code")
71
+ );
72
+ `);
73
+ const result = await db.query(getForeignKeys(["migrate-get-foreign-keys-test"]));
74
+ expect(result).toEqual([
75
+ expect.objectContaining({
76
+ schema: "migrate-get-foreign-keys-test",
77
+ constraintName: "fk_employees_company",
78
+ tableFrom: "employees",
79
+ columnsFrom: ["company_id", "company_code"],
80
+ tableTo: "companies",
81
+ columnsTo: ["id", "code"],
82
+ }),
83
+ ]);
84
+ }, { rollback: true });
85
+ });
86
+ });
@@ -0,0 +1,14 @@
1
+ import { z } from "zod";
2
+ export declare const PrimaryKeySchema: z.ZodObject<{
3
+ schema: z.ZodString;
4
+ table: z.ZodString;
5
+ constraintName: z.ZodString;
6
+ columns: z.ZodArray<z.ZodString>;
7
+ }, z.core.$strip>;
8
+ export type PrimaryKey = z.infer<typeof PrimaryKeySchema>;
9
+ export declare const getPrimaryKeys: (schemas: string[]) => import("@casekit/orm").SQLStatement<{
10
+ schema: string;
11
+ table: string;
12
+ constraintName: string;
13
+ columns: string[];
14
+ }>;