@zeno-lib/db 0.7.0-beta.0 → 0.7.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/config.d.mts CHANGED
@@ -15,6 +15,13 @@ import { Config, defineConfig } from "drizzle-kit";
15
15
  * Verified against Supabase CLI 2.84.1 / Postgres 17.
16
16
  */
17
17
  declare const supabaseManagedRoles: readonly ["pg_checkpoint", "pg_database_owner", "pg_execute_server_program", "pg_monitor", "pg_read_all_data", "pg_read_all_settings", "pg_read_all_stats", "pg_read_server_files", "pg_signal_backend", "pg_stat_scan_tables", "pg_write_all_data", "pg_write_server_files", "pgbouncer", "postgres", "supabase_functions_admin", "supabase_read_only_user", "supabase_realtime_admin", "supabase_replication_admin"];
18
- declare function defineDrizzleConfig(overrides?: Partial<Config>): ReturnType<typeof defineConfig>;
18
+ /**
19
+ * Drizzle Kit config for migrations the Supabase CLI applies.
20
+ * Moves each generated `<name>/migration.sql` to `<name>.sql` when `drizzle-kit generate` exits.
21
+ * Set `moveGeneratedSql: false` if `drizzle-kit migrate` applies them instead.
22
+ */
23
+ declare function defineDrizzleConfig(overrides?: Partial<Config> & {
24
+ moveGeneratedSql?: boolean;
25
+ }): ReturnType<typeof defineConfig>;
19
26
  //#endregion
20
27
  export { defineDrizzleConfig, supabaseManagedRoles };
package/dist/config.mjs CHANGED
@@ -77,8 +77,13 @@ const supabaseManagedRoles = [
77
77
  * never right. Add your own schemas here rather than dropping the filter.
78
78
  */
79
79
  const DEFAULT_SCHEMA_FILTER = ["public"];
80
+ /**
81
+ * Drizzle Kit config for migrations the Supabase CLI applies.
82
+ * Moves each generated `<name>/migration.sql` to `<name>.sql` when `drizzle-kit generate` exits.
83
+ * Set `moveGeneratedSql: false` if `drizzle-kit migrate` applies them instead.
84
+ */
80
85
  function defineDrizzleConfig(overrides = {}) {
81
- const { entities, ...configOverrides } = overrides;
86
+ const { entities, moveGeneratedSql = true, ...configOverrides } = overrides;
82
87
  const roleOverrides = typeof entities?.roles === "object" ? entities.roles : {};
83
88
  const config = defineConfig({
84
89
  dbCredentials: { url: process.env.SUPABASE_DATABASE_URL ?? "" },
@@ -96,7 +101,7 @@ function defineDrizzleConfig(overrides = {}) {
96
101
  schemaFilter: DEFAULT_SCHEMA_FILTER,
97
102
  ...configOverrides
98
103
  });
99
- if (config.out) moveGeneratedSqlAfterGenerate({ migrationsDir: config.out });
104
+ if (moveGeneratedSql && config.out) moveGeneratedSqlAfterGenerate({ migrationsDir: config.out });
100
105
  return config;
101
106
  }
102
107
  //#endregion
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zeno-lib/db",
3
- "version": "0.7.0-beta.0",
3
+ "version": "0.7.0",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
package/src/config.ts CHANGED
@@ -45,10 +45,15 @@ export const supabaseManagedRoles = [
45
45
  */
46
46
  const DEFAULT_SCHEMA_FILTER = ["public"]
47
47
 
48
+ /**
49
+ * Drizzle Kit config for migrations the Supabase CLI applies.
50
+ * Moves each generated `<name>/migration.sql` to `<name>.sql` when `drizzle-kit generate` exits.
51
+ * Set `moveGeneratedSql: false` if `drizzle-kit migrate` applies them instead.
52
+ */
48
53
  export function defineDrizzleConfig(
49
- overrides: Partial<Config> = {}
54
+ overrides: Partial<Config> & { moveGeneratedSql?: boolean } = {}
50
55
  ): ReturnType<typeof defineConfig> {
51
- const { entities, ...configOverrides } = overrides
56
+ const { entities, moveGeneratedSql = true, ...configOverrides } = overrides
52
57
  // `entities.roles` may be a boolean (`true`) in drizzle-kit config; in that
53
58
  // form there are no role options to preserve, so we only merge the object
54
59
  // form. The `provider: "supabase"` flag below is always enforced regardless.
@@ -76,7 +81,7 @@ export function defineDrizzleConfig(
76
81
  ...configOverrides,
77
82
  } as Config)
78
83
 
79
- if (config.out) {
84
+ if (moveGeneratedSql && config.out) {
80
85
  moveGeneratedSqlAfterGenerate({ migrationsDir: config.out })
81
86
  }
82
87
 
@@ -0,0 +1,98 @@
1
+ import {
2
+ mkdirSync,
3
+ mkdtempSync,
4
+ readdirSync,
5
+ readFileSync,
6
+ rmSync,
7
+ writeFileSync,
8
+ } from "node:fs"
9
+ import { tmpdir } from "node:os"
10
+ import { join } from "node:path"
11
+ import { afterEach, beforeEach, describe, expect, it } from "vitest"
12
+ import { moveGeneratedSql } from "./move-generated-sql.ts"
13
+
14
+ const POSTS = "20260102030405_posts"
15
+ const COMMENTS = "20260102030406_comments"
16
+
17
+ let migrationsDir: string
18
+
19
+ beforeEach(() => {
20
+ migrationsDir = mkdtempSync(join(tmpdir(), "zeno-db-migrations-"))
21
+ })
22
+
23
+ afterEach(() => {
24
+ rmSync(migrationsDir, { force: true, recursive: true })
25
+ })
26
+
27
+ // Write `<name>/migration.sql` and `<name>/snapshot.json`, as `drizzle-kit generate` does.
28
+ function generated(name: string): void {
29
+ mkdirSync(join(migrationsDir, name))
30
+ writeFileSync(join(migrationsDir, name, "migration.sql"), `-- ${name}`)
31
+ writeFileSync(join(migrationsDir, name, "snapshot.json"), "{}")
32
+ }
33
+
34
+ // The migrations folder, sorted.
35
+ const files = () => readdirSync(migrationsDir).sort()
36
+
37
+ const read = (name: string) => readFileSync(join(migrationsDir, name), "utf-8")
38
+
39
+ describe("moveGeneratedSql", () => {
40
+ it("moves migration.sql next to its folder", () => {
41
+ generated(POSTS)
42
+
43
+ moveGeneratedSql({ migrationsDir })
44
+
45
+ expect(files()).toEqual([POSTS, `${POSTS}.sql`])
46
+ expect(readdirSync(join(migrationsDir, POSTS))).toEqual(["snapshot.json"])
47
+ expect(read(`${POSTS}.sql`)).toBe(`-- ${POSTS}`)
48
+ })
49
+
50
+ it("returns the new paths in name order", () => {
51
+ generated(COMMENTS)
52
+ generated(POSTS)
53
+
54
+ expect(moveGeneratedSql({ migrationsDir })).toEqual({
55
+ moved: [
56
+ join(migrationsDir, `${POSTS}.sql`),
57
+ join(migrationsDir, `${COMMENTS}.sql`),
58
+ ],
59
+ })
60
+ })
61
+
62
+ it("moves nothing on a second run", () => {
63
+ generated(POSTS)
64
+ moveGeneratedSql({ migrationsDir })
65
+
66
+ expect(moveGeneratedSql({ migrationsDir })).toEqual({ moved: [] })
67
+ })
68
+
69
+ it("leaves a hand-written .sql file alone", () => {
70
+ generated(POSTS)
71
+ writeFileSync(join(migrationsDir, "20260102030407_grants.sql"), "grant;")
72
+
73
+ moveGeneratedSql({ migrationsDir })
74
+
75
+ expect(files()).toEqual([
76
+ POSTS,
77
+ `${POSTS}.sql`,
78
+ "20260102030407_grants.sql",
79
+ ])
80
+ expect(read("20260102030407_grants.sql")).toBe("grant;")
81
+ })
82
+
83
+ it("throws before moving anything when a .sql file is in the way", () => {
84
+ generated(POSTS)
85
+ generated(COMMENTS)
86
+ writeFileSync(join(migrationsDir, `${COMMENTS}.sql`), "-- edited by hand")
87
+
88
+ expect(() => moveGeneratedSql({ migrationsDir })).toThrow(`${COMMENTS}.sql`)
89
+ expect(files()).toEqual([POSTS, COMMENTS, `${COMMENTS}.sql`])
90
+ expect(read(`${COMMENTS}.sql`)).toBe("-- edited by hand")
91
+ })
92
+
93
+ it("returns nothing for a missing folder", () => {
94
+ expect(
95
+ moveGeneratedSql({ migrationsDir: join(migrationsDir, "missing") })
96
+ ).toEqual({ moved: [] })
97
+ })
98
+ })