@plutocms/supabase 0.0.1-alpha.10 → 0.0.1-alpha.11
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/bun.lock +3 -3
- package/modules/pluto-migrations.ts +71 -0
- package/package.json +2 -2
- package/public/schema.sql +25 -0
- package/server/api/setup/create.post.ts +34 -82
- package/server/plugins/migrations.ts +48 -0
- package/server/utils/migrations.ts +88 -0
- package/server/utils/sql.ts +81 -0
- package/shared/types/supabase.ts +78 -117
package/bun.lock
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"@antfu/eslint-config": "^6.2.0",
|
|
17
17
|
"@nuxt/eslint": "^1.15.1",
|
|
18
18
|
"@nuxt/ui": "^4.4.0",
|
|
19
|
-
"@types/bun": "^1.3.
|
|
19
|
+
"@types/bun": "^1.3.10",
|
|
20
20
|
"@vueuse/nuxt": "^14.2.1",
|
|
21
21
|
"eslint": "^9.39.1",
|
|
22
22
|
"nuxt": "^4.3.1",
|
|
@@ -678,7 +678,7 @@
|
|
|
678
678
|
|
|
679
679
|
"@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="],
|
|
680
680
|
|
|
681
|
-
"@types/bun": ["@types/bun@1.3.
|
|
681
|
+
"@types/bun": ["@types/bun@1.3.10", "", { "dependencies": { "bun-types": "1.3.10" } }, "sha512-0+rlrUrOrTSskibryHbvQkDOWRJwJZqZlxrUs1u4oOoTln8+WIXBPmAuCF35SWB2z4Zl3E84Nl/D0P7803nigQ=="],
|
|
682
682
|
|
|
683
683
|
"@types/debug": ["@types/debug@4.1.12", "", { "dependencies": { "@types/ms": "*" } }, "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ=="],
|
|
684
684
|
|
|
@@ -906,7 +906,7 @@
|
|
|
906
906
|
|
|
907
907
|
"builtin-modules": ["builtin-modules@5.0.0", "", {}, "sha512-bkXY9WsVpY7CvMhKSR6pZilZu9Ln5WDrKVBUXf2S443etkmEO4V58heTecXcUIsNsi4Rx8JUO4NfX1IcQl4deg=="],
|
|
908
908
|
|
|
909
|
-
"bun-types": ["bun-types@1.3.
|
|
909
|
+
"bun-types": ["bun-types@1.3.10", "", { "dependencies": { "@types/node": "*" } }, "sha512-tcpfCCl6XWo6nCVnpcVrxQ+9AYN1iqMIzgrSKYMB/fjLtV2eyAVEg7AxQJuCq/26R6HpKWykQXuSOq/21RYcbg=="],
|
|
910
910
|
|
|
911
911
|
"bundle-name": ["bundle-name@4.1.0", "", { "dependencies": { "run-applescript": "^7.0.0" } }, "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q=="],
|
|
912
912
|
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { existsSync, readdirSync, readFileSync } from 'node:fs'
|
|
2
|
+
import { join } from 'node:path'
|
|
3
|
+
import { defineNuxtModule, getLayerDirectories } from 'nuxt/kit'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Discovers schema.[layerName].sql files across all Nuxt layers,
|
|
7
|
+
* reads their content at build time, and populates runtimeConfig
|
|
8
|
+
* so the migrations plugin can run them at server startup.
|
|
9
|
+
*/
|
|
10
|
+
export default defineNuxtModule({
|
|
11
|
+
meta: {
|
|
12
|
+
name: 'pluto-migrations',
|
|
13
|
+
configKey: 'plutoMigrations',
|
|
14
|
+
},
|
|
15
|
+
|
|
16
|
+
setup(_options, nuxt) {
|
|
17
|
+
const layerDirs = getLayerDirectories()
|
|
18
|
+
const layerSchemas: Record<string, string> = {}
|
|
19
|
+
const schemaPattern = /^schema\.(.+)\.sql$/
|
|
20
|
+
|
|
21
|
+
for (const layer of layerDirs) {
|
|
22
|
+
// Each layer may have a public/ directory with schema files
|
|
23
|
+
const publicDir = join(layer.root, 'public')
|
|
24
|
+
|
|
25
|
+
if (!existsSync(publicDir)) {
|
|
26
|
+
continue
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
let files: string[] = []
|
|
30
|
+
try {
|
|
31
|
+
files = readdirSync(publicDir, 'utf-8')
|
|
32
|
+
} catch {
|
|
33
|
+
continue
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
for (const file of files) {
|
|
37
|
+
// Skip the core schema
|
|
38
|
+
if (file === 'schema.sql') {
|
|
39
|
+
continue
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const match = file.match(schemaPattern)
|
|
43
|
+
if (match?.[1]) {
|
|
44
|
+
const layerName = match[1]
|
|
45
|
+
// Read SQL content at build time
|
|
46
|
+
try {
|
|
47
|
+
layerSchemas[layerName] = readFileSync(
|
|
48
|
+
join(publicDir, file),
|
|
49
|
+
'utf-8'
|
|
50
|
+
)
|
|
51
|
+
} catch {
|
|
52
|
+
console.error(
|
|
53
|
+
`[pluto-migrations] Failed to read schema file: ${file}`
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const layerNames = Object.keys(layerSchemas)
|
|
61
|
+
|
|
62
|
+
// Populate runtimeConfig with layer names and their SQL content
|
|
63
|
+
nuxt.options.runtimeConfig.plutoLayerSchemas = layerSchemas
|
|
64
|
+
|
|
65
|
+
if (layerNames.length > 0) {
|
|
66
|
+
console.warn(
|
|
67
|
+
`[pluto-migrations] Discovered layer schemas: ${layerNames.join(', ')}`
|
|
68
|
+
)
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
})
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plutocms/supabase",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.1-alpha.
|
|
4
|
+
"version": "0.0.1-alpha.11",
|
|
5
5
|
"main": "./nuxt.config.ts",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"build": "nuxt build",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"@antfu/eslint-config": "^6.2.0",
|
|
27
27
|
"@nuxt/eslint": "^1.15.1",
|
|
28
28
|
"@nuxt/ui": "^4.4.0",
|
|
29
|
-
"@types/bun": "^1.3.
|
|
29
|
+
"@types/bun": "^1.3.10",
|
|
30
30
|
"@vueuse/nuxt": "^14.2.1",
|
|
31
31
|
"eslint": "^9.39.1",
|
|
32
32
|
"nuxt": "^4.3.1",
|
package/public/schema.sql
CHANGED
|
@@ -199,3 +199,28 @@ begin
|
|
|
199
199
|
end if;
|
|
200
200
|
end
|
|
201
201
|
$$;
|
|
202
|
+
|
|
203
|
+
-- Migrations tracking
|
|
204
|
+
create table if not exists public.pluto_migrations (
|
|
205
|
+
id bigint generated by default as identity primary key,
|
|
206
|
+
layer_name text not null,
|
|
207
|
+
applied_at timestamptz not null default now(),
|
|
208
|
+
constraint pluto_migrations_layer_key unique (layer_name)
|
|
209
|
+
);
|
|
210
|
+
|
|
211
|
+
alter table public.pluto_migrations enable row level security;
|
|
212
|
+
|
|
213
|
+
-- Only authenticated users can read migrations
|
|
214
|
+
do $$
|
|
215
|
+
begin
|
|
216
|
+
if not exists (
|
|
217
|
+
select 1 from pg_policies where tablename = 'pluto_migrations' and policyname = 'Enable read access for authenticated users on pluto_migrations'
|
|
218
|
+
) then
|
|
219
|
+
create policy "Enable read access for authenticated users on pluto_migrations"
|
|
220
|
+
on public.pluto_migrations
|
|
221
|
+
for select
|
|
222
|
+
to authenticated, dashboard_user
|
|
223
|
+
using (true);
|
|
224
|
+
end if;
|
|
225
|
+
end
|
|
226
|
+
$$;
|
|
@@ -1,92 +1,13 @@
|
|
|
1
|
+
import { readFile, writeFile } from 'node:fs/promises'
|
|
2
|
+
import { resolve } from 'node:path'
|
|
1
3
|
import postgres from 'postgres'
|
|
4
|
+
import { splitStatements } from '../../utils/sql'
|
|
2
5
|
|
|
3
6
|
interface Payload {
|
|
4
7
|
baseUrl: string
|
|
5
8
|
connectionString: string
|
|
6
9
|
}
|
|
7
10
|
|
|
8
|
-
/**
|
|
9
|
-
* Splits a SQL string into individual statements, correctly handling
|
|
10
|
-
* $$ dollar-quoted blocks, single-quoted strings, and -- comments.
|
|
11
|
-
*/
|
|
12
|
-
function splitStatements(sql: string): string[] {
|
|
13
|
-
const statements: string[] = []
|
|
14
|
-
let current = ''
|
|
15
|
-
let i = 0
|
|
16
|
-
|
|
17
|
-
while (i < sql.length) {
|
|
18
|
-
// Check for dollar-quoting ($$)
|
|
19
|
-
if (sql[i] === '$' && sql[i + 1] === '$') {
|
|
20
|
-
current += '$$'
|
|
21
|
-
i += 2
|
|
22
|
-
// Read until closing $$
|
|
23
|
-
while (i < sql.length) {
|
|
24
|
-
if (sql[i] === '$' && sql[i + 1] === '$') {
|
|
25
|
-
current += '$$'
|
|
26
|
-
i += 2
|
|
27
|
-
break
|
|
28
|
-
}
|
|
29
|
-
current += sql[i]
|
|
30
|
-
i++
|
|
31
|
-
}
|
|
32
|
-
continue
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// Check for single-quoted strings (handle '' escapes)
|
|
36
|
-
if (sql[i] === `'`) {
|
|
37
|
-
current += sql[i]
|
|
38
|
-
i++
|
|
39
|
-
while (i < sql.length) {
|
|
40
|
-
if (sql[i] === `'` && sql[i + 1] === `'`) {
|
|
41
|
-
// Escaped quote
|
|
42
|
-
current += `''`
|
|
43
|
-
i += 2
|
|
44
|
-
continue
|
|
45
|
-
}
|
|
46
|
-
if (sql[i] === `'`) {
|
|
47
|
-
current += sql[i]
|
|
48
|
-
i++
|
|
49
|
-
break
|
|
50
|
-
}
|
|
51
|
-
current += sql[i]
|
|
52
|
-
i++
|
|
53
|
-
}
|
|
54
|
-
continue
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Check for single-line comments
|
|
58
|
-
if (sql[i] === '-' && sql[i + 1] === '-') {
|
|
59
|
-
while (i < sql.length && sql[i] !== '\n') {
|
|
60
|
-
current += sql[i]
|
|
61
|
-
i++
|
|
62
|
-
}
|
|
63
|
-
continue
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// Statement terminator
|
|
67
|
-
if (sql[i] === ';') {
|
|
68
|
-
current += ';'
|
|
69
|
-
const trimmed = current.trim()
|
|
70
|
-
if (trimmed && trimmed !== ';') {
|
|
71
|
-
statements.push(trimmed)
|
|
72
|
-
}
|
|
73
|
-
current = ''
|
|
74
|
-
i++
|
|
75
|
-
continue
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
current += sql[i]
|
|
79
|
-
i++
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const trimmed = current.trim()
|
|
83
|
-
if (trimmed && trimmed !== ';') {
|
|
84
|
-
statements.push(trimmed)
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
return statements
|
|
88
|
-
}
|
|
89
|
-
|
|
90
11
|
export default defineEventHandler(async (event) => {
|
|
91
12
|
const body = await readBody<Payload>(event)
|
|
92
13
|
|
|
@@ -123,6 +44,37 @@ export default defineEventHandler(async (event) => {
|
|
|
123
44
|
`UPDATE public.healthcheck SET config_value = 'false' WHERE config_name = 'first_setup'`
|
|
124
45
|
)
|
|
125
46
|
|
|
47
|
+
// Record the core schema migration
|
|
48
|
+
await sql.unsafe(
|
|
49
|
+
`INSERT INTO public.pluto_migrations (layer_name)
|
|
50
|
+
VALUES ('core')
|
|
51
|
+
ON CONFLICT (layer_name) DO NOTHING`
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
// Persist connection string to .env for future layer migrations
|
|
55
|
+
const envPath = resolve(process.cwd(), '.env')
|
|
56
|
+
let envContent = ''
|
|
57
|
+
try {
|
|
58
|
+
envContent = await readFile(envPath, 'utf-8')
|
|
59
|
+
} catch {
|
|
60
|
+
// .env doesn't exist yet
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (envContent.includes('DATABASE_URL=')) {
|
|
64
|
+
envContent = envContent.replace(
|
|
65
|
+
/^DATABASE_URL=.*$/m,
|
|
66
|
+
`DATABASE_URL="${connectionString}"`
|
|
67
|
+
)
|
|
68
|
+
} else {
|
|
69
|
+
// Ensure there's a trailing newline before appending
|
|
70
|
+
if (envContent.length > 0 && !envContent.endsWith('\n')) {
|
|
71
|
+
envContent += '\n'
|
|
72
|
+
}
|
|
73
|
+
envContent += `DATABASE_URL="${connectionString}"\n`
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
await writeFile(envPath, envContent, 'utf-8')
|
|
77
|
+
|
|
126
78
|
return {
|
|
127
79
|
success: true,
|
|
128
80
|
message: 'Database setup completed successfully.',
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { runLayerMigration } from '../utils/migrations'
|
|
2
|
+
|
|
3
|
+
export default defineNitroPlugin(async () => {
|
|
4
|
+
// Only run if DATABASE_URL is configured (setup already completed)
|
|
5
|
+
if (!process.env.DATABASE_URL) {
|
|
6
|
+
return
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const config = useRuntimeConfig()
|
|
10
|
+
const layerSchemas: Record<string, string> =
|
|
11
|
+
(config as any).plutoLayerSchemas ?? {}
|
|
12
|
+
|
|
13
|
+
const layerNames = Object.keys(layerSchemas)
|
|
14
|
+
|
|
15
|
+
if (layerNames.length === 0) {
|
|
16
|
+
return
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
for (const layerName of layerNames) {
|
|
20
|
+
const schemaSql = layerSchemas[layerName]
|
|
21
|
+
|
|
22
|
+
if (!schemaSql) {
|
|
23
|
+
continue
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
const result = await runLayerMigration({
|
|
28
|
+
layerName,
|
|
29
|
+
schemaSql,
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
if (result.skipped) {
|
|
33
|
+
console.warn(
|
|
34
|
+
`[migrations] Layer "${layerName}" already applied, skipped.`
|
|
35
|
+
)
|
|
36
|
+
} else if (result.success) {
|
|
37
|
+
console.warn(`[migrations] Layer "${layerName}" migrated successfully.`)
|
|
38
|
+
} else {
|
|
39
|
+
console.error(`[migrations] Layer "${layerName}" failed:`, result.error)
|
|
40
|
+
}
|
|
41
|
+
} catch (error) {
|
|
42
|
+
console.error(
|
|
43
|
+
`[migrations] Error running migration for "${layerName}":`,
|
|
44
|
+
error
|
|
45
|
+
)
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
})
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import postgres from 'postgres'
|
|
2
|
+
import { splitStatements } from './sql'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Retrieves the database connection string from environment variables.
|
|
6
|
+
* Stored in .env during initial setup.
|
|
7
|
+
*/
|
|
8
|
+
export function getConnectionString(): string | null {
|
|
9
|
+
return process.env.DATABASE_URL ?? null
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Checks if a specific layer migration has already been applied.
|
|
14
|
+
*/
|
|
15
|
+
async function isMigrationApplied(
|
|
16
|
+
sql: postgres.Sql,
|
|
17
|
+
layerName: string
|
|
18
|
+
): Promise<boolean> {
|
|
19
|
+
const result = await sql.unsafe(
|
|
20
|
+
`SELECT 1 FROM public.pluto_migrations WHERE layer_name = $1`,
|
|
21
|
+
[layerName]
|
|
22
|
+
)
|
|
23
|
+
return result.length > 0
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Records a migration as applied.
|
|
28
|
+
*/
|
|
29
|
+
async function recordMigration(
|
|
30
|
+
sql: postgres.Sql,
|
|
31
|
+
layerName: string
|
|
32
|
+
): Promise<void> {
|
|
33
|
+
await sql.unsafe(
|
|
34
|
+
`INSERT INTO public.pluto_migrations (layer_name)
|
|
35
|
+
VALUES ($1)
|
|
36
|
+
ON CONFLICT (layer_name) DO NOTHING`,
|
|
37
|
+
[layerName]
|
|
38
|
+
)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
interface LayerMigrationResult {
|
|
42
|
+
success: boolean
|
|
43
|
+
skipped?: boolean
|
|
44
|
+
error?: string
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Runs a layer's schema SQL if not already applied.
|
|
49
|
+
* Splits and executes statements, then records the migration.
|
|
50
|
+
*/
|
|
51
|
+
export async function runLayerMigration(opts: {
|
|
52
|
+
layerName: string
|
|
53
|
+
schemaSql: string
|
|
54
|
+
connectionString?: string
|
|
55
|
+
}): Promise<LayerMigrationResult> {
|
|
56
|
+
const connStr = opts.connectionString ?? getConnectionString()
|
|
57
|
+
|
|
58
|
+
if (!connStr) {
|
|
59
|
+
return {
|
|
60
|
+
success: false,
|
|
61
|
+
error: 'No DATABASE_URL configured. Re-run setup or add it to .env.',
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const sql = postgres(connStr)
|
|
66
|
+
|
|
67
|
+
try {
|
|
68
|
+
const applied = await isMigrationApplied(sql, opts.layerName)
|
|
69
|
+
if (applied) {
|
|
70
|
+
return { success: true, skipped: true }
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const statements = splitStatements(opts.schemaSql)
|
|
74
|
+
|
|
75
|
+
for (const statement of statements) {
|
|
76
|
+
await sql.unsafe(statement)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
await recordMigration(sql, opts.layerName)
|
|
80
|
+
|
|
81
|
+
return { success: true }
|
|
82
|
+
} catch (error: any) {
|
|
83
|
+
console.error(`Migration error [${opts.layerName}]:`, error)
|
|
84
|
+
return { success: false, error: error.message }
|
|
85
|
+
} finally {
|
|
86
|
+
await sql.end()
|
|
87
|
+
}
|
|
88
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Splits a SQL string into individual statements, correctly handling
|
|
3
|
+
* $$ dollar-quoted blocks, single-quoted strings, and -- comments.
|
|
4
|
+
*/
|
|
5
|
+
export function splitStatements(sql: string): string[] {
|
|
6
|
+
const statements: string[] = []
|
|
7
|
+
let current = ''
|
|
8
|
+
let i = 0
|
|
9
|
+
|
|
10
|
+
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 $$
|
|
16
|
+
while (i < sql.length) {
|
|
17
|
+
if (sql[i] === '$' && sql[i + 1] === '$') {
|
|
18
|
+
current += '$$'
|
|
19
|
+
i += 2
|
|
20
|
+
break
|
|
21
|
+
}
|
|
22
|
+
current += sql[i]
|
|
23
|
+
i++
|
|
24
|
+
}
|
|
25
|
+
continue
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Check for single-quoted strings (handle '' escapes)
|
|
29
|
+
if (sql[i] === `'`) {
|
|
30
|
+
current += sql[i]
|
|
31
|
+
i++
|
|
32
|
+
while (i < sql.length) {
|
|
33
|
+
if (sql[i] === `'` && sql[i + 1] === `'`) {
|
|
34
|
+
// Escaped quote
|
|
35
|
+
current += `''`
|
|
36
|
+
i += 2
|
|
37
|
+
continue
|
|
38
|
+
}
|
|
39
|
+
if (sql[i] === `'`) {
|
|
40
|
+
current += sql[i]
|
|
41
|
+
i++
|
|
42
|
+
break
|
|
43
|
+
}
|
|
44
|
+
current += sql[i]
|
|
45
|
+
i++
|
|
46
|
+
}
|
|
47
|
+
continue
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Check for single-line comments
|
|
51
|
+
if (sql[i] === '-' && sql[i + 1] === '-') {
|
|
52
|
+
while (i < sql.length && sql[i] !== '\n') {
|
|
53
|
+
current += sql[i]
|
|
54
|
+
i++
|
|
55
|
+
}
|
|
56
|
+
continue
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Statement terminator
|
|
60
|
+
if (sql[i] === ';') {
|
|
61
|
+
current += ';'
|
|
62
|
+
const trimmed = current.trim()
|
|
63
|
+
if (trimmed && trimmed !== ';') {
|
|
64
|
+
statements.push(trimmed)
|
|
65
|
+
}
|
|
66
|
+
current = ''
|
|
67
|
+
i++
|
|
68
|
+
continue
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
current += sql[i]
|
|
72
|
+
i++
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const trimmed = current.trim()
|
|
76
|
+
if (trimmed && trimmed !== ';') {
|
|
77
|
+
statements.push(trimmed)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return statements
|
|
81
|
+
}
|
package/shared/types/supabase.ts
CHANGED
|
@@ -10,95 +10,113 @@ export type Database = {
|
|
|
10
10
|
// Allows to automatically instantiate createClient with right options
|
|
11
11
|
// instead of createClient<Database, { PostgrestVersion: 'XX' }>(URL, KEY)
|
|
12
12
|
__InternalSupabase: {
|
|
13
|
-
PostgrestVersion: "
|
|
13
|
+
PostgrestVersion: "14.1"
|
|
14
14
|
}
|
|
15
15
|
public: {
|
|
16
16
|
Tables: {
|
|
17
|
-
|
|
17
|
+
healthcheck: {
|
|
18
18
|
Row: {
|
|
19
|
-
|
|
19
|
+
config_name: Database["public"]["Enums"]["thealthcheck"]
|
|
20
|
+
config_value: string
|
|
20
21
|
id: number
|
|
21
|
-
label: string | null
|
|
22
|
-
slug: string | null
|
|
23
22
|
}
|
|
24
23
|
Insert: {
|
|
25
|
-
|
|
24
|
+
config_name: Database["public"]["Enums"]["thealthcheck"]
|
|
25
|
+
config_value: string
|
|
26
26
|
id?: number
|
|
27
|
-
label?: string | null
|
|
28
|
-
slug?: string | null
|
|
29
27
|
}
|
|
30
28
|
Update: {
|
|
31
|
-
|
|
29
|
+
config_name?: Database["public"]["Enums"]["thealthcheck"]
|
|
30
|
+
config_value?: string
|
|
32
31
|
id?: number
|
|
33
|
-
label?: string | null
|
|
34
|
-
slug?: string | null
|
|
35
32
|
}
|
|
36
33
|
Relationships: []
|
|
37
34
|
}
|
|
38
|
-
|
|
35
|
+
pluto_migrations: {
|
|
39
36
|
Row: {
|
|
40
|
-
|
|
37
|
+
applied_at: string
|
|
38
|
+
id: number
|
|
39
|
+
layer_name: string
|
|
40
|
+
}
|
|
41
|
+
Insert: {
|
|
42
|
+
applied_at?: string
|
|
43
|
+
id?: number
|
|
44
|
+
layer_name: string
|
|
45
|
+
}
|
|
46
|
+
Update: {
|
|
47
|
+
applied_at?: string
|
|
48
|
+
id?: number
|
|
49
|
+
layer_name?: string
|
|
50
|
+
}
|
|
51
|
+
Relationships: []
|
|
52
|
+
}
|
|
53
|
+
product_availability: {
|
|
54
|
+
Row: {
|
|
55
|
+
created_at: string
|
|
41
56
|
id: number
|
|
42
57
|
label: string
|
|
43
58
|
slug: string
|
|
44
59
|
}
|
|
45
60
|
Insert: {
|
|
46
|
-
|
|
47
|
-
id?:
|
|
61
|
+
created_at?: string
|
|
62
|
+
id?: never
|
|
48
63
|
label: string
|
|
49
64
|
slug: string
|
|
50
65
|
}
|
|
51
66
|
Update: {
|
|
52
|
-
|
|
53
|
-
id?:
|
|
67
|
+
created_at?: string
|
|
68
|
+
id?: never
|
|
54
69
|
label?: string
|
|
55
70
|
slug?: string
|
|
56
71
|
}
|
|
57
72
|
Relationships: []
|
|
58
73
|
}
|
|
59
|
-
|
|
74
|
+
product_categories: {
|
|
60
75
|
Row: {
|
|
61
|
-
|
|
62
|
-
config_value: string | null
|
|
76
|
+
description: string | null
|
|
63
77
|
id: number
|
|
78
|
+
label: string
|
|
79
|
+
slug: string
|
|
64
80
|
}
|
|
65
81
|
Insert: {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
82
|
+
description?: string | null
|
|
83
|
+
id?: never
|
|
84
|
+
label: string
|
|
85
|
+
slug: string
|
|
69
86
|
}
|
|
70
87
|
Update: {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
88
|
+
description?: string | null
|
|
89
|
+
id?: never
|
|
90
|
+
label?: string
|
|
91
|
+
slug?: string
|
|
74
92
|
}
|
|
75
93
|
Relationships: []
|
|
76
94
|
}
|
|
77
|
-
|
|
95
|
+
product_media: {
|
|
78
96
|
Row: {
|
|
79
97
|
alt: string | null
|
|
80
98
|
created_at: string
|
|
81
99
|
id: number
|
|
82
|
-
name: string
|
|
100
|
+
name: string
|
|
83
101
|
product_id: number | null
|
|
84
102
|
}
|
|
85
103
|
Insert: {
|
|
86
104
|
alt?: string | null
|
|
87
105
|
created_at?: string
|
|
88
|
-
id?:
|
|
89
|
-
name
|
|
106
|
+
id?: never
|
|
107
|
+
name: string
|
|
90
108
|
product_id?: number | null
|
|
91
109
|
}
|
|
92
110
|
Update: {
|
|
93
111
|
alt?: string | null
|
|
94
112
|
created_at?: string
|
|
95
|
-
id?:
|
|
96
|
-
name?: string
|
|
113
|
+
id?: never
|
|
114
|
+
name?: string
|
|
97
115
|
product_id?: number | null
|
|
98
116
|
}
|
|
99
117
|
Relationships: [
|
|
100
118
|
{
|
|
101
|
-
foreignKeyName: "
|
|
119
|
+
foreignKeyName: "product_media_product_id_fkey"
|
|
102
120
|
columns: ["product_id"]
|
|
103
121
|
isOneToOne: false
|
|
104
122
|
referencedRelation: "products"
|
|
@@ -106,56 +124,6 @@ export type Database = {
|
|
|
106
124
|
},
|
|
107
125
|
]
|
|
108
126
|
}
|
|
109
|
-
posts: {
|
|
110
|
-
Row: {
|
|
111
|
-
author_id: string
|
|
112
|
-
content: string | null
|
|
113
|
-
created_at: string
|
|
114
|
-
deleted_at: string | null
|
|
115
|
-
excerpt: string | null
|
|
116
|
-
id: number
|
|
117
|
-
is_draft: boolean | null
|
|
118
|
-
published_at: string | null
|
|
119
|
-
slug: string
|
|
120
|
-
title: string | null
|
|
121
|
-
updated_at: string | null
|
|
122
|
-
}
|
|
123
|
-
Insert: {
|
|
124
|
-
author_id: string
|
|
125
|
-
content?: string | null
|
|
126
|
-
created_at?: string
|
|
127
|
-
deleted_at?: string | null
|
|
128
|
-
excerpt?: string | null
|
|
129
|
-
id?: number
|
|
130
|
-
is_draft?: boolean | null
|
|
131
|
-
published_at?: string | null
|
|
132
|
-
slug: string
|
|
133
|
-
title?: string | null
|
|
134
|
-
updated_at?: string | null
|
|
135
|
-
}
|
|
136
|
-
Update: {
|
|
137
|
-
author_id?: string
|
|
138
|
-
content?: string | null
|
|
139
|
-
created_at?: string
|
|
140
|
-
deleted_at?: string | null
|
|
141
|
-
excerpt?: string | null
|
|
142
|
-
id?: number
|
|
143
|
-
is_draft?: boolean | null
|
|
144
|
-
published_at?: string | null
|
|
145
|
-
slug?: string
|
|
146
|
-
title?: string | null
|
|
147
|
-
updated_at?: string | null
|
|
148
|
-
}
|
|
149
|
-
Relationships: [
|
|
150
|
-
{
|
|
151
|
-
foreignKeyName: "posts_author_id_fkey"
|
|
152
|
-
columns: ["author_id"]
|
|
153
|
-
isOneToOne: true
|
|
154
|
-
referencedRelation: "profiles"
|
|
155
|
-
referencedColumns: ["id"]
|
|
156
|
-
},
|
|
157
|
-
]
|
|
158
|
-
}
|
|
159
127
|
products: {
|
|
160
128
|
Row: {
|
|
161
129
|
availability: number | null
|
|
@@ -172,9 +140,9 @@ export type Database = {
|
|
|
172
140
|
Insert: {
|
|
173
141
|
availability?: number | null
|
|
174
142
|
category?: number | null
|
|
175
|
-
created_at
|
|
143
|
+
created_at?: string
|
|
176
144
|
description?: string | null
|
|
177
|
-
id?:
|
|
145
|
+
id?: never
|
|
178
146
|
is_custom?: boolean
|
|
179
147
|
name: string
|
|
180
148
|
price: number
|
|
@@ -186,7 +154,7 @@ export type Database = {
|
|
|
186
154
|
category?: number | null
|
|
187
155
|
created_at?: string
|
|
188
156
|
description?: string | null
|
|
189
|
-
id?:
|
|
157
|
+
id?: never
|
|
190
158
|
is_custom?: boolean
|
|
191
159
|
name?: string
|
|
192
160
|
price?: number
|
|
@@ -198,53 +166,59 @@ export type Database = {
|
|
|
198
166
|
foreignKeyName: "products_availability_fkey"
|
|
199
167
|
columns: ["availability"]
|
|
200
168
|
isOneToOne: false
|
|
201
|
-
referencedRelation: "
|
|
169
|
+
referencedRelation: "product_availability"
|
|
202
170
|
referencedColumns: ["id"]
|
|
203
171
|
},
|
|
204
172
|
{
|
|
205
173
|
foreignKeyName: "products_category_fkey"
|
|
206
174
|
columns: ["category"]
|
|
207
175
|
isOneToOne: false
|
|
208
|
-
referencedRelation: "
|
|
176
|
+
referencedRelation: "product_categories"
|
|
209
177
|
referencedColumns: ["id"]
|
|
210
178
|
},
|
|
211
179
|
]
|
|
212
180
|
}
|
|
213
181
|
profiles: {
|
|
214
182
|
Row: {
|
|
215
|
-
|
|
183
|
+
display_name: string | null
|
|
184
|
+
email: string | null
|
|
216
185
|
id: string
|
|
217
|
-
is_admin: boolean
|
|
218
|
-
|
|
186
|
+
is_admin: boolean
|
|
187
|
+
updated_at: string | null
|
|
188
|
+
username: string | null
|
|
219
189
|
}
|
|
220
190
|
Insert: {
|
|
221
|
-
|
|
191
|
+
display_name?: string | null
|
|
192
|
+
email?: string | null
|
|
222
193
|
id: string
|
|
223
|
-
is_admin?: boolean
|
|
224
|
-
|
|
194
|
+
is_admin?: boolean
|
|
195
|
+
updated_at?: string | null
|
|
196
|
+
username?: string | null
|
|
225
197
|
}
|
|
226
198
|
Update: {
|
|
227
|
-
|
|
199
|
+
display_name?: string | null
|
|
200
|
+
email?: string | null
|
|
228
201
|
id?: string
|
|
229
|
-
is_admin?: boolean
|
|
230
|
-
|
|
202
|
+
is_admin?: boolean
|
|
203
|
+
updated_at?: string | null
|
|
204
|
+
username?: string | null
|
|
231
205
|
}
|
|
232
206
|
Relationships: []
|
|
233
207
|
}
|
|
234
208
|
settings: {
|
|
235
209
|
Row: {
|
|
236
210
|
id: number
|
|
237
|
-
setting_name: Database["public"]["Enums"]["
|
|
211
|
+
setting_name: Database["public"]["Enums"]["tsettings"]
|
|
238
212
|
setting_value: string
|
|
239
213
|
}
|
|
240
214
|
Insert: {
|
|
241
215
|
id?: number
|
|
242
|
-
setting_name: Database["public"]["Enums"]["
|
|
216
|
+
setting_name: Database["public"]["Enums"]["tsettings"]
|
|
243
217
|
setting_value: string
|
|
244
218
|
}
|
|
245
219
|
Update: {
|
|
246
220
|
id?: number
|
|
247
|
-
setting_name?: Database["public"]["Enums"]["
|
|
221
|
+
setting_name?: Database["public"]["Enums"]["tsettings"]
|
|
248
222
|
setting_value?: string
|
|
249
223
|
}
|
|
250
224
|
Relationships: []
|
|
@@ -257,14 +231,8 @@ export type Database = {
|
|
|
257
231
|
[_ in never]: never
|
|
258
232
|
}
|
|
259
233
|
Enums: {
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
Settings:
|
|
263
|
-
| "admin_email"
|
|
264
|
-
| "website_description"
|
|
265
|
-
| "website_title"
|
|
266
|
-
| "website_url"
|
|
267
|
-
| "users_can_register"
|
|
234
|
+
thealthcheck: "first_setup"
|
|
235
|
+
tsettings: "website_title" | "website_url" | "website_description"
|
|
268
236
|
}
|
|
269
237
|
CompositeTypes: {
|
|
270
238
|
[_ in never]: never
|
|
@@ -392,15 +360,8 @@ export type CompositeTypes<
|
|
|
392
360
|
export const Constants = {
|
|
393
361
|
public: {
|
|
394
362
|
Enums: {
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
Settings: [
|
|
398
|
-
"admin_email",
|
|
399
|
-
"website_description",
|
|
400
|
-
"website_title",
|
|
401
|
-
"website_url",
|
|
402
|
-
"users_can_register",
|
|
403
|
-
],
|
|
363
|
+
thealthcheck: ["first_setup"],
|
|
364
|
+
tsettings: ["website_title", "website_url", "website_description"],
|
|
404
365
|
},
|
|
405
366
|
},
|
|
406
367
|
} as const
|