@astrojs/db 0.4.1 → 0.6.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/core/cli/commands/execute/index.d.ts +8 -0
- package/dist/core/cli/commands/execute/index.js +32 -0
- package/dist/core/cli/commands/link/index.d.ts +20 -8
- package/dist/core/cli/commands/link/index.js +191 -31
- package/dist/core/cli/commands/login/index.d.ts +4 -2
- package/dist/core/cli/commands/login/index.js +31 -22
- package/dist/core/cli/commands/logout/index.d.ts +1 -6
- package/dist/core/cli/commands/logout/index.js +1 -1
- package/dist/core/cli/commands/push/index.d.ts +4 -2
- package/dist/core/cli/commands/push/index.js +30 -170
- package/dist/core/cli/commands/shell/index.d.ts +4 -2
- package/dist/core/cli/commands/shell/index.js +3 -1
- package/dist/core/cli/commands/verify/index.d.ts +4 -2
- package/dist/core/cli/commands/verify/index.js +23 -37
- package/dist/core/cli/index.d.ts +1 -1
- package/dist/core/cli/index.js +26 -17
- package/dist/core/cli/migration-queries.d.ts +8 -13
- package/dist/core/cli/migration-queries.js +65 -121
- package/dist/core/consts.d.ts +2 -0
- package/dist/core/consts.js +4 -0
- package/dist/core/errors.d.ts +9 -7
- package/dist/core/errors.js +44 -43
- package/dist/core/integration/file-url.js +2 -5
- package/dist/core/integration/index.js +56 -112
- package/dist/core/integration/typegen.js +3 -13
- package/dist/core/integration/vite-plugin-db.d.ts +9 -5
- package/dist/core/integration/vite-plugin-db.js +66 -23
- package/dist/core/integration/vite-plugin-inject-env-ts.d.ts +1 -1
- package/dist/core/load-file.d.ts +31 -0
- package/dist/core/load-file.js +98 -0
- package/dist/core/tokens.js +1 -1
- package/dist/core/types.d.ts +1148 -5306
- package/dist/core/types.js +19 -85
- package/dist/core/utils.d.ts +1 -0
- package/dist/core/utils.js +4 -0
- package/dist/index.d.ts +2 -3
- package/dist/index.js +3 -5
- package/dist/runtime/config.d.ts +147 -0
- package/dist/runtime/config.js +42 -0
- package/dist/runtime/db-client.d.ts +2 -9
- package/dist/runtime/db-client.js +8 -39
- package/dist/runtime/index.d.ts +5 -4
- package/dist/runtime/index.js +12 -10
- package/dist/{core → runtime}/queries.d.ts +20 -17
- package/dist/{core → runtime}/queries.js +67 -91
- package/dist/runtime/types.d.ts +3 -3
- package/dist/utils.d.ts +1 -0
- package/dist/utils.js +4 -0
- package/index.d.ts +5 -3
- package/package.json +20 -5
- package/config-augment.d.ts +0 -4
- package/dist/core/cli/commands/gen/index.d.ts +0 -6
- package/dist/core/cli/commands/gen/index.js +0 -39
- package/dist/core/cli/migrations.d.ts +0 -34
- package/dist/core/cli/migrations.js +0 -129
- package/dist/core/integration/load-astro-config.d.ts +0 -6
- package/dist/core/integration/load-astro-config.js +0 -79
|
@@ -1,127 +1,103 @@
|
|
|
1
|
-
import {
|
|
2
|
-
} from "
|
|
3
|
-
import { bold } from "kleur/colors";
|
|
4
|
-
import { sql, getTableName } from "drizzle-orm";
|
|
1
|
+
import { LibsqlError } from "@libsql/client";
|
|
2
|
+
import { sql } from "drizzle-orm";
|
|
5
3
|
import { SQLiteAsyncDialect } from "drizzle-orm/sqlite-core";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
|
|
4
|
+
import { bold } from "kleur/colors";
|
|
5
|
+
import {
|
|
6
|
+
FOREIGN_KEY_DNE_ERROR,
|
|
7
|
+
FOREIGN_KEY_REFERENCES_EMPTY_ERROR,
|
|
8
|
+
FOREIGN_KEY_REFERENCES_LENGTH_ERROR,
|
|
9
|
+
REFERENCE_DNE_ERROR,
|
|
10
|
+
SEED_ERROR
|
|
11
|
+
} from "../core/errors.js";
|
|
12
|
+
import { hasPrimaryKey } from "./index.js";
|
|
13
|
+
import { isSerializedSQL } from "./types.js";
|
|
9
14
|
const sqlite = new SQLiteAsyncDialect();
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
tables
|
|
13
|
-
}) {
|
|
14
|
-
const setupQueries = [];
|
|
15
|
-
for (const [name, collection] of Object.entries(tables)) {
|
|
16
|
-
const dropQuery = sql.raw(`DROP TABLE IF EXISTS ${sqlite.escapeName(name)}`);
|
|
17
|
-
const createQuery = sql.raw(getCreateTableQuery(name, collection));
|
|
18
|
-
const indexQueries = getCreateIndexQueries(name, collection);
|
|
19
|
-
setupQueries.push(dropQuery, createQuery, ...indexQueries.map((s) => sql.raw(s)));
|
|
20
|
-
}
|
|
21
|
-
for (const q of setupQueries) {
|
|
22
|
-
await db.run(q);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
async function seedData({
|
|
15
|
+
const SEED_DEV_FILE_NAME = ["seed.ts", "seed.js", "seed.mjs", "seed.mts"];
|
|
16
|
+
async function seedLocal({
|
|
26
17
|
db,
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
18
|
+
tables,
|
|
19
|
+
// Glob all potential seed files to catch renames and deletions.
|
|
20
|
+
fileGlob
|
|
30
21
|
}) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
const msg = e instanceof Error ? e.message : String(e);
|
|
41
|
-
throw new Error(SEED_ERROR(getTableName(config.table), msg));
|
|
42
|
-
}
|
|
43
|
-
},
|
|
44
|
-
seedReturning: async (config, values) => {
|
|
45
|
-
seedErrorChecks(mode, config, values);
|
|
46
|
-
try {
|
|
47
|
-
let result = db.insert(config.table).values(values).returning();
|
|
48
|
-
if (!Array.isArray(values)) {
|
|
49
|
-
result = result.get();
|
|
50
|
-
}
|
|
51
|
-
return result;
|
|
52
|
-
} catch (e) {
|
|
53
|
-
const msg = e instanceof Error ? e.message : String(e);
|
|
54
|
-
throw new Error(SEED_ERROR(getTableName(config.table), msg));
|
|
55
|
-
}
|
|
56
|
-
},
|
|
57
|
-
db,
|
|
58
|
-
mode
|
|
22
|
+
await recreateTables({ db, tables });
|
|
23
|
+
for (const fileName of SEED_DEV_FILE_NAME) {
|
|
24
|
+
const key = Object.keys(fileGlob).find((f) => f.endsWith(fileName));
|
|
25
|
+
if (key) {
|
|
26
|
+
await fileGlob[key]().catch((e) => {
|
|
27
|
+
if (e instanceof LibsqlError) {
|
|
28
|
+
throw new Error(SEED_ERROR(e.message));
|
|
29
|
+
}
|
|
30
|
+
throw e;
|
|
59
31
|
});
|
|
32
|
+
return;
|
|
60
33
|
}
|
|
61
|
-
} catch (e) {
|
|
62
|
-
if (!(e instanceof Error))
|
|
63
|
-
throw e;
|
|
64
|
-
(logger ?? console).error(e.message);
|
|
65
34
|
}
|
|
66
35
|
}
|
|
67
|
-
function
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
36
|
+
async function recreateTables({ db, tables }) {
|
|
37
|
+
const setupQueries = [];
|
|
38
|
+
for (const [name, table] of Object.entries(tables)) {
|
|
39
|
+
const dropQuery = sql.raw(`DROP TABLE IF EXISTS ${sqlite.escapeName(name)}`);
|
|
40
|
+
const createQuery = sql.raw(getCreateTableQuery(name, table));
|
|
41
|
+
const indexQueries = getCreateIndexQueries(name, table);
|
|
42
|
+
setupQueries.push(dropQuery, createQuery, ...indexQueries.map((s) => sql.raw(s)));
|
|
74
43
|
}
|
|
44
|
+
await db.batch([
|
|
45
|
+
db.run(sql`pragma defer_foreign_keys=true;`),
|
|
46
|
+
...setupQueries.map((q) => db.run(q))
|
|
47
|
+
]);
|
|
75
48
|
}
|
|
76
|
-
function
|
|
77
|
-
|
|
49
|
+
function getDropTableIfExistsQuery(tableName) {
|
|
50
|
+
return `DROP TABLE IF EXISTS ${sqlite.escapeName(tableName)}`;
|
|
51
|
+
}
|
|
52
|
+
function getCreateTableQuery(tableName, table) {
|
|
53
|
+
let query = `CREATE TABLE ${sqlite.escapeName(tableName)} (`;
|
|
78
54
|
const colQueries = [];
|
|
79
|
-
const colHasPrimaryKey = Object.entries(
|
|
55
|
+
const colHasPrimaryKey = Object.entries(table.columns).find(
|
|
80
56
|
([, column]) => hasPrimaryKey(column)
|
|
81
57
|
);
|
|
82
58
|
if (!colHasPrimaryKey) {
|
|
83
59
|
colQueries.push("_id INTEGER PRIMARY KEY");
|
|
84
60
|
}
|
|
85
|
-
for (const [columnName, column] of Object.entries(
|
|
61
|
+
for (const [columnName, column] of Object.entries(table.columns)) {
|
|
86
62
|
const colQuery = `${sqlite.escapeName(columnName)} ${schemaTypeToSqlType(
|
|
87
63
|
column.type
|
|
88
64
|
)}${getModifiers(columnName, column)}`;
|
|
89
65
|
colQueries.push(colQuery);
|
|
90
66
|
}
|
|
91
|
-
colQueries.push(...getCreateForeignKeyQueries(
|
|
67
|
+
colQueries.push(...getCreateForeignKeyQueries(tableName, table));
|
|
92
68
|
query += colQueries.join(", ") + ")";
|
|
93
69
|
return query;
|
|
94
70
|
}
|
|
95
|
-
function getCreateIndexQueries(
|
|
71
|
+
function getCreateIndexQueries(tableName, table) {
|
|
96
72
|
let queries = [];
|
|
97
|
-
for (const [indexName, indexProps] of Object.entries(
|
|
73
|
+
for (const [indexName, indexProps] of Object.entries(table.indexes ?? {})) {
|
|
98
74
|
const onColNames = asArray(indexProps.on);
|
|
99
75
|
const onCols = onColNames.map((colName) => sqlite.escapeName(colName));
|
|
100
76
|
const unique = indexProps.unique ? "UNIQUE " : "";
|
|
101
77
|
const indexQuery = `CREATE ${unique}INDEX ${sqlite.escapeName(
|
|
102
78
|
indexName
|
|
103
|
-
)} ON ${sqlite.escapeName(
|
|
79
|
+
)} ON ${sqlite.escapeName(tableName)} (${onCols.join(", ")})`;
|
|
104
80
|
queries.push(indexQuery);
|
|
105
81
|
}
|
|
106
82
|
return queries;
|
|
107
83
|
}
|
|
108
|
-
function getCreateForeignKeyQueries(
|
|
84
|
+
function getCreateForeignKeyQueries(tableName, table) {
|
|
109
85
|
let queries = [];
|
|
110
|
-
for (const foreignKey of
|
|
86
|
+
for (const foreignKey of table.foreignKeys ?? []) {
|
|
111
87
|
const columns = asArray(foreignKey.columns);
|
|
112
88
|
const references = asArray(foreignKey.references);
|
|
113
89
|
if (columns.length !== references.length) {
|
|
114
|
-
throw new Error(
|
|
115
|
-
|
|
116
|
-
|
|
90
|
+
throw new Error(FOREIGN_KEY_REFERENCES_LENGTH_ERROR(tableName));
|
|
91
|
+
}
|
|
92
|
+
const firstReference = references[0];
|
|
93
|
+
if (!firstReference) {
|
|
94
|
+
throw new Error(FOREIGN_KEY_REFERENCES_EMPTY_ERROR(tableName));
|
|
117
95
|
}
|
|
118
|
-
const
|
|
119
|
-
if (!
|
|
120
|
-
throw new Error(
|
|
121
|
-
`Foreign key on ${collectionName} is misconfigured. \`references\` cannot be empty.`
|
|
122
|
-
);
|
|
96
|
+
const referencedTable = firstReference.schema.collection;
|
|
97
|
+
if (!referencedTable) {
|
|
98
|
+
throw new Error(FOREIGN_KEY_DNE_ERROR(tableName));
|
|
123
99
|
}
|
|
124
|
-
const query = `FOREIGN KEY (${columns.map((f) => sqlite.escapeName(f)).join(", ")}) REFERENCES ${sqlite.escapeName(
|
|
100
|
+
const query = `FOREIGN KEY (${columns.map((f) => sqlite.escapeName(f)).join(", ")}) REFERENCES ${sqlite.escapeName(referencedTable)}(${references.map((r) => sqlite.escapeName(r.schema.name)).join(", ")})`;
|
|
125
101
|
queries.push(query);
|
|
126
102
|
}
|
|
127
103
|
return queries;
|
|
@@ -156,13 +132,11 @@ function getModifiers(columnName, column) {
|
|
|
156
132
|
}
|
|
157
133
|
const references = getReferencesConfig(column);
|
|
158
134
|
if (references) {
|
|
159
|
-
const { collection, name } = references.schema;
|
|
160
|
-
if (!
|
|
161
|
-
throw new Error(
|
|
162
|
-
`Column ${collection}.${name} references a collection that does not exist. Did you apply the referenced collection to the \`tables\` object in your Astro config?`
|
|
163
|
-
);
|
|
135
|
+
const { collection: tableName, name } = references.schema;
|
|
136
|
+
if (!tableName || !name) {
|
|
137
|
+
throw new Error(REFERENCE_DNE_ERROR(columnName));
|
|
164
138
|
}
|
|
165
|
-
modifiers += ` REFERENCES ${sqlite.escapeName(
|
|
139
|
+
modifiers += ` REFERENCES ${sqlite.escapeName(tableName)} (${sqlite.escapeName(name)})`;
|
|
166
140
|
}
|
|
167
141
|
return modifiers;
|
|
168
142
|
}
|
|
@@ -218,13 +192,15 @@ function getDefaultValueSql(columnName, column) {
|
|
|
218
192
|
}
|
|
219
193
|
}
|
|
220
194
|
export {
|
|
195
|
+
SEED_DEV_FILE_NAME,
|
|
221
196
|
getCreateForeignKeyQueries,
|
|
222
197
|
getCreateIndexQueries,
|
|
223
198
|
getCreateTableQuery,
|
|
199
|
+
getDropTableIfExistsQuery,
|
|
224
200
|
getModifiers,
|
|
225
201
|
getReferencesConfig,
|
|
226
202
|
hasDefault,
|
|
227
203
|
recreateTables,
|
|
228
204
|
schemaTypeToSqlType,
|
|
229
|
-
|
|
205
|
+
seedLocal
|
|
230
206
|
};
|
package/dist/runtime/types.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ColumnBaseConfig, ColumnDataType } from 'drizzle-orm';
|
|
2
2
|
import type { SQLiteColumn, SQLiteTableWithColumns } from 'drizzle-orm/sqlite-core';
|
|
3
|
-
import type { DBColumn,
|
|
3
|
+
import type { ColumnsConfig, DBColumn, OutputColumnsConfig } from '../core/types.js';
|
|
4
4
|
type GeneratedConfig<T extends ColumnDataType = ColumnDataType> = Pick<ColumnBaseConfig<T, string>, 'name' | 'tableName' | 'notNull' | 'hasDefault'>;
|
|
5
5
|
export type AstroText<T extends GeneratedConfig<'string'>> = SQLiteColumn<T & {
|
|
6
6
|
data: string;
|
|
@@ -43,7 +43,7 @@ export type AstroJson<T extends GeneratedConfig<'custom'>> = SQLiteColumn<T & {
|
|
|
43
43
|
baseColumn: never;
|
|
44
44
|
}>;
|
|
45
45
|
export type Column<T extends DBColumn['type'], S extends GeneratedConfig> = T extends 'boolean' ? AstroBoolean<S> : T extends 'number' ? AstroNumber<S> : T extends 'text' ? AstroText<S> : T extends 'date' ? AstroDate<S> : T extends 'json' ? AstroJson<S> : never;
|
|
46
|
-
export type Table<TTableName extends string, TColumns extends ColumnsConfig> = SQLiteTableWithColumns<{
|
|
46
|
+
export type Table<TTableName extends string, TColumns extends OutputColumnsConfig | ColumnsConfig> = SQLiteTableWithColumns<{
|
|
47
47
|
name: TTableName;
|
|
48
48
|
schema: undefined;
|
|
49
49
|
dialect: 'sqlite';
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { asDrizzleTable } from './runtime/index.js';
|
package/dist/utils.js
ADDED
package/index.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
export { default, cli } from './dist/index.js';
|
|
2
|
+
|
|
3
|
+
declare module 'astro:db' {
|
|
4
|
+
export { defineTable, defineDB, column, sql, NOW, TRUE, FALSE } from './dist/index.js';
|
|
5
|
+
}
|
package/package.json
CHANGED
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astrojs/db",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
|
-
"types": "./index.d.ts",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
8
|
"author": "withastro",
|
|
9
9
|
"main": "./dist/index.js",
|
|
10
10
|
"exports": {
|
|
11
11
|
".": {
|
|
12
|
-
"types": "./index.d.ts",
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
13
|
"import": "./dist/index.js"
|
|
14
14
|
},
|
|
15
|
+
"./utils": {
|
|
16
|
+
"types": "./dist/utils.d.ts",
|
|
17
|
+
"import": "./dist/utils.js"
|
|
18
|
+
},
|
|
15
19
|
"./runtime": {
|
|
16
20
|
"types": "./dist/runtime/index.d.ts",
|
|
17
21
|
"import": "./dist/runtime/index.js"
|
|
@@ -20,6 +24,10 @@
|
|
|
20
24
|
"types": "./dist/runtime/drizzle.d.ts",
|
|
21
25
|
"import": "./dist/runtime/drizzle.js"
|
|
22
26
|
},
|
|
27
|
+
"./runtime/config": {
|
|
28
|
+
"types": "./dist/runtime/config.d.ts",
|
|
29
|
+
"import": "./dist/runtime/config.js"
|
|
30
|
+
},
|
|
23
31
|
"./package.json": "./package.json"
|
|
24
32
|
},
|
|
25
33
|
"typesVersions": {
|
|
@@ -27,11 +35,17 @@
|
|
|
27
35
|
".": [
|
|
28
36
|
"./index.d.ts"
|
|
29
37
|
],
|
|
38
|
+
"utils": [
|
|
39
|
+
"./dist/utils.d.ts"
|
|
40
|
+
],
|
|
30
41
|
"runtime": [
|
|
31
42
|
"./dist/runtime/index.d.ts"
|
|
32
43
|
],
|
|
33
44
|
"runtime/drizzle": [
|
|
34
45
|
"./dist/runtime/drizzle.d.ts"
|
|
46
|
+
],
|
|
47
|
+
"runtime/config": [
|
|
48
|
+
"./dist/runtime/config.d.ts"
|
|
35
49
|
]
|
|
36
50
|
}
|
|
37
51
|
},
|
|
@@ -46,6 +60,7 @@
|
|
|
46
60
|
],
|
|
47
61
|
"dependencies": {
|
|
48
62
|
"@libsql/client": "^0.4.3",
|
|
63
|
+
"async-listen": "^3.0.1",
|
|
49
64
|
"deep-diff": "^1.0.2",
|
|
50
65
|
"drizzle-orm": "^0.28.6",
|
|
51
66
|
"kleur": "^4.1.5",
|
|
@@ -67,8 +82,8 @@
|
|
|
67
82
|
"cheerio": "1.0.0-rc.12",
|
|
68
83
|
"mocha": "^10.2.0",
|
|
69
84
|
"typescript": "^5.2.2",
|
|
70
|
-
"vite": "^
|
|
71
|
-
"astro": "4.4.
|
|
85
|
+
"vite": "^5.1.4",
|
|
86
|
+
"astro": "4.4.10",
|
|
72
87
|
"astro-scripts": "0.0.14"
|
|
73
88
|
},
|
|
74
89
|
"scripts": {
|
package/config-augment.d.ts
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { writeFile } from "node:fs/promises";
|
|
2
|
-
import {
|
|
3
|
-
MIGRATIONS_CREATED,
|
|
4
|
-
MIGRATIONS_UP_TO_DATE,
|
|
5
|
-
getMigrationStatus,
|
|
6
|
-
initializeMigrationsDirectory
|
|
7
|
-
} from "../../migrations.js";
|
|
8
|
-
import { getMigrationQueries } from "../../migration-queries.js";
|
|
9
|
-
import { bgRed, red, reset } from "kleur/colors";
|
|
10
|
-
async function cmd({ config }) {
|
|
11
|
-
const migration = await getMigrationStatus(config);
|
|
12
|
-
if (migration.state === "no-migrations-found") {
|
|
13
|
-
await initializeMigrationsDirectory(migration.currentSnapshot);
|
|
14
|
-
console.log(MIGRATIONS_CREATED);
|
|
15
|
-
return;
|
|
16
|
-
} else if (migration.state === "up-to-date") {
|
|
17
|
-
console.log(MIGRATIONS_UP_TO_DATE);
|
|
18
|
-
return;
|
|
19
|
-
}
|
|
20
|
-
const { oldSnapshot, newSnapshot, newFilename, diff } = migration;
|
|
21
|
-
const { queries: migrationQueries, confirmations } = await getMigrationQueries({
|
|
22
|
-
oldSnapshot,
|
|
23
|
-
newSnapshot
|
|
24
|
-
});
|
|
25
|
-
confirmations.map((message) => console.log(bgRed(" !!! ") + " " + red(message)));
|
|
26
|
-
const migrationFileContent = {
|
|
27
|
-
diff,
|
|
28
|
-
db: migrationQueries,
|
|
29
|
-
// TODO(fks): Encode the relevant data, instead of the raw message.
|
|
30
|
-
// This will give `db push` more control over the formatting of the message.
|
|
31
|
-
confirm: confirmations.map((c) => reset(c))
|
|
32
|
-
};
|
|
33
|
-
const migrationFileName = `./migrations/${newFilename}`;
|
|
34
|
-
await writeFile(migrationFileName, JSON.stringify(migrationFileContent, void 0, 2));
|
|
35
|
-
console.log(migrationFileName + " created!");
|
|
36
|
-
}
|
|
37
|
-
export {
|
|
38
|
-
cmd
|
|
39
|
-
};
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import deepDiff from 'deep-diff';
|
|
2
|
-
import { type DBSnapshot } from '../types.js';
|
|
3
|
-
import type { AstroConfig } from 'astro';
|
|
4
|
-
export type MigrationStatus = {
|
|
5
|
-
state: 'no-migrations-found';
|
|
6
|
-
currentSnapshot: DBSnapshot;
|
|
7
|
-
} | {
|
|
8
|
-
state: 'ahead';
|
|
9
|
-
oldSnapshot: DBSnapshot;
|
|
10
|
-
newSnapshot: DBSnapshot;
|
|
11
|
-
diff: deepDiff.Diff<DBSnapshot, DBSnapshot>[];
|
|
12
|
-
newFilename: string;
|
|
13
|
-
summary: string;
|
|
14
|
-
newFileContent?: string;
|
|
15
|
-
} | {
|
|
16
|
-
state: 'up-to-date';
|
|
17
|
-
currentSnapshot: DBSnapshot;
|
|
18
|
-
};
|
|
19
|
-
export declare function getMigrationStatus(config: AstroConfig): Promise<MigrationStatus>;
|
|
20
|
-
export declare const MIGRATIONS_CREATED: string;
|
|
21
|
-
export declare const MIGRATIONS_UP_TO_DATE: string;
|
|
22
|
-
export declare const MIGRATIONS_NOT_INITIALIZED: string;
|
|
23
|
-
export declare const MIGRATION_NEEDED: string;
|
|
24
|
-
export declare function getMigrations(): Promise<string[]>;
|
|
25
|
-
export declare function loadMigration(migration: string): Promise<{
|
|
26
|
-
diff: any[];
|
|
27
|
-
db: string[];
|
|
28
|
-
confirm?: string[];
|
|
29
|
-
}>;
|
|
30
|
-
export declare function loadInitialSnapshot(): Promise<DBSnapshot>;
|
|
31
|
-
export declare function initializeMigrationsDirectory(currentSnapshot: DBSnapshot): Promise<void>;
|
|
32
|
-
export declare function initializeFromMigrations(allMigrationFiles: string[]): Promise<DBSnapshot>;
|
|
33
|
-
export declare function createCurrentSnapshot(config: AstroConfig): DBSnapshot;
|
|
34
|
-
export declare function createEmptySnapshot(): DBSnapshot;
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
import deepDiff from "deep-diff";
|
|
2
|
-
import { mkdir, readFile, readdir, writeFile } from "fs/promises";
|
|
3
|
-
import { tablesSchema } from "../types.js";
|
|
4
|
-
import { cyan, green, yellow } from "kleur/colors";
|
|
5
|
-
const { applyChange, diff: generateDiff } = deepDiff;
|
|
6
|
-
async function getMigrationStatus(config) {
|
|
7
|
-
const currentSnapshot = createCurrentSnapshot(config);
|
|
8
|
-
const allMigrationFiles = await getMigrations();
|
|
9
|
-
if (allMigrationFiles.length === 0) {
|
|
10
|
-
return {
|
|
11
|
-
state: "no-migrations-found",
|
|
12
|
-
currentSnapshot
|
|
13
|
-
};
|
|
14
|
-
}
|
|
15
|
-
const previousSnapshot = await initializeFromMigrations(allMigrationFiles);
|
|
16
|
-
const diff = generateDiff(previousSnapshot, currentSnapshot);
|
|
17
|
-
if (diff) {
|
|
18
|
-
const n = getNewMigrationNumber(allMigrationFiles);
|
|
19
|
-
const newFilename = `${String(n + 1).padStart(4, "0")}_migration.json`;
|
|
20
|
-
return {
|
|
21
|
-
state: "ahead",
|
|
22
|
-
oldSnapshot: previousSnapshot,
|
|
23
|
-
newSnapshot: currentSnapshot,
|
|
24
|
-
diff,
|
|
25
|
-
newFilename,
|
|
26
|
-
summary: generateDiffSummary(diff)
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
return {
|
|
30
|
-
state: "up-to-date",
|
|
31
|
-
currentSnapshot
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
const MIGRATIONS_CREATED = `${green(
|
|
35
|
-
"\u25A0 Migrations initialized!"
|
|
36
|
-
)}
|
|
37
|
-
|
|
38
|
-
To execute your migrations, run
|
|
39
|
-
${cyan("astro db push")}`;
|
|
40
|
-
const MIGRATIONS_UP_TO_DATE = `${green(
|
|
41
|
-
"\u25A0 No migrations needed!"
|
|
42
|
-
)}
|
|
43
|
-
|
|
44
|
-
Your database is up to date.
|
|
45
|
-
`;
|
|
46
|
-
const MIGRATIONS_NOT_INITIALIZED = `${yellow(
|
|
47
|
-
"\u25B6 No migrations found!"
|
|
48
|
-
)}
|
|
49
|
-
|
|
50
|
-
To scaffold your migrations folder, run
|
|
51
|
-
${cyan("astro db sync")}
|
|
52
|
-
`;
|
|
53
|
-
const MIGRATION_NEEDED = `${yellow(
|
|
54
|
-
"\u25B6 Changes detected!"
|
|
55
|
-
)}
|
|
56
|
-
|
|
57
|
-
To create the necessary migration file, run
|
|
58
|
-
${cyan("astro db sync")}
|
|
59
|
-
`;
|
|
60
|
-
function generateDiffSummary(diff) {
|
|
61
|
-
return JSON.stringify(diff, null, 2);
|
|
62
|
-
}
|
|
63
|
-
function getNewMigrationNumber(allMigrationFiles) {
|
|
64
|
-
const len = allMigrationFiles.length - 1;
|
|
65
|
-
return allMigrationFiles.reduce((acc, curr) => {
|
|
66
|
-
const num = Number.parseInt(curr.split("_")[0] ?? len, 10);
|
|
67
|
-
return num > acc ? num : acc;
|
|
68
|
-
}, 0);
|
|
69
|
-
}
|
|
70
|
-
async function getMigrations() {
|
|
71
|
-
const migrationFiles = await readdir("./migrations").catch((err) => {
|
|
72
|
-
if (err.code === "ENOENT") {
|
|
73
|
-
return [];
|
|
74
|
-
}
|
|
75
|
-
throw err;
|
|
76
|
-
});
|
|
77
|
-
return migrationFiles;
|
|
78
|
-
}
|
|
79
|
-
async function loadMigration(migration) {
|
|
80
|
-
return JSON.parse(await readFile(`./migrations/${migration}`, "utf-8"));
|
|
81
|
-
}
|
|
82
|
-
async function loadInitialSnapshot() {
|
|
83
|
-
const snapshot = JSON.parse(await readFile("./migrations/0000_snapshot.json", "utf-8"));
|
|
84
|
-
if (snapshot.experimentalVersion === 1) {
|
|
85
|
-
return snapshot;
|
|
86
|
-
}
|
|
87
|
-
if (!snapshot.schema) {
|
|
88
|
-
return { experimentalVersion: 1, schema: snapshot };
|
|
89
|
-
}
|
|
90
|
-
throw new Error("Invalid snapshot format");
|
|
91
|
-
}
|
|
92
|
-
async function initializeMigrationsDirectory(currentSnapshot) {
|
|
93
|
-
await mkdir("./migrations", { recursive: true });
|
|
94
|
-
await writeFile("./migrations/0000_snapshot.json", JSON.stringify(currentSnapshot, void 0, 2));
|
|
95
|
-
}
|
|
96
|
-
async function initializeFromMigrations(allMigrationFiles) {
|
|
97
|
-
const prevSnapshot = await loadInitialSnapshot();
|
|
98
|
-
for (const migration of allMigrationFiles) {
|
|
99
|
-
if (migration === "0000_snapshot.json")
|
|
100
|
-
continue;
|
|
101
|
-
const migrationContent = await loadMigration(migration);
|
|
102
|
-
migrationContent.diff.forEach((change) => {
|
|
103
|
-
applyChange(prevSnapshot, {}, change);
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
return prevSnapshot;
|
|
107
|
-
}
|
|
108
|
-
function createCurrentSnapshot(config) {
|
|
109
|
-
const tablesConfig = tablesSchema.parse(config.db?.tables ?? {});
|
|
110
|
-
const schema = JSON.parse(JSON.stringify(tablesConfig));
|
|
111
|
-
return { experimentalVersion: 1, schema };
|
|
112
|
-
}
|
|
113
|
-
function createEmptySnapshot() {
|
|
114
|
-
return { experimentalVersion: 1, schema: {} };
|
|
115
|
-
}
|
|
116
|
-
export {
|
|
117
|
-
MIGRATIONS_CREATED,
|
|
118
|
-
MIGRATIONS_NOT_INITIALIZED,
|
|
119
|
-
MIGRATIONS_UP_TO_DATE,
|
|
120
|
-
MIGRATION_NEEDED,
|
|
121
|
-
createCurrentSnapshot,
|
|
122
|
-
createEmptySnapshot,
|
|
123
|
-
getMigrationStatus,
|
|
124
|
-
getMigrations,
|
|
125
|
-
initializeFromMigrations,
|
|
126
|
-
initializeMigrationsDirectory,
|
|
127
|
-
loadInitialSnapshot,
|
|
128
|
-
loadMigration
|
|
129
|
-
};
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { pathToFileURL } from "node:url";
|
|
4
|
-
import { bold, red } from "kleur/colors";
|
|
5
|
-
import { createServer } from "vite";
|
|
6
|
-
async function loadAstroConfig(root) {
|
|
7
|
-
const configPath = search(root);
|
|
8
|
-
if (!configPath)
|
|
9
|
-
return {};
|
|
10
|
-
try {
|
|
11
|
-
return await loadConfigWithVite(configPath);
|
|
12
|
-
} catch (e) {
|
|
13
|
-
console.error(`${bold(red("[astro]"))} Unable to load Astro config.
|
|
14
|
-
`);
|
|
15
|
-
throw e;
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
function search(root) {
|
|
19
|
-
const paths = [
|
|
20
|
-
"astro.config.mjs",
|
|
21
|
-
"astro.config.js",
|
|
22
|
-
"astro.config.ts",
|
|
23
|
-
"astro.config.mts",
|
|
24
|
-
"astro.config.cjs",
|
|
25
|
-
"astro.config.cts"
|
|
26
|
-
].map((p) => path.join(root, p));
|
|
27
|
-
for (const file of paths) {
|
|
28
|
-
if (fs.existsSync(file)) {
|
|
29
|
-
return file;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
async function loadConfigWithVite(configPath) {
|
|
34
|
-
if (/\.[cm]?js$/.test(configPath)) {
|
|
35
|
-
try {
|
|
36
|
-
const config = await import(
|
|
37
|
-
/* @vite-ignore */
|
|
38
|
-
pathToFileURL(configPath).toString() + "?t=" + Date.now()
|
|
39
|
-
);
|
|
40
|
-
return config.default ?? {};
|
|
41
|
-
} catch (e) {
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
let server;
|
|
45
|
-
try {
|
|
46
|
-
server = await createViteServer();
|
|
47
|
-
const mod = await server.ssrLoadModule(configPath, { fixStacktrace: true });
|
|
48
|
-
return mod.default ?? {};
|
|
49
|
-
} finally {
|
|
50
|
-
if (server) {
|
|
51
|
-
await server.close();
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
async function createViteServer() {
|
|
56
|
-
const viteServer = await createServer({
|
|
57
|
-
server: { middlewareMode: true, hmr: false, watch: { ignored: ["**"] } },
|
|
58
|
-
optimizeDeps: { disabled: true },
|
|
59
|
-
clearScreen: false,
|
|
60
|
-
appType: "custom",
|
|
61
|
-
ssr: {
|
|
62
|
-
// NOTE: Vite doesn't externalize linked packages by default. During testing locally,
|
|
63
|
-
// these dependencies trip up Vite's dev SSR transform. Awaiting upstream feature:
|
|
64
|
-
// https://github.com/vitejs/vite/pull/10939
|
|
65
|
-
external: [
|
|
66
|
-
"@astrojs/tailwind",
|
|
67
|
-
"@astrojs/mdx",
|
|
68
|
-
"@astrojs/react",
|
|
69
|
-
"@astrojs/preact",
|
|
70
|
-
"@astrojs/sitemap",
|
|
71
|
-
"@astrojs/markdoc"
|
|
72
|
-
]
|
|
73
|
-
}
|
|
74
|
-
});
|
|
75
|
-
return viteServer;
|
|
76
|
-
}
|
|
77
|
-
export {
|
|
78
|
-
loadAstroConfig
|
|
79
|
-
};
|