@astrojs/db 0.9.5 → 0.9.7
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/_internal/core/types.d.ts +0 -2
- package/dist/core/cli/migration-queries.d.ts +4 -4
- package/dist/core/cli/migration-queries.js +70 -77
- package/dist/core/cli/print-help.js +1 -1
- package/dist/core/errors.d.ts +0 -6
- package/dist/core/errors.js +0 -34
- package/dist/core/integration/index.js +13 -0
- package/dist/core/integration/typegen.js +3 -3
- package/dist/core/integration/vite-plugin-db.js +7 -6
- package/dist/core/schemas.js +2 -2
- package/dist/core/types.d.ts +0 -2
- package/dist/index.d.ts +1 -1
- package/dist/runtime/errors.d.ts +6 -0
- package/dist/runtime/errors.js +37 -0
- package/dist/runtime/queries.js +1 -1
- package/dist/runtime/seed-local.js +1 -1
- package/package.json +1 -1
|
@@ -38,8 +38,6 @@ export interface TableConfig<TColumns extends ColumnsConfig = ColumnsConfig> ext
|
|
|
38
38
|
interface IndexConfig<TColumns extends ColumnsConfig> extends z.input<typeof indexSchema> {
|
|
39
39
|
on: MaybeArray<Extract<keyof TColumns, string>>;
|
|
40
40
|
}
|
|
41
|
-
/** @deprecated Use `TableConfig` instead */
|
|
42
|
-
export type ResolvedCollectionConfig<TColumns extends ColumnsConfig = ColumnsConfig> = TableConfig<TColumns>;
|
|
43
41
|
export type NumberColumnOpts = z.input<typeof numberColumnOptsSchema>;
|
|
44
42
|
export type TextColumnOpts = z.input<typeof textColumnOptsSchema>;
|
|
45
43
|
export type AstroDbIntegration = AstroIntegration & {
|
|
@@ -7,10 +7,10 @@ export declare function getMigrationQueries({ oldSnapshot, newSnapshot, reset, }
|
|
|
7
7
|
queries: string[];
|
|
8
8
|
confirmations: string[];
|
|
9
9
|
}>;
|
|
10
|
-
export declare function
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
export declare function getTableChangeQueries({ tableName, oldTable, newTable, }: {
|
|
11
|
+
tableName: string;
|
|
12
|
+
oldTable: DBTable;
|
|
13
|
+
newTable: DBTable;
|
|
14
14
|
}): Promise<{
|
|
15
15
|
queries: string[];
|
|
16
16
|
confirmations: string[];
|
|
@@ -7,6 +7,7 @@ import { hasPrimaryKey } from "../../runtime/index.js";
|
|
|
7
7
|
import {
|
|
8
8
|
getCreateIndexQueries,
|
|
9
9
|
getCreateTableQuery,
|
|
10
|
+
getDropTableIfExistsQuery,
|
|
10
11
|
getModifiers,
|
|
11
12
|
getReferencesConfig,
|
|
12
13
|
hasDefault,
|
|
@@ -34,84 +35,79 @@ async function getMigrationQueries({
|
|
|
34
35
|
oldSnapshot = createEmptySnapshot();
|
|
35
36
|
queries.push(...getDropTableQueriesForSnapshot(currentSnapshot));
|
|
36
37
|
}
|
|
37
|
-
const
|
|
38
|
-
const droppedTables =
|
|
38
|
+
const addedTables = getAddedTables(oldSnapshot, newSnapshot);
|
|
39
|
+
const droppedTables = getDroppedTables(oldSnapshot, newSnapshot);
|
|
39
40
|
const notDeprecatedDroppedTables = Object.fromEntries(
|
|
40
41
|
Object.entries(droppedTables).filter(([, table]) => !table.deprecated)
|
|
41
42
|
);
|
|
42
|
-
if (!isEmpty(
|
|
43
|
+
if (!isEmpty(addedTables) && !isEmpty(notDeprecatedDroppedTables)) {
|
|
43
44
|
throw new Error(
|
|
44
|
-
RENAME_TABLE_ERROR(
|
|
45
|
-
Object.keys(addedCollections)[0],
|
|
46
|
-
Object.keys(notDeprecatedDroppedTables)[0]
|
|
47
|
-
)
|
|
45
|
+
RENAME_TABLE_ERROR(Object.keys(addedTables)[0], Object.keys(notDeprecatedDroppedTables)[0])
|
|
48
46
|
);
|
|
49
47
|
}
|
|
50
|
-
for (const [
|
|
51
|
-
queries.push(getCreateTableQuery(
|
|
52
|
-
queries.push(...getCreateIndexQueries(
|
|
48
|
+
for (const [tableName, table] of Object.entries(addedTables)) {
|
|
49
|
+
queries.push(getCreateTableQuery(tableName, table));
|
|
50
|
+
queries.push(...getCreateIndexQueries(tableName, table));
|
|
53
51
|
}
|
|
54
|
-
for (const [
|
|
55
|
-
const dropQuery = `DROP TABLE ${sqlite.escapeName(
|
|
52
|
+
for (const [tableName] of Object.entries(droppedTables)) {
|
|
53
|
+
const dropQuery = `DROP TABLE ${sqlite.escapeName(tableName)}`;
|
|
56
54
|
queries.push(dropQuery);
|
|
57
55
|
}
|
|
58
|
-
for (const [
|
|
59
|
-
const
|
|
60
|
-
if (!
|
|
56
|
+
for (const [tableName, newTable] of Object.entries(newSnapshot.schema)) {
|
|
57
|
+
const oldTable = oldSnapshot.schema[tableName];
|
|
58
|
+
if (!oldTable)
|
|
61
59
|
continue;
|
|
62
|
-
const addedColumns = getAdded(
|
|
63
|
-
const droppedColumns = getDropped(
|
|
60
|
+
const addedColumns = getAdded(oldTable.columns, newTable.columns);
|
|
61
|
+
const droppedColumns = getDropped(oldTable.columns, newTable.columns);
|
|
64
62
|
const notDeprecatedDroppedColumns = Object.fromEntries(
|
|
65
63
|
Object.entries(droppedColumns).filter(([, col]) => !col.schema.deprecated)
|
|
66
64
|
);
|
|
67
65
|
if (!isEmpty(addedColumns) && !isEmpty(notDeprecatedDroppedColumns)) {
|
|
68
66
|
throw new Error(
|
|
69
67
|
RENAME_COLUMN_ERROR(
|
|
70
|
-
`${
|
|
71
|
-
`${
|
|
68
|
+
`${tableName}.${Object.keys(addedColumns)[0]}`,
|
|
69
|
+
`${tableName}.${Object.keys(notDeprecatedDroppedColumns)[0]}`
|
|
72
70
|
)
|
|
73
71
|
);
|
|
74
72
|
}
|
|
75
|
-
const result = await
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
73
|
+
const result = await getTableChangeQueries({
|
|
74
|
+
tableName,
|
|
75
|
+
oldTable,
|
|
76
|
+
newTable
|
|
79
77
|
});
|
|
80
78
|
queries.push(...result.queries);
|
|
81
79
|
confirmations.push(...result.confirmations);
|
|
82
80
|
}
|
|
83
81
|
return { queries, confirmations };
|
|
84
82
|
}
|
|
85
|
-
async function
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
83
|
+
async function getTableChangeQueries({
|
|
84
|
+
tableName,
|
|
85
|
+
oldTable,
|
|
86
|
+
newTable
|
|
89
87
|
}) {
|
|
90
88
|
const queries = [];
|
|
91
89
|
const confirmations = [];
|
|
92
|
-
const updated = getUpdatedColumns(
|
|
93
|
-
const added = getAdded(
|
|
94
|
-
const dropped = getDropped(
|
|
95
|
-
const hasForeignKeyChanges = Boolean(
|
|
96
|
-
deepDiff(oldCollection.foreignKeys, newCollection.foreignKeys)
|
|
97
|
-
);
|
|
90
|
+
const updated = getUpdatedColumns(oldTable.columns, newTable.columns);
|
|
91
|
+
const added = getAdded(oldTable.columns, newTable.columns);
|
|
92
|
+
const dropped = getDropped(oldTable.columns, newTable.columns);
|
|
93
|
+
const hasForeignKeyChanges = Boolean(deepDiff(oldTable.foreignKeys, newTable.foreignKeys));
|
|
98
94
|
if (!hasForeignKeyChanges && isEmpty(updated) && isEmpty(added) && isEmpty(dropped)) {
|
|
99
95
|
return {
|
|
100
96
|
queries: getChangeIndexQueries({
|
|
101
|
-
|
|
102
|
-
oldIndexes:
|
|
103
|
-
newIndexes:
|
|
97
|
+
tableName,
|
|
98
|
+
oldIndexes: oldTable.indexes,
|
|
99
|
+
newIndexes: newTable.indexes
|
|
104
100
|
}),
|
|
105
101
|
confirmations
|
|
106
102
|
};
|
|
107
103
|
}
|
|
108
104
|
if (!hasForeignKeyChanges && isEmpty(updated) && Object.values(dropped).every(canAlterTableDropColumn) && Object.values(added).every(canAlterTableAddColumn)) {
|
|
109
105
|
queries.push(
|
|
110
|
-
...getAlterTableQueries(
|
|
106
|
+
...getAlterTableQueries(tableName, added, dropped),
|
|
111
107
|
...getChangeIndexQueries({
|
|
112
|
-
|
|
113
|
-
oldIndexes:
|
|
114
|
-
newIndexes:
|
|
108
|
+
tableName,
|
|
109
|
+
oldIndexes: oldTable.indexes,
|
|
110
|
+
newIndexes: newTable.indexes
|
|
115
111
|
})
|
|
116
112
|
);
|
|
117
113
|
return { queries, confirmations };
|
|
@@ -121,31 +117,31 @@ async function getCollectionChangeQueries({
|
|
|
121
117
|
const { reason, columnName } = dataLossCheck;
|
|
122
118
|
const reasonMsgs = {
|
|
123
119
|
"added-required": `You added new required column '${color.bold(
|
|
124
|
-
|
|
120
|
+
tableName + "." + columnName
|
|
125
121
|
)}' with no default value.
|
|
126
122
|
This cannot be executed on an existing table.`,
|
|
127
123
|
"updated-type": `Updating existing column ${color.bold(
|
|
128
|
-
|
|
124
|
+
tableName + "." + columnName
|
|
129
125
|
)} to a new type that cannot be handled automatically.`
|
|
130
126
|
};
|
|
131
127
|
confirmations.push(reasonMsgs[reason]);
|
|
132
128
|
}
|
|
133
|
-
const primaryKeyExists = Object.entries(
|
|
129
|
+
const primaryKeyExists = Object.entries(newTable.columns).find(
|
|
134
130
|
([, column]) => hasPrimaryKey(column)
|
|
135
131
|
);
|
|
136
132
|
const droppedPrimaryKey = Object.entries(dropped).find(([, column]) => hasPrimaryKey(column));
|
|
137
133
|
const recreateTableQueries = getRecreateTableQueries({
|
|
138
|
-
|
|
139
|
-
|
|
134
|
+
tableName,
|
|
135
|
+
newTable,
|
|
140
136
|
added,
|
|
141
137
|
hasDataLoss: dataLossCheck.dataLoss,
|
|
142
138
|
migrateHiddenPrimaryKey: !primaryKeyExists && !droppedPrimaryKey
|
|
143
139
|
});
|
|
144
|
-
queries.push(...recreateTableQueries, ...getCreateIndexQueries(
|
|
140
|
+
queries.push(...recreateTableQueries, ...getCreateIndexQueries(tableName, newTable));
|
|
145
141
|
return { queries, confirmations };
|
|
146
142
|
}
|
|
147
143
|
function getChangeIndexQueries({
|
|
148
|
-
|
|
144
|
+
tableName,
|
|
149
145
|
oldIndexes = {},
|
|
150
146
|
newIndexes = {}
|
|
151
147
|
}) {
|
|
@@ -159,32 +155,32 @@ function getChangeIndexQueries({
|
|
|
159
155
|
const dropQuery = `DROP INDEX ${sqlite.escapeName(indexName)}`;
|
|
160
156
|
queries.push(dropQuery);
|
|
161
157
|
}
|
|
162
|
-
queries.push(...getCreateIndexQueries(
|
|
158
|
+
queries.push(...getCreateIndexQueries(tableName, { indexes: added }));
|
|
163
159
|
return queries;
|
|
164
160
|
}
|
|
165
|
-
function
|
|
161
|
+
function getAddedTables(oldTables, newTables) {
|
|
166
162
|
const added = {};
|
|
167
|
-
for (const [key,
|
|
168
|
-
if (!(key in
|
|
169
|
-
added[key] =
|
|
163
|
+
for (const [key, newTable] of Object.entries(newTables.schema)) {
|
|
164
|
+
if (!(key in oldTables.schema))
|
|
165
|
+
added[key] = newTable;
|
|
170
166
|
}
|
|
171
167
|
return added;
|
|
172
168
|
}
|
|
173
|
-
function
|
|
169
|
+
function getDroppedTables(oldTables, newTables) {
|
|
174
170
|
const dropped = {};
|
|
175
|
-
for (const [key,
|
|
176
|
-
if (!(key in
|
|
177
|
-
dropped[key] =
|
|
171
|
+
for (const [key, oldTable] of Object.entries(oldTables.schema)) {
|
|
172
|
+
if (!(key in newTables.schema))
|
|
173
|
+
dropped[key] = oldTable;
|
|
178
174
|
}
|
|
179
175
|
return dropped;
|
|
180
176
|
}
|
|
181
|
-
function getAlterTableQueries(
|
|
177
|
+
function getAlterTableQueries(unescTableName, added, dropped) {
|
|
182
178
|
const queries = [];
|
|
183
|
-
const
|
|
179
|
+
const tableName = sqlite.escapeName(unescTableName);
|
|
184
180
|
for (const [unescColumnName, column] of Object.entries(added)) {
|
|
185
181
|
const columnName = sqlite.escapeName(unescColumnName);
|
|
186
182
|
const type = schemaTypeToSqlType(column.type);
|
|
187
|
-
const q = `ALTER TABLE ${
|
|
183
|
+
const q = `ALTER TABLE ${tableName} ADD COLUMN ${columnName} ${type}${getModifiers(
|
|
188
184
|
columnName,
|
|
189
185
|
column
|
|
190
186
|
)}`;
|
|
@@ -192,37 +188,34 @@ function getAlterTableQueries(unescapedCollectionName, added, dropped) {
|
|
|
192
188
|
}
|
|
193
189
|
for (const unescColumnName of Object.keys(dropped)) {
|
|
194
190
|
const columnName = sqlite.escapeName(unescColumnName);
|
|
195
|
-
const q = `ALTER TABLE ${
|
|
191
|
+
const q = `ALTER TABLE ${tableName} DROP COLUMN ${columnName}`;
|
|
196
192
|
queries.push(q);
|
|
197
193
|
}
|
|
198
194
|
return queries;
|
|
199
195
|
}
|
|
200
196
|
function getRecreateTableQueries({
|
|
201
|
-
|
|
202
|
-
|
|
197
|
+
tableName: unescTableName,
|
|
198
|
+
newTable,
|
|
203
199
|
added,
|
|
204
200
|
hasDataLoss,
|
|
205
201
|
migrateHiddenPrimaryKey
|
|
206
202
|
}) {
|
|
207
|
-
const unescTempName = `${
|
|
203
|
+
const unescTempName = `${unescTableName}_${genTempTableName()}`;
|
|
208
204
|
const tempName = sqlite.escapeName(unescTempName);
|
|
209
|
-
const
|
|
205
|
+
const tableName = sqlite.escapeName(unescTableName);
|
|
210
206
|
if (hasDataLoss) {
|
|
211
|
-
return [
|
|
212
|
-
`DROP TABLE ${collectionName}`,
|
|
213
|
-
getCreateTableQuery(unescCollectionName, newCollection)
|
|
214
|
-
];
|
|
207
|
+
return [`DROP TABLE ${tableName}`, getCreateTableQuery(unescTableName, newTable)];
|
|
215
208
|
}
|
|
216
|
-
const newColumns = [...Object.keys(
|
|
209
|
+
const newColumns = [...Object.keys(newTable.columns)];
|
|
217
210
|
if (migrateHiddenPrimaryKey) {
|
|
218
211
|
newColumns.unshift("_id");
|
|
219
212
|
}
|
|
220
213
|
const escapedColumns = newColumns.filter((i) => !(i in added)).map((c) => sqlite.escapeName(c)).join(", ");
|
|
221
214
|
return [
|
|
222
|
-
getCreateTableQuery(unescTempName,
|
|
223
|
-
`INSERT INTO ${tempName} (${escapedColumns}) SELECT ${escapedColumns} FROM ${
|
|
224
|
-
`DROP TABLE ${
|
|
225
|
-
`ALTER TABLE ${tempName} RENAME TO ${
|
|
215
|
+
getCreateTableQuery(unescTempName, newTable),
|
|
216
|
+
`INSERT INTO ${tempName} (${escapedColumns}) SELECT ${escapedColumns} FROM ${tableName}`,
|
|
217
|
+
`DROP TABLE ${tableName}`,
|
|
218
|
+
`ALTER TABLE ${tempName} RENAME TO ${tableName}`
|
|
226
219
|
];
|
|
227
220
|
}
|
|
228
221
|
function isEmpty(obj) {
|
|
@@ -354,8 +347,8 @@ async function getProductionCurrentSnapshot({
|
|
|
354
347
|
}
|
|
355
348
|
function getDropTableQueriesForSnapshot(snapshot) {
|
|
356
349
|
const queries = [];
|
|
357
|
-
for (const
|
|
358
|
-
const dropQuery =
|
|
350
|
+
for (const tableName of Object.keys(snapshot.schema)) {
|
|
351
|
+
const dropQuery = getDropTableIfExistsQuery(tableName);
|
|
359
352
|
queries.unshift(dropQuery);
|
|
360
353
|
}
|
|
361
354
|
return queries;
|
|
@@ -387,7 +380,7 @@ export {
|
|
|
387
380
|
createCurrentSnapshot,
|
|
388
381
|
createEmptySnapshot,
|
|
389
382
|
formatDataLossMessage,
|
|
390
|
-
getCollectionChangeQueries,
|
|
391
383
|
getMigrationQueries,
|
|
392
|
-
getProductionCurrentSnapshot
|
|
384
|
+
getProductionCurrentSnapshot,
|
|
385
|
+
getTableChangeQueries
|
|
393
386
|
};
|
package/dist/core/errors.d.ts
CHANGED
|
@@ -5,12 +5,6 @@ export declare const RENAME_TABLE_ERROR: (oldTable: string, newTable: string) =>
|
|
|
5
5
|
export declare const RENAME_COLUMN_ERROR: (oldSelector: string, newSelector: string) => string;
|
|
6
6
|
export declare const FILE_NOT_FOUND_ERROR: (path: string) => string;
|
|
7
7
|
export declare const SHELL_QUERY_MISSING_ERROR: string;
|
|
8
|
-
export declare const SEED_ERROR: (error: string) => string;
|
|
9
8
|
export declare const EXEC_ERROR: (error: string) => string;
|
|
10
|
-
export declare const SEED_DEFAULT_EXPORT_ERROR: (fileName: string) => string;
|
|
11
9
|
export declare const EXEC_DEFAULT_EXPORT_ERROR: (fileName: string) => string;
|
|
12
|
-
export declare const REFERENCE_DNE_ERROR: (columnName: string) => string;
|
|
13
|
-
export declare const FOREIGN_KEY_DNE_ERROR: (tableName: string) => string;
|
|
14
|
-
export declare const FOREIGN_KEY_REFERENCES_LENGTH_ERROR: (tableName: string) => string;
|
|
15
|
-
export declare const FOREIGN_KEY_REFERENCES_EMPTY_ERROR: (tableName: string) => string;
|
|
16
10
|
export declare const INTEGRATION_TABLE_CONFLICT_ERROR: (integrationName: string, tableName: string, isUserConflict: boolean) => string;
|
package/dist/core/errors.js
CHANGED
|
@@ -29,42 +29,14 @@ const SHELL_QUERY_MISSING_ERROR = `${red(
|
|
|
29
29
|
"\u25B6 Please provide a query to execute using the --query flag."
|
|
30
30
|
)}
|
|
31
31
|
`;
|
|
32
|
-
const SEED_ERROR = (error) => {
|
|
33
|
-
return `${red(`Error while seeding database:`)}
|
|
34
|
-
|
|
35
|
-
${error}`;
|
|
36
|
-
};
|
|
37
32
|
const EXEC_ERROR = (error) => {
|
|
38
33
|
return `${red(`Error while executing file:`)}
|
|
39
34
|
|
|
40
35
|
${error}`;
|
|
41
36
|
};
|
|
42
|
-
const SEED_DEFAULT_EXPORT_ERROR = (fileName) => {
|
|
43
|
-
return SEED_ERROR(`Missing default function export in ${bold(fileName)}`);
|
|
44
|
-
};
|
|
45
37
|
const EXEC_DEFAULT_EXPORT_ERROR = (fileName) => {
|
|
46
38
|
return EXEC_ERROR(`Missing default function export in ${bold(fileName)}`);
|
|
47
39
|
};
|
|
48
|
-
const REFERENCE_DNE_ERROR = (columnName) => {
|
|
49
|
-
return `Column ${bold(
|
|
50
|
-
columnName
|
|
51
|
-
)} references a table that does not exist. Did you apply the referenced table to the \`tables\` object in your db config?`;
|
|
52
|
-
};
|
|
53
|
-
const FOREIGN_KEY_DNE_ERROR = (tableName) => {
|
|
54
|
-
return `Table ${bold(
|
|
55
|
-
tableName
|
|
56
|
-
)} references a table that does not exist. Did you apply the referenced table to the \`tables\` object in your db config?`;
|
|
57
|
-
};
|
|
58
|
-
const FOREIGN_KEY_REFERENCES_LENGTH_ERROR = (tableName) => {
|
|
59
|
-
return `Foreign key on ${bold(
|
|
60
|
-
tableName
|
|
61
|
-
)} is misconfigured. \`columns\` and \`references\` must be the same length.`;
|
|
62
|
-
};
|
|
63
|
-
const FOREIGN_KEY_REFERENCES_EMPTY_ERROR = (tableName) => {
|
|
64
|
-
return `Foreign key on ${bold(
|
|
65
|
-
tableName
|
|
66
|
-
)} is misconfigured. \`references\` array cannot be empty.`;
|
|
67
|
-
};
|
|
68
40
|
const INTEGRATION_TABLE_CONFLICT_ERROR = (integrationName, tableName, isUserConflict) => {
|
|
69
41
|
return red("\u25B6 Conflicting table name in integration " + bold(integrationName)) + isUserConflict ? `
|
|
70
42
|
A user-defined table named ${bold(tableName)} already exists` : `
|
|
@@ -74,17 +46,11 @@ export {
|
|
|
74
46
|
EXEC_DEFAULT_EXPORT_ERROR,
|
|
75
47
|
EXEC_ERROR,
|
|
76
48
|
FILE_NOT_FOUND_ERROR,
|
|
77
|
-
FOREIGN_KEY_DNE_ERROR,
|
|
78
|
-
FOREIGN_KEY_REFERENCES_EMPTY_ERROR,
|
|
79
|
-
FOREIGN_KEY_REFERENCES_LENGTH_ERROR,
|
|
80
49
|
INTEGRATION_TABLE_CONFLICT_ERROR,
|
|
81
50
|
MISSING_EXECUTE_PATH_ERROR,
|
|
82
51
|
MISSING_PROJECT_ID_ERROR,
|
|
83
52
|
MISSING_SESSION_ID_ERROR,
|
|
84
|
-
REFERENCE_DNE_ERROR,
|
|
85
53
|
RENAME_COLUMN_ERROR,
|
|
86
54
|
RENAME_TABLE_ERROR,
|
|
87
|
-
SEED_DEFAULT_EXPORT_ERROR,
|
|
88
|
-
SEED_ERROR,
|
|
89
55
|
SHELL_QUERY_MISSING_ERROR
|
|
90
56
|
};
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { existsSync } from "fs";
|
|
2
2
|
import { dirname } from "path";
|
|
3
3
|
import { fileURLToPath } from "url";
|
|
4
|
+
import { AstroError } from "astro/errors";
|
|
4
5
|
import { mkdir, writeFile } from "fs/promises";
|
|
5
6
|
import { blue, yellow } from "kleur/colors";
|
|
7
|
+
import { loadEnv } from "vite";
|
|
6
8
|
import parseArgs from "yargs-parser";
|
|
7
9
|
import { CONFIG_FILE_NAMES, DB_PATH } from "../consts.js";
|
|
8
10
|
import { resolveDbConfig } from "../load-file.js";
|
|
@@ -28,12 +30,14 @@ function astroDBIntegration() {
|
|
|
28
30
|
}
|
|
29
31
|
};
|
|
30
32
|
let command;
|
|
33
|
+
let output = "server";
|
|
31
34
|
return {
|
|
32
35
|
name: "astro:db",
|
|
33
36
|
hooks: {
|
|
34
37
|
"astro:config:setup": async ({ updateConfig, config, command: _command, logger }) => {
|
|
35
38
|
command = _command;
|
|
36
39
|
root = config.root;
|
|
40
|
+
output = config.output;
|
|
37
41
|
if (command === "preview")
|
|
38
42
|
return;
|
|
39
43
|
let dbPlugin = void 0;
|
|
@@ -98,6 +102,11 @@ function astroDBIntegration() {
|
|
|
98
102
|
});
|
|
99
103
|
},
|
|
100
104
|
"astro:build:start": async ({ logger }) => {
|
|
105
|
+
if (!connectToStudio && !databaseFileEnvDefined() && (output === "server" || output === "hybrid")) {
|
|
106
|
+
const message = `Attempting to build without the --remote flag or the ASTRO_DATABASE_FILE environment variable defined. You probably want to pass --remote to astro build.`;
|
|
107
|
+
const hint = "Learn more connecting to Studio: https://docs.astro.build/en/guides/astro-db/#connect-to-astro-studio";
|
|
108
|
+
throw new AstroError(message, hint);
|
|
109
|
+
}
|
|
101
110
|
logger.info("database: " + (connectToStudio ? yellow("remote") : blue("local database.")));
|
|
102
111
|
},
|
|
103
112
|
"astro:build:done": async ({}) => {
|
|
@@ -106,6 +115,10 @@ function astroDBIntegration() {
|
|
|
106
115
|
}
|
|
107
116
|
};
|
|
108
117
|
}
|
|
118
|
+
function databaseFileEnvDefined() {
|
|
119
|
+
const env = loadEnv("", process.cwd());
|
|
120
|
+
return env.ASTRO_DATABASE_FILE != null || process.env.ASTRO_DATABASE_FILE != null;
|
|
121
|
+
}
|
|
109
122
|
function integration() {
|
|
110
123
|
return [astroDBIntegration(), fileURLIntegration()];
|
|
111
124
|
}
|
|
@@ -9,7 +9,7 @@ async function typegen(astroConfig) {
|
|
|
9
9
|
async function typegenInternal({ tables, root }) {
|
|
10
10
|
const content = `// This file is generated by Astro DB
|
|
11
11
|
declare module 'astro:db' {
|
|
12
|
-
${Object.entries(tables).map(([name,
|
|
12
|
+
${Object.entries(tables).map(([name, table]) => generateTableType(name, table)).join("\n")}
|
|
13
13
|
}
|
|
14
14
|
`;
|
|
15
15
|
const dotAstroDir = new URL(".astro/", root);
|
|
@@ -18,8 +18,8 @@ ${Object.entries(tables).map(([name, collection]) => generateTableType(name, col
|
|
|
18
18
|
}
|
|
19
19
|
await writeFile(new URL(DB_TYPES_FILE, dotAstroDir), content);
|
|
20
20
|
}
|
|
21
|
-
function generateTableType(name,
|
|
22
|
-
const sanitizedColumnsList = Object.entries(
|
|
21
|
+
function generateTableType(name, table) {
|
|
22
|
+
const sanitizedColumnsList = Object.entries(table.columns).filter(([, val]) => !val.schema.deprecated);
|
|
23
23
|
const sanitizedColumns = Object.fromEntries(sanitizedColumnsList);
|
|
24
24
|
let tableType = ` export const ${name}: import(${RUNTIME_IMPORT}).Table<
|
|
25
25
|
${JSON.stringify(name)},
|
|
@@ -78,7 +78,8 @@ import { asDrizzleTable, createLocalDatabaseClient } from ${RUNTIME_IMPORT};
|
|
|
78
78
|
${shouldSeed ? `import { seedLocal } from ${RUNTIME_IMPORT};` : ""}
|
|
79
79
|
${shouldSeed ? integrationSeedImportStatements.join("\n") : ""}
|
|
80
80
|
|
|
81
|
-
const dbUrl = ${JSON.stringify(dbUrl)};
|
|
81
|
+
const dbUrl = import.meta.env.ASTRO_DATABASE_FILE ?? ${JSON.stringify(dbUrl)};
|
|
82
|
+
|
|
82
83
|
export const db = createLocalDatabaseClient({ dbUrl });
|
|
83
84
|
|
|
84
85
|
${shouldSeed ? `await seedLocal({
|
|
@@ -90,7 +91,7 @@ ${shouldSeed ? `await seedLocal({
|
|
|
90
91
|
|
|
91
92
|
export * from ${RUNTIME_CONFIG_IMPORT};
|
|
92
93
|
|
|
93
|
-
${
|
|
94
|
+
${getStringifiedTableExports(tables)}`;
|
|
94
95
|
}
|
|
95
96
|
function getStudioVirtualModContents({
|
|
96
97
|
tables,
|
|
@@ -115,13 +116,13 @@ export const db = await createRemoteDatabaseClient(${appTokenArg()}, ${dbUrlArg(
|
|
|
115
116
|
|
|
116
117
|
export * from ${RUNTIME_CONFIG_IMPORT};
|
|
117
118
|
|
|
118
|
-
${
|
|
119
|
+
${getStringifiedTableExports(tables)}
|
|
119
120
|
`;
|
|
120
121
|
}
|
|
121
|
-
function
|
|
122
|
+
function getStringifiedTableExports(tables) {
|
|
122
123
|
return Object.entries(tables).map(
|
|
123
|
-
([name,
|
|
124
|
-
|
|
124
|
+
([name, table]) => `export const ${name} = asDrizzleTable(${JSON.stringify(name)}, ${JSON.stringify(
|
|
125
|
+
table
|
|
125
126
|
)}, false)`
|
|
126
127
|
).join("\n");
|
|
127
128
|
}
|
package/dist/core/schemas.js
CHANGED
|
@@ -15,9 +15,9 @@ const baseColumnSchema = z.object({
|
|
|
15
15
|
optional: z.boolean().optional().default(false),
|
|
16
16
|
unique: z.boolean().optional().default(false),
|
|
17
17
|
deprecated: z.boolean().optional().default(false),
|
|
18
|
-
// Defined when `
|
|
18
|
+
// Defined when `defineDb()` is called to resolve `references`
|
|
19
19
|
name: z.string().optional(),
|
|
20
|
-
// TODO:
|
|
20
|
+
// TODO: Update to `table`. Will need migration file version change
|
|
21
21
|
collection: z.string().optional()
|
|
22
22
|
});
|
|
23
23
|
const booleanColumnSchema = z.object({
|
package/dist/core/types.d.ts
CHANGED
|
@@ -38,8 +38,6 @@ export interface TableConfig<TColumns extends ColumnsConfig = ColumnsConfig> ext
|
|
|
38
38
|
interface IndexConfig<TColumns extends ColumnsConfig> extends z.input<typeof indexSchema> {
|
|
39
39
|
on: MaybeArray<Extract<keyof TColumns, string>>;
|
|
40
40
|
}
|
|
41
|
-
/** @deprecated Use `TableConfig` instead */
|
|
42
|
-
export type ResolvedCollectionConfig<TColumns extends ColumnsConfig = ColumnsConfig> = TableConfig<TColumns>;
|
|
43
41
|
export type NumberColumnOpts = z.input<typeof numberColumnOptsSchema>;
|
|
44
42
|
export type TextColumnOpts = z.input<typeof textColumnOptsSchema>;
|
|
45
43
|
export type AstroDbIntegration = AstroIntegration & {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type {
|
|
1
|
+
export type { TableConfig } from './core/types.js';
|
|
2
2
|
export { cli } from './core/cli/index.js';
|
|
3
3
|
export { integration as default } from './core/integration/index.js';
|
|
4
4
|
export { typegen } from './core/integration/typegen.js';
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare const FOREIGN_KEY_DNE_ERROR: (tableName: string) => string;
|
|
2
|
+
export declare const FOREIGN_KEY_REFERENCES_LENGTH_ERROR: (tableName: string) => string;
|
|
3
|
+
export declare const FOREIGN_KEY_REFERENCES_EMPTY_ERROR: (tableName: string) => string;
|
|
4
|
+
export declare const REFERENCE_DNE_ERROR: (columnName: string) => string;
|
|
5
|
+
export declare const SEED_ERROR: (error: string) => string;
|
|
6
|
+
export declare const SEED_DEFAULT_EXPORT_ERROR: (fileName: string) => string;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { bold, red } from "kleur/colors";
|
|
2
|
+
const FOREIGN_KEY_DNE_ERROR = (tableName) => {
|
|
3
|
+
return `Table ${bold(
|
|
4
|
+
tableName
|
|
5
|
+
)} references a table that does not exist. Did you apply the referenced table to the \`tables\` object in your db config?`;
|
|
6
|
+
};
|
|
7
|
+
const FOREIGN_KEY_REFERENCES_LENGTH_ERROR = (tableName) => {
|
|
8
|
+
return `Foreign key on ${bold(
|
|
9
|
+
tableName
|
|
10
|
+
)} is misconfigured. \`columns\` and \`references\` must be the same length.`;
|
|
11
|
+
};
|
|
12
|
+
const FOREIGN_KEY_REFERENCES_EMPTY_ERROR = (tableName) => {
|
|
13
|
+
return `Foreign key on ${bold(
|
|
14
|
+
tableName
|
|
15
|
+
)} is misconfigured. \`references\` array cannot be empty.`;
|
|
16
|
+
};
|
|
17
|
+
const REFERENCE_DNE_ERROR = (columnName) => {
|
|
18
|
+
return `Column ${bold(
|
|
19
|
+
columnName
|
|
20
|
+
)} references a table that does not exist. Did you apply the referenced table to the \`tables\` object in your db config?`;
|
|
21
|
+
};
|
|
22
|
+
const SEED_ERROR = (error) => {
|
|
23
|
+
return `${red(`Error while seeding database:`)}
|
|
24
|
+
|
|
25
|
+
${error}`;
|
|
26
|
+
};
|
|
27
|
+
const SEED_DEFAULT_EXPORT_ERROR = (fileName) => {
|
|
28
|
+
return SEED_ERROR(`Missing default function export in ${bold(fileName)}`);
|
|
29
|
+
};
|
|
30
|
+
export {
|
|
31
|
+
FOREIGN_KEY_DNE_ERROR,
|
|
32
|
+
FOREIGN_KEY_REFERENCES_EMPTY_ERROR,
|
|
33
|
+
FOREIGN_KEY_REFERENCES_LENGTH_ERROR,
|
|
34
|
+
REFERENCE_DNE_ERROR,
|
|
35
|
+
SEED_DEFAULT_EXPORT_ERROR,
|
|
36
|
+
SEED_ERROR
|
|
37
|
+
};
|
package/dist/runtime/queries.js
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
FOREIGN_KEY_REFERENCES_EMPTY_ERROR,
|
|
7
7
|
FOREIGN_KEY_REFERENCES_LENGTH_ERROR,
|
|
8
8
|
REFERENCE_DNE_ERROR
|
|
9
|
-
} from "
|
|
9
|
+
} from "./errors.js";
|
|
10
10
|
import { hasPrimaryKey } from "./index.js";
|
|
11
11
|
import { isSerializedSQL } from "./types.js";
|
|
12
12
|
const sqlite = new SQLiteAsyncDialect();
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { LibsqlError } from "@libsql/client";
|
|
2
2
|
import { sql } from "drizzle-orm";
|
|
3
3
|
import { SQLiteAsyncDialect } from "drizzle-orm/sqlite-core";
|
|
4
|
-
import { SEED_DEFAULT_EXPORT_ERROR, SEED_ERROR } from "../core/errors.js";
|
|
5
4
|
import {} from "../core/types.js";
|
|
5
|
+
import { SEED_DEFAULT_EXPORT_ERROR, SEED_ERROR } from "./errors.js";
|
|
6
6
|
import { getCreateIndexQueries, getCreateTableQuery } from "./queries.js";
|
|
7
7
|
const sqlite = new SQLiteAsyncDialect();
|
|
8
8
|
async function seedLocal({
|