@plutocms/supabase 0.3.0 → 0.4.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.
@@ -1,6 +1,35 @@
1
1
  /**
2
- * Splits a SQL string into individual statements, correctly handling
3
- * $$ dollar-quoted blocks, single-quoted strings, and -- comments.
2
+ * Matches a dollar-quote delimiter: bare (`$$`) or tagged (`$tag$`).
3
+ * The `y` (sticky) flag anchors the match to `lastIndex`, so it only
4
+ * matches when the delimiter starts at the exact position checked —
5
+ * it never matches later in the string.
6
+ */
7
+ const dollarTagPattern = /\$(?:[a-z_]\w*)?\$/iy
8
+
9
+ /**
10
+ * Returns the dollar-quote delimiter starting at `sql[i]`, or `null` when
11
+ * there is none. Used both for a bare `$$` and a named `$tag$` delimiter.
12
+ * Also correctly rejects a positional parameter like `$1`, since a tag
13
+ * name can't start with a digit.
14
+ */
15
+ function matchDollarTag(sql: string, i: number): string | null {
16
+ if (sql[i] !== '$') {
17
+ return null
18
+ }
19
+ dollarTagPattern.lastIndex = i
20
+ const match = dollarTagPattern.exec(sql)
21
+ return match ? match[0] : null
22
+ }
23
+
24
+ /**
25
+ * Splits a SQL string into individual statements.
26
+ *
27
+ * Recognizes the SQL syntax that can hide a statement-terminating `;`:
28
+ * - Dollar-quoted strings, both bare (`$$...$$`) and tagged (`$tag$...$tag$`).
29
+ * - Single-quoted string literals, with `''` as an escaped quote.
30
+ * - Double-quoted identifiers, with `""` as an escaped quote.
31
+ * - Line comments (`-- ...`).
32
+ * - Block comments (`/* ... *\/`), including nested block comments.
4
33
  */
5
34
  export function splitStatements(sql: string): string[] {
6
35
  const statements: string[] = []
@@ -8,15 +37,36 @@ export function splitStatements(sql: string): string[] {
8
37
  let i = 0
9
38
 
10
39
  while (i < sql.length) {
11
- // Check for dollar-quoting ($$)
12
- if (sql[i] === '$' && sql[i + 1] === '$') {
13
- current += '$$'
14
- i += 2
15
- // Read until closing $$
40
+ // Dollar-quoted strings: bare `$$` or a named `$tag$`.
41
+ const tag = matchDollarTag(sql, i)
42
+ if (tag) {
43
+ current += tag
44
+ i += tag.length
45
+ const end = sql.indexOf(tag, i)
46
+ if (end === -1) {
47
+ // Unterminated dollar quote — take the rest of the string as-is.
48
+ current += sql.slice(i)
49
+ i = sql.length
50
+ continue
51
+ }
52
+ current += sql.slice(i, end + tag.length)
53
+ i = end + tag.length
54
+ continue
55
+ }
56
+
57
+ // Double-quoted identifiers (handle "" escapes).
58
+ if (sql[i] === '"') {
59
+ current += sql[i]
60
+ i++
16
61
  while (i < sql.length) {
17
- if (sql[i] === '$' && sql[i + 1] === '$') {
18
- current += '$$'
62
+ if (sql[i] === '"' && sql[i + 1] === '"') {
63
+ current += '""'
19
64
  i += 2
65
+ continue
66
+ }
67
+ if (sql[i] === '"') {
68
+ current += sql[i]
69
+ i++
20
70
  break
21
71
  }
22
72
  current += sql[i]
@@ -25,7 +75,7 @@ export function splitStatements(sql: string): string[] {
25
75
  continue
26
76
  }
27
77
 
28
- // Check for single-quoted strings (handle '' escapes)
78
+ // Single-quoted strings (handle '' escapes).
29
79
  if (sql[i] === `'`) {
30
80
  current += sql[i]
31
81
  i++
@@ -47,7 +97,32 @@ export function splitStatements(sql: string): string[] {
47
97
  continue
48
98
  }
49
99
 
50
- // Check for single-line comments
100
+ // Block comments, including nested block comments (Postgres allows
101
+ // `/* outer /* inner */ still outer */`).
102
+ if (sql[i] === '/' && sql[i + 1] === '*') {
103
+ current += '/*'
104
+ i += 2
105
+ let depth = 1
106
+ while (i < sql.length && depth > 0) {
107
+ if (sql[i] === '/' && sql[i + 1] === '*') {
108
+ current += '/*'
109
+ i += 2
110
+ depth++
111
+ continue
112
+ }
113
+ if (sql[i] === '*' && sql[i + 1] === '/') {
114
+ current += '*/'
115
+ i += 2
116
+ depth--
117
+ continue
118
+ }
119
+ current += sql[i]
120
+ i++
121
+ }
122
+ continue
123
+ }
124
+
125
+ // Single-line comments
51
126
  if (sql[i] === '-' && sql[i + 1] === '-') {
52
127
  while (i < sql.length && sql[i] !== '\n') {
53
128
  current += sql[i]
@@ -0,0 +1,28 @@
1
+ /**
2
+ * A single discovered migration file for one layer.
3
+ *
4
+ * `modules/pluto-migrations.ts` discovers these at build time, either from
5
+ * a layer's `db/migrations/` directory, or as a single legacy
6
+ * `public/schema.sql` / `public/schema.<name>.sql` file. `server/utils/
7
+ * migrations.ts` applies them at runtime.
8
+ *
9
+ * Lives under `shared/` so both the Nuxt module (which runs under
10
+ * `nuxt/kit`, at build time, outside the app/server TS projects) and
11
+ * server code can import the same type.
12
+ */
13
+ export interface PlutoMigrationFile {
14
+ /** File name, for example `001_baseline.sql` or `002_admin_hardening.sql`. */
15
+ name: string
16
+ /** Raw SQL content of the file. */
17
+ sql: string
18
+ /** First 16 hex characters of the SHA-256 digest of `sql`. */
19
+ checksum: string
20
+ /**
21
+ * True when the file's first non-blank line matches
22
+ * `-- pluto:no-transaction`. Such a file runs statement-by-statement,
23
+ * with no surrounding transaction — use this only when a statement
24
+ * cannot run inside a transaction (for example `create index
25
+ * concurrently`).
26
+ */
27
+ noTransaction: boolean
28
+ }
@@ -1,15 +1,17 @@
1
+ import type { PlutoMigrationFile } from './migrations'
2
+
1
3
  // Nuxt infers runtimeConfig types from the actual merged value at build
2
- // time, which narrows `plutoLayerSchemas` to whatever layer keys happen
3
- // to be discovered in a given project (e.g. `{ "supabase-shop": string }`)
4
- // instead of the general `Record<string, string>` declared in
5
- // nuxt.config.ts. This augmentation pins the intended, stable shape.
6
- // Lives under shared/ so it's picked up by the app, server, and shared
7
- // TS projects alike (layer-root .d.ts files are only included by the
8
- // shared project).
4
+ // time, which narrows `plutoLayerMigrations` to whatever layer keys happen
5
+ // to be discovered in a given project (e.g. `{ "supabase-shop":
6
+ // PlutoMigrationFile[] }`) instead of the general `Record<string,
7
+ // PlutoMigrationFile[]>` declared in nuxt.config.ts. This augmentation
8
+ // pins the intended, stable shape. Lives under shared/ so it's picked up
9
+ // by the app, server, and shared TS projects alike (layer-root .d.ts
10
+ // files are only included by the shared project).
9
11
  declare module '@nuxt/schema' {
10
12
  interface RuntimeConfig {
11
13
  plutoRootDir: string
12
- plutoLayerSchemas: Record<string, string>
14
+ plutoLayerMigrations: Record<string, PlutoMigrationFile[]>
13
15
  }
14
16
  }
15
17
 
@@ -39,7 +39,6 @@ export type Database = {
39
39
  id: number
40
40
  mime_type: string | null
41
41
  name: string | null
42
- product_id: number | null
43
42
  size: number | null
44
43
  storage_path: string | null
45
44
  }
@@ -49,7 +48,6 @@ export type Database = {
49
48
  id?: number
50
49
  mime_type?: string | null
51
50
  name?: string | null
52
- product_id?: number | null
53
51
  size?: number | null
54
52
  storage_path?: string | null
55
53
  }
@@ -59,35 +57,32 @@ export type Database = {
59
57
  id?: number
60
58
  mime_type?: string | null
61
59
  name?: string | null
62
- product_id?: number | null
63
60
  size?: number | null
64
61
  storage_path?: string | null
65
62
  }
66
- Relationships: [
67
- {
68
- foreignKeyName: "media_product_id_fkey"
69
- columns: ["product_id"]
70
- isOneToOne: false
71
- referencedRelation: "products"
72
- referencedColumns: ["id"]
73
- },
74
- ]
63
+ Relationships: []
75
64
  }
76
65
  pluto_migrations: {
77
66
  Row: {
78
67
  applied_at: string
68
+ checksum: string | null
79
69
  id: number
80
70
  layer_name: string
71
+ migration_name: string
81
72
  }
82
73
  Insert: {
83
74
  applied_at?: string
75
+ checksum?: string | null
84
76
  id?: number
85
77
  layer_name: string
78
+ migration_name: string
86
79
  }
87
80
  Update: {
88
81
  applied_at?: string
82
+ checksum?: string | null
89
83
  id?: number
90
84
  layer_name?: string
85
+ migration_name?: string
91
86
  }
92
87
  Relationships: []
93
88
  }