@astrojs/db 0.3.4 → 0.3.6-nightly-01234567890
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/cli/bin.d.ts +2 -0
- package/dist/cli/commands/deploy/index.d.ts +1 -0
- package/dist/cli/commands/diff/index.d.ts +4 -0
- package/dist/cli/commands/run/index.d.ts +1 -0
- package/dist/cli/commands/snapshot/index.d.ts +4 -0
- package/dist/cli/util.d.ts +34 -0
- package/dist/config.d.ts +13 -137
- package/dist/core/cli/commands/gen/index.d.ts +6 -0
- package/dist/core/cli/commands/link/index.js +7 -3
- package/dist/core/cli/commands/push/index.js +3 -3
- package/dist/core/cli/commands/verify/index.js +6 -1
- package/dist/core/cli/index.js +8 -6
- package/dist/core/cli/migration-queries.d.ts +4 -4
- package/dist/core/cli/migration-queries.js +78 -77
- package/dist/core/cli/migrations.js +15 -7
- package/dist/core/errors.d.ts +2 -0
- package/dist/core/errors.js +26 -9
- package/dist/core/integration/file-url.js +2 -1
- package/dist/core/integration/index.js +106 -53
- package/dist/core/integration/typegen.d.ts +3 -3
- package/dist/core/integration/typegen.js +8 -8
- package/dist/core/integration/vite-plugin-db.d.ts +14 -9
- package/dist/core/integration/vite-plugin-db.js +15 -12
- package/dist/core/integration/vite-plugin-inject-env-ts.d.ts +4 -2
- package/dist/core/integration/vite-plugin-inject-env-ts.js +8 -4
- package/dist/core/queries.d.ts +20 -20
- package/dist/core/queries.js +50 -32
- package/dist/core/types.d.ts +1162 -1153
- package/dist/core/types.js +63 -61
- package/dist/core/utils.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +4 -4
- package/dist/integration.d.ts +1 -1
- package/dist/internal.d.ts +4 -4
- package/dist/runtime/db-client.d.ts +9 -4
- package/dist/runtime/db-client.js +11 -7
- package/dist/runtime/index.d.ts +7 -7
- package/dist/runtime/index.js +29 -43
- package/dist/runtime/types.d.ts +7 -7
- package/dist/types.d.ts +6 -124
- package/dist/utils-runtime.d.ts +1 -0
- package/dist/vite-plugin-db.d.ts +3 -3
- package/package.json +13 -15
- package/LICENSE +0 -59
- package/components/Renderer.astro +0 -14
- package/components/astro-env.d.ts +0 -1
- package/components/index.ts +0 -2
- package/components/tsconfig.json +0 -7
- package/dist/cli/seed.d.ts +0 -6
- package/dist/file-url-integration.d.ts +0 -2
- package/dist/root.d.ts +0 -3
- /package/dist/core/cli/commands/{sync → gen}/index.js +0 -0
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import * as color from "kleur/colors";
|
|
2
2
|
import deepDiff from "deep-diff";
|
|
3
|
+
import {
|
|
4
|
+
columnSchema
|
|
5
|
+
} from "../types.js";
|
|
3
6
|
import { SQLiteAsyncDialect } from "drizzle-orm/sqlite-core";
|
|
4
7
|
import { customAlphabet } from "nanoid";
|
|
5
8
|
import prompts from "prompts";
|
|
@@ -65,9 +68,9 @@ async function getCollectionChangeQueries({
|
|
|
65
68
|
}) {
|
|
66
69
|
const queries = [];
|
|
67
70
|
const confirmations = [];
|
|
68
|
-
const updated =
|
|
69
|
-
let added = getAdded(oldCollection.
|
|
70
|
-
let dropped = getDropped(oldCollection.
|
|
71
|
+
const updated = getUpdatedColumns(oldCollection.columns, newCollection.columns);
|
|
72
|
+
let added = getAdded(oldCollection.columns, newCollection.columns);
|
|
73
|
+
let dropped = getDropped(oldCollection.columns, newCollection.columns);
|
|
71
74
|
const hasForeignKeyChanges = Boolean(
|
|
72
75
|
deepDiff(oldCollection.foreignKeys, newCollection.foreignKeys)
|
|
73
76
|
);
|
|
@@ -82,10 +85,10 @@ async function getCollectionChangeQueries({
|
|
|
82
85
|
};
|
|
83
86
|
}
|
|
84
87
|
if (!hasForeignKeyChanges && !isEmpty(added) && !isEmpty(dropped)) {
|
|
85
|
-
const resolved = await
|
|
88
|
+
const resolved = await resolveColumnRenames(collectionName, added, dropped, ambiguityResponses);
|
|
86
89
|
added = resolved.added;
|
|
87
90
|
dropped = resolved.dropped;
|
|
88
|
-
queries.push(...
|
|
91
|
+
queries.push(...getColumnRenameQueries(collectionName, resolved.renamed));
|
|
89
92
|
}
|
|
90
93
|
if (!hasForeignKeyChanges && isEmpty(updated) && Object.values(dropped).every(canAlterTableDropColumn) && Object.values(added).every(canAlterTableAddColumn)) {
|
|
91
94
|
queries.push(
|
|
@@ -100,33 +103,33 @@ async function getCollectionChangeQueries({
|
|
|
100
103
|
}
|
|
101
104
|
const dataLossCheck = canRecreateTableWithoutDataLoss(added, updated);
|
|
102
105
|
if (dataLossCheck.dataLoss) {
|
|
103
|
-
const { reason,
|
|
106
|
+
const { reason, columnName } = dataLossCheck;
|
|
104
107
|
const reasonMsgs = {
|
|
105
|
-
"added-required": `New
|
|
106
|
-
collectionName + "." +
|
|
108
|
+
"added-required": `New column ${color.bold(
|
|
109
|
+
collectionName + "." + columnName
|
|
107
110
|
)} is required with no default value.
|
|
108
111
|
This requires deleting existing data in the ${color.bold(
|
|
109
112
|
collectionName
|
|
110
113
|
)} collection.`,
|
|
111
|
-
"added-unique": `New
|
|
112
|
-
collectionName + "." +
|
|
114
|
+
"added-unique": `New column ${color.bold(
|
|
115
|
+
collectionName + "." + columnName
|
|
113
116
|
)} is marked as unique.
|
|
114
117
|
This requires deleting existing data in the ${color.bold(
|
|
115
118
|
collectionName
|
|
116
119
|
)} collection.`,
|
|
117
|
-
"updated-type": `Updated
|
|
118
|
-
collectionName + "." +
|
|
119
|
-
)} cannot convert data to new
|
|
120
|
+
"updated-type": `Updated column ${color.bold(
|
|
121
|
+
collectionName + "." + columnName
|
|
122
|
+
)} cannot convert data to new column data type.
|
|
120
123
|
This requires deleting existing data in the ${color.bold(
|
|
121
124
|
collectionName
|
|
122
125
|
)} collection.`
|
|
123
126
|
};
|
|
124
127
|
confirmations.push(reasonMsgs[reason]);
|
|
125
128
|
}
|
|
126
|
-
const primaryKeyExists = Object.entries(newCollection.
|
|
127
|
-
([,
|
|
129
|
+
const primaryKeyExists = Object.entries(newCollection.columns).find(
|
|
130
|
+
([, column]) => hasPrimaryKey(column)
|
|
128
131
|
);
|
|
129
|
-
const droppedPrimaryKey = Object.entries(dropped).find(([,
|
|
132
|
+
const droppedPrimaryKey = Object.entries(dropped).find(([, column]) => hasPrimaryKey(column));
|
|
130
133
|
const recreateTableQueries = getRecreateTableQueries({
|
|
131
134
|
collectionName,
|
|
132
135
|
newCollection,
|
|
@@ -155,20 +158,20 @@ function getChangeIndexQueries({
|
|
|
155
158
|
queries.push(...getCreateIndexQueries(collectionName, { indexes: added }));
|
|
156
159
|
return queries;
|
|
157
160
|
}
|
|
158
|
-
async function
|
|
161
|
+
async function resolveColumnRenames(collectionName, mightAdd, mightDrop, ambiguityResponses) {
|
|
159
162
|
const added = {};
|
|
160
163
|
const dropped = {};
|
|
161
164
|
const renamed = [];
|
|
162
|
-
for (const [
|
|
163
|
-
let
|
|
164
|
-
if (!
|
|
165
|
+
for (const [columnName, column] of Object.entries(mightAdd)) {
|
|
166
|
+
let oldColumnName = ambiguityResponses ? ambiguityResponses.columnRenames[collectionName]?.[columnName] ?? "__NEW__" : void 0;
|
|
167
|
+
if (!oldColumnName) {
|
|
165
168
|
const res = await prompts(
|
|
166
169
|
{
|
|
167
170
|
type: "select",
|
|
168
|
-
name: "
|
|
169
|
-
message: "New
|
|
171
|
+
name: "columnName",
|
|
172
|
+
message: "New column " + color.blue(color.bold(`${collectionName}.${columnName}`)) + " detected. Was this renamed from an existing column?",
|
|
170
173
|
choices: [
|
|
171
|
-
{ title: "New
|
|
174
|
+
{ title: "New column (not renamed from existing)", value: "__NEW__" },
|
|
172
175
|
...Object.keys(mightDrop).filter((key) => !(key in renamed)).map((key) => ({ title: key, value: key }))
|
|
173
176
|
]
|
|
174
177
|
},
|
|
@@ -178,17 +181,17 @@ async function resolveFieldRenames(collectionName, mightAdd, mightDrop, ambiguit
|
|
|
178
181
|
}
|
|
179
182
|
}
|
|
180
183
|
);
|
|
181
|
-
|
|
184
|
+
oldColumnName = res.columnName;
|
|
182
185
|
}
|
|
183
|
-
if (
|
|
184
|
-
added[
|
|
186
|
+
if (oldColumnName === "__NEW__") {
|
|
187
|
+
added[columnName] = column;
|
|
185
188
|
} else {
|
|
186
|
-
renamed.push({ from:
|
|
189
|
+
renamed.push({ from: oldColumnName, to: columnName });
|
|
187
190
|
}
|
|
188
191
|
}
|
|
189
|
-
for (const [
|
|
190
|
-
if (!renamed.find((r) => r.from ===
|
|
191
|
-
dropped[
|
|
192
|
+
for (const [droppedColumnName, droppedColumn] of Object.entries(mightDrop)) {
|
|
193
|
+
if (!renamed.find((r) => r.from === droppedColumnName)) {
|
|
194
|
+
dropped[droppedColumnName] = droppedColumn;
|
|
192
195
|
}
|
|
193
196
|
}
|
|
194
197
|
return { added, dropped, renamed };
|
|
@@ -247,7 +250,7 @@ function getDroppedCollections(oldCollections, newCollections) {
|
|
|
247
250
|
}
|
|
248
251
|
return dropped;
|
|
249
252
|
}
|
|
250
|
-
function
|
|
253
|
+
function getColumnRenameQueries(unescapedCollectionName, renamed) {
|
|
251
254
|
const queries = [];
|
|
252
255
|
const collectionName = sqlite.escapeName(unescapedCollectionName);
|
|
253
256
|
for (const { from, to } of renamed) {
|
|
@@ -261,18 +264,18 @@ function getFieldRenameQueries(unescapedCollectionName, renamed) {
|
|
|
261
264
|
function getAlterTableQueries(unescapedCollectionName, added, dropped) {
|
|
262
265
|
const queries = [];
|
|
263
266
|
const collectionName = sqlite.escapeName(unescapedCollectionName);
|
|
264
|
-
for (const [
|
|
265
|
-
const
|
|
266
|
-
const type = schemaTypeToSqlType(
|
|
267
|
-
const q = `ALTER TABLE ${collectionName} ADD COLUMN ${
|
|
268
|
-
|
|
269
|
-
|
|
267
|
+
for (const [unescColumnName, column] of Object.entries(added)) {
|
|
268
|
+
const columnName = sqlite.escapeName(unescColumnName);
|
|
269
|
+
const type = schemaTypeToSqlType(column.type);
|
|
270
|
+
const q = `ALTER TABLE ${collectionName} ADD COLUMN ${columnName} ${type}${getModifiers(
|
|
271
|
+
columnName,
|
|
272
|
+
column
|
|
270
273
|
)}`;
|
|
271
274
|
queries.push(q);
|
|
272
275
|
}
|
|
273
|
-
for (const
|
|
274
|
-
const
|
|
275
|
-
const q = `ALTER TABLE ${collectionName} DROP COLUMN ${
|
|
276
|
+
for (const unescColumnName of Object.keys(dropped)) {
|
|
277
|
+
const columnName = sqlite.escapeName(unescColumnName);
|
|
278
|
+
const q = `ALTER TABLE ${collectionName} DROP COLUMN ${columnName}`;
|
|
276
279
|
queries.push(q);
|
|
277
280
|
}
|
|
278
281
|
return queries;
|
|
@@ -293,7 +296,7 @@ function getRecreateTableQueries({
|
|
|
293
296
|
getCreateTableQuery(unescCollectionName, newCollection)
|
|
294
297
|
];
|
|
295
298
|
}
|
|
296
|
-
const newColumns = [...Object.keys(newCollection.
|
|
299
|
+
const newColumns = [...Object.keys(newCollection.columns)];
|
|
297
300
|
if (migrateHiddenPrimaryKey) {
|
|
298
301
|
newColumns.unshift("_id");
|
|
299
302
|
}
|
|
@@ -308,41 +311,41 @@ function getRecreateTableQueries({
|
|
|
308
311
|
function isEmpty(obj) {
|
|
309
312
|
return Object.keys(obj).length === 0;
|
|
310
313
|
}
|
|
311
|
-
function canAlterTableAddColumn(
|
|
312
|
-
if (
|
|
314
|
+
function canAlterTableAddColumn(column) {
|
|
315
|
+
if (column.schema.unique)
|
|
313
316
|
return false;
|
|
314
|
-
if (hasRuntimeDefault(
|
|
317
|
+
if (hasRuntimeDefault(column))
|
|
315
318
|
return false;
|
|
316
|
-
if (!
|
|
319
|
+
if (!column.schema.optional && !hasDefault(column))
|
|
317
320
|
return false;
|
|
318
|
-
if (hasPrimaryKey(
|
|
321
|
+
if (hasPrimaryKey(column))
|
|
319
322
|
return false;
|
|
320
|
-
if (getReferencesConfig(
|
|
323
|
+
if (getReferencesConfig(column))
|
|
321
324
|
return false;
|
|
322
325
|
return true;
|
|
323
326
|
}
|
|
324
|
-
function canAlterTableDropColumn(
|
|
325
|
-
if (
|
|
327
|
+
function canAlterTableDropColumn(column) {
|
|
328
|
+
if (column.schema.unique)
|
|
326
329
|
return false;
|
|
327
|
-
if (hasPrimaryKey(
|
|
330
|
+
if (hasPrimaryKey(column))
|
|
328
331
|
return false;
|
|
329
332
|
return true;
|
|
330
333
|
}
|
|
331
334
|
function canRecreateTableWithoutDataLoss(added, updated) {
|
|
332
|
-
for (const [
|
|
335
|
+
for (const [columnName, a] of Object.entries(added)) {
|
|
333
336
|
if (hasPrimaryKey(a) && a.type !== "number" && !hasDefault(a)) {
|
|
334
|
-
return { dataLoss: true,
|
|
337
|
+
return { dataLoss: true, columnName, reason: "added-required" };
|
|
335
338
|
}
|
|
336
339
|
if (!a.schema.optional && !hasDefault(a)) {
|
|
337
|
-
return { dataLoss: true,
|
|
340
|
+
return { dataLoss: true, columnName, reason: "added-required" };
|
|
338
341
|
}
|
|
339
342
|
if (!a.schema.optional && a.schema.unique) {
|
|
340
|
-
return { dataLoss: true,
|
|
343
|
+
return { dataLoss: true, columnName, reason: "added-unique" };
|
|
341
344
|
}
|
|
342
345
|
}
|
|
343
|
-
for (const [
|
|
346
|
+
for (const [columnName, u] of Object.entries(updated)) {
|
|
344
347
|
if (u.old.type !== u.new.type && !canChangeTypeWithoutQuery(u.old, u.new)) {
|
|
345
|
-
return { dataLoss: true,
|
|
348
|
+
return { dataLoss: true, columnName, reason: "updated-type" };
|
|
346
349
|
}
|
|
347
350
|
}
|
|
348
351
|
return { dataLoss: false };
|
|
@@ -374,21 +377,24 @@ function getUpdated(oldObj, newObj) {
|
|
|
374
377
|
}
|
|
375
378
|
return updated;
|
|
376
379
|
}
|
|
377
|
-
function
|
|
380
|
+
function getUpdatedColumns(oldColumns, newColumns) {
|
|
378
381
|
const updated = {};
|
|
379
|
-
for (const [key,
|
|
380
|
-
|
|
381
|
-
if (!
|
|
382
|
+
for (const [key, newColumn] of Object.entries(newColumns)) {
|
|
383
|
+
let oldColumn = oldColumns[key];
|
|
384
|
+
if (!oldColumn)
|
|
382
385
|
continue;
|
|
383
|
-
|
|
384
|
-
const
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
)
|
|
389
|
-
|
|
386
|
+
if (oldColumn.type !== newColumn.type && canChangeTypeWithoutQuery(oldColumn, newColumn)) {
|
|
387
|
+
const asNewColumn = columnSchema.safeParse({
|
|
388
|
+
type: newColumn.type,
|
|
389
|
+
schema: oldColumn.schema
|
|
390
|
+
});
|
|
391
|
+
if (asNewColumn.success) {
|
|
392
|
+
oldColumn = asNewColumn.data;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
const diff = deepDiff(oldColumn, newColumn);
|
|
390
396
|
if (diff) {
|
|
391
|
-
updated[key] = { old:
|
|
397
|
+
updated[key] = { old: oldColumn, new: newColumn };
|
|
392
398
|
}
|
|
393
399
|
}
|
|
394
400
|
return updated;
|
|
@@ -397,19 +403,14 @@ const typeChangesWithoutQuery = [
|
|
|
397
403
|
{ from: "boolean", to: "number" },
|
|
398
404
|
{ from: "date", to: "text" },
|
|
399
405
|
{ from: "json", to: "text" }
|
|
400
|
-
// TODO: decide on these. They *could* work with SQLite CAST
|
|
401
|
-
// { from: 'boolean', to: 'text' },
|
|
402
|
-
// { from: 'boolean', to: 'json' },
|
|
403
|
-
// { from: 'number', to: 'text' },
|
|
404
|
-
// { from: 'number', to: 'json' },
|
|
405
406
|
];
|
|
406
|
-
function canChangeTypeWithoutQuery(
|
|
407
|
+
function canChangeTypeWithoutQuery(oldColumn, newColumn) {
|
|
407
408
|
return typeChangesWithoutQuery.some(
|
|
408
|
-
({ from, to }) =>
|
|
409
|
+
({ from, to }) => oldColumn.type === from && newColumn.type === to
|
|
409
410
|
);
|
|
410
411
|
}
|
|
411
|
-
function hasRuntimeDefault(
|
|
412
|
-
return !!(
|
|
412
|
+
function hasRuntimeDefault(column) {
|
|
413
|
+
return !!(column.schema.default && isSerializedSQL(column.schema.default));
|
|
413
414
|
}
|
|
414
415
|
export {
|
|
415
416
|
getCollectionChangeQueries,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import deepDiff from "deep-diff";
|
|
2
2
|
import { mkdir, readFile, readdir, writeFile } from "fs/promises";
|
|
3
|
-
import {
|
|
3
|
+
import { tablesSchema } from "../types.js";
|
|
4
4
|
import { cyan, green, yellow } from "kleur/colors";
|
|
5
5
|
const { applyChange, diff: generateDiff } = deepDiff;
|
|
6
6
|
async function getMigrationStatus(config) {
|
|
@@ -31,20 +31,28 @@ async function getMigrationStatus(config) {
|
|
|
31
31
|
currentSnapshot
|
|
32
32
|
};
|
|
33
33
|
}
|
|
34
|
-
const MIGRATIONS_CREATED = `${green(
|
|
34
|
+
const MIGRATIONS_CREATED = `${green(
|
|
35
|
+
"\u25A0 Migrations initialized!"
|
|
36
|
+
)}
|
|
35
37
|
|
|
36
38
|
To execute your migrations, run
|
|
37
39
|
${cyan("astro db push")}`;
|
|
38
|
-
const MIGRATIONS_UP_TO_DATE = `${green(
|
|
40
|
+
const MIGRATIONS_UP_TO_DATE = `${green(
|
|
41
|
+
"\u25A0 No migrations needed!"
|
|
42
|
+
)}
|
|
39
43
|
|
|
40
44
|
Your database is up to date.
|
|
41
45
|
`;
|
|
42
|
-
const MIGRATIONS_NOT_INITIALIZED = `${yellow(
|
|
46
|
+
const MIGRATIONS_NOT_INITIALIZED = `${yellow(
|
|
47
|
+
"\u25B6 No migrations found!"
|
|
48
|
+
)}
|
|
43
49
|
|
|
44
50
|
To scaffold your migrations folder, run
|
|
45
51
|
${cyan("astro db sync")}
|
|
46
52
|
`;
|
|
47
|
-
const MIGRATION_NEEDED = `${yellow(
|
|
53
|
+
const MIGRATION_NEEDED = `${yellow(
|
|
54
|
+
"\u25B6 Changes detected!"
|
|
55
|
+
)}
|
|
48
56
|
|
|
49
57
|
To create the necessary migration file, run
|
|
50
58
|
${cyan("astro db sync")}
|
|
@@ -98,8 +106,8 @@ async function initializeFromMigrations(allMigrationFiles) {
|
|
|
98
106
|
return prevSnapshot;
|
|
99
107
|
}
|
|
100
108
|
function createCurrentSnapshot(config) {
|
|
101
|
-
const
|
|
102
|
-
const schema = JSON.parse(JSON.stringify(
|
|
109
|
+
const tablesConfig = tablesSchema.parse(config.db?.tables ?? {});
|
|
110
|
+
const schema = JSON.parse(JSON.stringify(tablesConfig));
|
|
103
111
|
return { experimentalVersion: 1, schema };
|
|
104
112
|
}
|
|
105
113
|
function createEmptySnapshot() {
|
package/dist/core/errors.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export declare const MISSING_SESSION_ID_ERROR: string;
|
|
2
2
|
export declare const MISSING_PROJECT_ID_ERROR: string;
|
|
3
3
|
export declare const STUDIO_CONFIG_MISSING_WRITABLE_COLLECTIONS_ERROR: (collectionName: string) => string;
|
|
4
|
+
export declare const UNSAFE_WRITABLE_WARNING: string;
|
|
4
5
|
export declare const STUDIO_CONFIG_MISSING_CLI_ERROR: string;
|
|
5
6
|
export declare const MIGRATIONS_NOT_INITIALIZED: string;
|
|
7
|
+
export declare const SEED_WRITABLE_IN_PROD_ERROR: (collectionName: string) => string;
|
package/dist/core/errors.js
CHANGED
|
@@ -1,37 +1,54 @@
|
|
|
1
1
|
import { cyan, bold, red, green, yellow } from "kleur/colors";
|
|
2
|
-
const MISSING_SESSION_ID_ERROR = `${red(
|
|
3
|
-
"\u25B6 Login required!"
|
|
4
|
-
)}
|
|
2
|
+
const MISSING_SESSION_ID_ERROR = `${red("\u25B6 Login required!")}
|
|
5
3
|
|
|
6
4
|
To authenticate with Astro Studio, run
|
|
7
5
|
${cyan("astro db login")}
|
|
8
6
|
`;
|
|
9
|
-
const MISSING_PROJECT_ID_ERROR = `${red(
|
|
10
|
-
"\u25B6 Directory not linked."
|
|
11
|
-
)}
|
|
7
|
+
const MISSING_PROJECT_ID_ERROR = `${red("\u25B6 Directory not linked.")}
|
|
12
8
|
|
|
13
9
|
To link this directory to an Astro Studio project, run
|
|
14
10
|
${cyan("astro db link")}
|
|
15
11
|
`;
|
|
16
|
-
const STUDIO_CONFIG_MISSING_WRITABLE_COLLECTIONS_ERROR = (collectionName) => `${red(
|
|
12
|
+
const STUDIO_CONFIG_MISSING_WRITABLE_COLLECTIONS_ERROR = (collectionName) => `${red(
|
|
13
|
+
`\u25B6 Writable collection ${bold(collectionName)} requires Astro Studio or the ${yellow(
|
|
14
|
+
"unsafeWritable"
|
|
15
|
+
)} option.`
|
|
16
|
+
)}
|
|
17
17
|
|
|
18
18
|
Visit ${cyan("https://astro.build/studio")} to create your account
|
|
19
19
|
and set ${green("studio: true")} in your astro.config.mjs file to enable Studio.
|
|
20
20
|
`;
|
|
21
|
+
const UNSAFE_WRITABLE_WARNING = `${yellow(
|
|
22
|
+
"unsafeWritable"
|
|
23
|
+
)} option is enabled and you are using writable tables.
|
|
24
|
+
Redeploying your app may result in wiping away your database.
|
|
25
|
+
I hope you know what you are doing.
|
|
26
|
+
`;
|
|
21
27
|
const STUDIO_CONFIG_MISSING_CLI_ERROR = `${red("\u25B6 This command requires Astro Studio.")}
|
|
22
28
|
|
|
23
29
|
Visit ${cyan("https://astro.build/studio")} to create your account
|
|
24
30
|
and set ${green("studio: true")} in your astro.config.mjs file to enable Studio.
|
|
25
31
|
`;
|
|
26
|
-
const MIGRATIONS_NOT_INITIALIZED = `${yellow(
|
|
32
|
+
const MIGRATIONS_NOT_INITIALIZED = `${yellow(
|
|
33
|
+
"\u25B6 No migrations found!"
|
|
34
|
+
)}
|
|
27
35
|
|
|
28
36
|
To scaffold your migrations folder, run
|
|
29
37
|
${cyan("astro db sync")}
|
|
30
38
|
`;
|
|
39
|
+
const SEED_WRITABLE_IN_PROD_ERROR = (collectionName) => {
|
|
40
|
+
return `${red(
|
|
41
|
+
`Writable tables should not be seeded in production with data().`
|
|
42
|
+
)} You can seed ${bold(
|
|
43
|
+
collectionName
|
|
44
|
+
)} in development mode only using the "mode" flag. See the docs for more: https://www.notion.so/astroinc/astrojs-db-README-dcf6fa10de9a4f528be56cee96e8c054?pvs=4#278aed3fc37e4cec80240d1552ff6ac5`;
|
|
45
|
+
};
|
|
31
46
|
export {
|
|
32
47
|
MIGRATIONS_NOT_INITIALIZED,
|
|
33
48
|
MISSING_PROJECT_ID_ERROR,
|
|
34
49
|
MISSING_SESSION_ID_ERROR,
|
|
50
|
+
SEED_WRITABLE_IN_PROD_ERROR,
|
|
35
51
|
STUDIO_CONFIG_MISSING_CLI_ERROR,
|
|
36
|
-
STUDIO_CONFIG_MISSING_WRITABLE_COLLECTIONS_ERROR
|
|
52
|
+
STUDIO_CONFIG_MISSING_WRITABLE_COLLECTIONS_ERROR,
|
|
53
|
+
UNSAFE_WRITABLE_WARNING
|
|
37
54
|
};
|
|
@@ -8,7 +8,7 @@ async function copyFile(toDir, fromUrl, toUrl) {
|
|
|
8
8
|
function fileURLIntegration() {
|
|
9
9
|
const fileNames = [];
|
|
10
10
|
function createVitePlugin(command) {
|
|
11
|
-
|
|
11
|
+
let referenceIds = [];
|
|
12
12
|
return {
|
|
13
13
|
name: "@astrojs/db/file-url",
|
|
14
14
|
enforce: "pre",
|
|
@@ -34,6 +34,7 @@ function fileURLIntegration() {
|
|
|
34
34
|
for (const referenceId of referenceIds) {
|
|
35
35
|
fileNames.push(this.getFileName(referenceId));
|
|
36
36
|
}
|
|
37
|
+
referenceIds = [];
|
|
37
38
|
}
|
|
38
39
|
};
|
|
39
40
|
}
|
|
@@ -1,3 +1,43 @@
|
|
|
1
|
+
var __knownSymbol = (name, symbol) => {
|
|
2
|
+
return (symbol = Symbol[name]) ? symbol : Symbol.for("Symbol." + name);
|
|
3
|
+
};
|
|
4
|
+
var __using = (stack, value, async) => {
|
|
5
|
+
if (value != null) {
|
|
6
|
+
if (typeof value !== "object" && typeof value !== "function")
|
|
7
|
+
throw TypeError("Object expected");
|
|
8
|
+
var dispose;
|
|
9
|
+
if (async)
|
|
10
|
+
dispose = value[__knownSymbol("asyncDispose")];
|
|
11
|
+
if (dispose === void 0)
|
|
12
|
+
dispose = value[__knownSymbol("dispose")];
|
|
13
|
+
if (typeof dispose !== "function")
|
|
14
|
+
throw TypeError("Object not disposable");
|
|
15
|
+
stack.push([async, dispose, value]);
|
|
16
|
+
} else if (async) {
|
|
17
|
+
stack.push([async]);
|
|
18
|
+
}
|
|
19
|
+
return value;
|
|
20
|
+
};
|
|
21
|
+
var __callDispose = (stack, error, hasError) => {
|
|
22
|
+
var E = typeof SuppressedError === "function" ? SuppressedError : function(e, s, m, _) {
|
|
23
|
+
return _ = Error(m), _.name = "SuppressedError", _.error = e, _.suppressed = s, _;
|
|
24
|
+
};
|
|
25
|
+
var fail = (e) => error = hasError ? new E(e, error, "An error was suppressed during disposal") : (hasError = true, e);
|
|
26
|
+
var next = (it) => {
|
|
27
|
+
while (it = stack.pop()) {
|
|
28
|
+
try {
|
|
29
|
+
var result = it[1] && it[1].call(it[2]);
|
|
30
|
+
if (it[0])
|
|
31
|
+
return Promise.resolve(result).then(next, (e) => (fail(e), next()));
|
|
32
|
+
} catch (e) {
|
|
33
|
+
fail(e);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
if (hasError)
|
|
37
|
+
throw error;
|
|
38
|
+
};
|
|
39
|
+
return next();
|
|
40
|
+
};
|
|
1
41
|
import { vitePluginDb } from "./vite-plugin-db.js";
|
|
2
42
|
import { vitePluginInjectEnvTs } from "./vite-plugin-inject-env-ts.js";
|
|
3
43
|
import { typegen } from "./typegen.js";
|
|
@@ -7,7 +47,10 @@ import { DB_PATH } from "../consts.js";
|
|
|
7
47
|
import { createLocalDatabaseClient } from "../../runtime/db-client.js";
|
|
8
48
|
import { astroConfigWithDbSchema } from "../types.js";
|
|
9
49
|
import {} from "../utils.js";
|
|
10
|
-
import {
|
|
50
|
+
import {
|
|
51
|
+
STUDIO_CONFIG_MISSING_WRITABLE_COLLECTIONS_ERROR,
|
|
52
|
+
UNSAFE_WRITABLE_WARNING
|
|
53
|
+
} from "../errors.js";
|
|
11
54
|
import { errorMap } from "./error-map.js";
|
|
12
55
|
import { dirname } from "path";
|
|
13
56
|
import { fileURLToPath } from "url";
|
|
@@ -18,81 +61,91 @@ import { getManagedAppTokenOrExit } from "../tokens.js";
|
|
|
18
61
|
function astroDBIntegration() {
|
|
19
62
|
let connectedToRemote = false;
|
|
20
63
|
let appToken;
|
|
64
|
+
let schemas = {
|
|
65
|
+
tables() {
|
|
66
|
+
throw new Error("tables not found");
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
let command;
|
|
21
70
|
return {
|
|
22
71
|
name: "astro:db",
|
|
23
72
|
hooks: {
|
|
24
|
-
"astro:config:setup": async ({
|
|
25
|
-
|
|
73
|
+
"astro:config:setup": async ({ updateConfig, config, command: _command, logger }) => {
|
|
74
|
+
command = _command;
|
|
75
|
+
if (_command === "preview")
|
|
26
76
|
return;
|
|
27
|
-
|
|
28
|
-
const
|
|
29
|
-
const studio = configWithDb.db?.studio ?? false;
|
|
30
|
-
const foundWritableCollection = Object.entries(collections).find(([, c]) => c.writable);
|
|
31
|
-
if (!studio && foundWritableCollection) {
|
|
32
|
-
logger.error(
|
|
33
|
-
STUDIO_CONFIG_MISSING_WRITABLE_COLLECTIONS_ERROR(foundWritableCollection[0])
|
|
34
|
-
);
|
|
35
|
-
process.exit(1);
|
|
36
|
-
}
|
|
37
|
-
let dbPlugin;
|
|
77
|
+
let dbPlugin = void 0;
|
|
78
|
+
const studio = config.db?.studio ?? false;
|
|
38
79
|
if (studio && command === "build" && process.env.ASTRO_DB_TEST_ENV !== "1") {
|
|
39
80
|
appToken = await getManagedAppTokenOrExit();
|
|
40
81
|
connectedToRemote = true;
|
|
41
82
|
dbPlugin = vitePluginDb({
|
|
42
83
|
connectToStudio: true,
|
|
43
|
-
collections,
|
|
44
84
|
appToken: appToken.token,
|
|
85
|
+
schemas,
|
|
45
86
|
root: config.root
|
|
46
87
|
});
|
|
47
88
|
} else {
|
|
48
|
-
const dbUrl = new URL(DB_PATH, config.root);
|
|
49
|
-
if (existsSync(dbUrl)) {
|
|
50
|
-
await rm(dbUrl);
|
|
51
|
-
}
|
|
52
|
-
await mkdir(dirname(fileURLToPath(dbUrl)), { recursive: true });
|
|
53
|
-
await writeFile(dbUrl, "");
|
|
54
|
-
const db = await createLocalDatabaseClient({
|
|
55
|
-
collections,
|
|
56
|
-
dbUrl: dbUrl.toString(),
|
|
57
|
-
seeding: true
|
|
58
|
-
});
|
|
59
|
-
await recreateTables({ db, collections });
|
|
60
|
-
if (configWithDb.db?.data) {
|
|
61
|
-
await seedData({
|
|
62
|
-
db,
|
|
63
|
-
data: configWithDb.db.data,
|
|
64
|
-
logger,
|
|
65
|
-
mode: command === "dev" ? "dev" : "build"
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
logger.debug("Database setup complete.");
|
|
69
89
|
dbPlugin = vitePluginDb({
|
|
70
90
|
connectToStudio: false,
|
|
71
|
-
|
|
91
|
+
schemas,
|
|
72
92
|
root: config.root
|
|
73
93
|
});
|
|
74
94
|
}
|
|
75
95
|
updateConfig({
|
|
76
96
|
vite: {
|
|
77
97
|
assetsInclude: [DB_PATH],
|
|
78
|
-
plugins: [
|
|
79
|
-
dbPlugin,
|
|
80
|
-
vitePluginInjectEnvTs(config),
|
|
81
|
-
{
|
|
82
|
-
name: "my-plugin",
|
|
83
|
-
resolveId(id) {
|
|
84
|
-
if (id.endsWith("?server-path")) {
|
|
85
|
-
}
|
|
86
|
-
},
|
|
87
|
-
load(id) {
|
|
88
|
-
if (id.endsWith("?server-path")) {
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
]
|
|
98
|
+
plugins: [dbPlugin, vitePluginInjectEnvTs(config, logger)]
|
|
93
99
|
}
|
|
94
100
|
});
|
|
95
|
-
|
|
101
|
+
},
|
|
102
|
+
"astro:config:done": async ({ config, logger }) => {
|
|
103
|
+
const configWithDb = astroConfigWithDbSchema.parse(config, { errorMap });
|
|
104
|
+
const tables = configWithDb.db?.tables ?? {};
|
|
105
|
+
schemas.tables = () => tables;
|
|
106
|
+
const studio = configWithDb.db?.studio ?? false;
|
|
107
|
+
const unsafeWritable = Boolean(configWithDb.db?.unsafeWritable);
|
|
108
|
+
const foundWritableCollection = Object.entries(tables).find(([, c]) => c.writable);
|
|
109
|
+
const writableAllowed = studio || unsafeWritable;
|
|
110
|
+
if (!writableAllowed && foundWritableCollection) {
|
|
111
|
+
logger.error(
|
|
112
|
+
STUDIO_CONFIG_MISSING_WRITABLE_COLLECTIONS_ERROR(foundWritableCollection[0])
|
|
113
|
+
);
|
|
114
|
+
process.exit(1);
|
|
115
|
+
} else if (unsafeWritable && foundWritableCollection) {
|
|
116
|
+
logger.warn(UNSAFE_WRITABLE_WARNING);
|
|
117
|
+
}
|
|
118
|
+
if (!connectedToRemote) {
|
|
119
|
+
var _stack = [];
|
|
120
|
+
try {
|
|
121
|
+
const dbUrl = new URL(DB_PATH, config.root);
|
|
122
|
+
if (existsSync(dbUrl)) {
|
|
123
|
+
await rm(dbUrl);
|
|
124
|
+
}
|
|
125
|
+
await mkdir(dirname(fileURLToPath(dbUrl)), { recursive: true });
|
|
126
|
+
await writeFile(dbUrl, "");
|
|
127
|
+
const db = __using(_stack, await createLocalDatabaseClient({
|
|
128
|
+
tables,
|
|
129
|
+
dbUrl: dbUrl.toString(),
|
|
130
|
+
seeding: true
|
|
131
|
+
}));
|
|
132
|
+
await recreateTables({ db, tables });
|
|
133
|
+
if (configWithDb.db?.data) {
|
|
134
|
+
await seedData({
|
|
135
|
+
db,
|
|
136
|
+
data: configWithDb.db.data,
|
|
137
|
+
logger,
|
|
138
|
+
mode: command === "dev" ? "dev" : "build"
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
logger.debug("Database setup complete.");
|
|
142
|
+
} catch (_) {
|
|
143
|
+
var _error = _, _hasError = true;
|
|
144
|
+
} finally {
|
|
145
|
+
__callDispose(_stack, _error, _hasError);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
await typegen({ tables, root: config.root });
|
|
96
149
|
},
|
|
97
150
|
"astro:server:start": async ({ logger }) => {
|
|
98
151
|
setTimeout(() => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export declare function typegen({
|
|
3
|
-
|
|
1
|
+
import type { DBTables } from '../types.js';
|
|
2
|
+
export declare function typegen({ tables, root }: {
|
|
3
|
+
tables: DBTables;
|
|
4
4
|
root: URL;
|
|
5
5
|
}): Promise<void>;
|