@astrojs/db 0.1.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.
Files changed (56) hide show
  1. package/LICENSE +59 -0
  2. package/components/Renderer.astro +14 -0
  3. package/components/astro-env.d.ts +1 -0
  4. package/components/index.ts +2 -0
  5. package/components/tsconfig.json +7 -0
  6. package/config-augment.d.ts +4 -0
  7. package/dist/cli/commands/push/index.d.ts +6 -0
  8. package/dist/cli/commands/push/index.js +144 -0
  9. package/dist/cli/commands/sync/index.d.ts +6 -0
  10. package/dist/cli/commands/sync/index.js +45 -0
  11. package/dist/cli/commands/verify/index.d.ts +6 -0
  12. package/dist/cli/commands/verify/index.js +25 -0
  13. package/dist/cli/index.d.ts +6 -0
  14. package/dist/cli/index.js +24 -0
  15. package/dist/cli/queries.d.ts +19 -0
  16. package/dist/cli/queries.js +453 -0
  17. package/dist/cli/seed.d.ts +6 -0
  18. package/dist/cli/sync/admin.d.ts +33 -0
  19. package/dist/cli/sync/index.d.ts +1 -0
  20. package/dist/cli/sync/index.js +0 -0
  21. package/dist/cli/sync/migrate.d.ts +1 -0
  22. package/dist/cli/sync/migrate.js +0 -0
  23. package/dist/cli/sync/queries.d.ts +19 -0
  24. package/dist/cli/sync/remote-db.d.ts +1 -0
  25. package/dist/config.d.ts +1149 -0
  26. package/dist/config.js +53 -0
  27. package/dist/consts.d.ts +6 -0
  28. package/dist/consts.js +19 -0
  29. package/dist/error-map.d.ts +6 -0
  30. package/dist/error-map.js +79 -0
  31. package/dist/errors.d.ts +3 -0
  32. package/dist/errors.js +15 -0
  33. package/dist/index.d.ts +3 -0
  34. package/dist/index.js +10 -0
  35. package/dist/integration.d.ts +2 -0
  36. package/dist/integration.js +68 -0
  37. package/dist/internal-drizzle.d.ts +1 -0
  38. package/dist/internal-drizzle.js +48 -0
  39. package/dist/internal.d.ts +50 -0
  40. package/dist/internal.js +250 -0
  41. package/dist/load-astro-config.d.ts +6 -0
  42. package/dist/load-astro-config.js +79 -0
  43. package/dist/migrations.d.ts +9 -0
  44. package/dist/migrations.js +41 -0
  45. package/dist/typegen.d.ts +5 -0
  46. package/dist/typegen.js +57 -0
  47. package/dist/types.d.ts +1367 -0
  48. package/dist/types.js +58 -0
  49. package/dist/utils.d.ts +59 -0
  50. package/dist/utils.js +84 -0
  51. package/dist/vite-plugin-db.d.ts +19 -0
  52. package/dist/vite-plugin-db.js +66 -0
  53. package/dist/vite-plugin-inject-env-ts.d.ts +9 -0
  54. package/dist/vite-plugin-inject-env-ts.js +49 -0
  55. package/index.d.ts +3 -0
  56. package/package.json +72 -0
package/dist/config.js ADDED
@@ -0,0 +1,53 @@
1
+ import {
2
+ collectionsSchema
3
+ } from "./types.js";
4
+ import { z } from "zod";
5
+ const dbConfigSchema = z.object({
6
+ studio: z.boolean().optional(),
7
+ collections: collectionsSchema.optional()
8
+ });
9
+ const astroConfigWithDbSchema = z.object({
10
+ db: dbConfigSchema.optional()
11
+ });
12
+ function defineCollection(userConfig) {
13
+ return {
14
+ ...userConfig,
15
+ writable: false
16
+ };
17
+ }
18
+ function defineWritableCollection(userConfig) {
19
+ return {
20
+ ...userConfig,
21
+ writable: true
22
+ };
23
+ }
24
+ const baseDefaults = {
25
+ optional: false,
26
+ unique: false,
27
+ label: void 0,
28
+ default: void 0
29
+ };
30
+ const field = {
31
+ number(opts = {}) {
32
+ return { type: "number", ...baseDefaults, ...opts };
33
+ },
34
+ boolean(opts = {}) {
35
+ return { type: "boolean", ...baseDefaults, ...opts };
36
+ },
37
+ text(opts = {}) {
38
+ return { type: "text", multiline: false, ...baseDefaults, ...opts };
39
+ },
40
+ date(opts = {}) {
41
+ return { type: "date", ...baseDefaults, ...opts };
42
+ },
43
+ json(opts = {}) {
44
+ return { type: "json", ...baseDefaults, ...opts };
45
+ }
46
+ };
47
+ export {
48
+ astroConfigWithDbSchema,
49
+ dbConfigSchema,
50
+ defineCollection,
51
+ defineWritableCollection,
52
+ field
53
+ };
@@ -0,0 +1,6 @@
1
+ export declare const PACKAGE_NAME: any;
2
+ export declare const INTERNAL_MOD_IMPORT: string;
3
+ export declare const DRIZZLE_MOD_IMPORT: string;
4
+ export declare const DB_TYPES_FILE = "db-types.d.ts";
5
+ export declare const VIRTUAL_MODULE_ID = "astro:db";
6
+ export declare function getLocalDbUrl(root: URL): URL;
package/dist/consts.js ADDED
@@ -0,0 +1,19 @@
1
+ import { readFileSync } from "node:fs";
2
+ const PACKAGE_NAME = JSON.parse(
3
+ readFileSync(new URL("../package.json", import.meta.url), "utf8")
4
+ ).name;
5
+ const INTERNAL_MOD_IMPORT = JSON.stringify(`${PACKAGE_NAME}/internal`);
6
+ const DRIZZLE_MOD_IMPORT = JSON.stringify(`${PACKAGE_NAME}/internal-drizzle`);
7
+ const DB_TYPES_FILE = "db-types.d.ts";
8
+ const VIRTUAL_MODULE_ID = "astro:db";
9
+ function getLocalDbUrl(root) {
10
+ return new URL(".astro/content.db", root);
11
+ }
12
+ export {
13
+ DB_TYPES_FILE,
14
+ DRIZZLE_MOD_IMPORT,
15
+ INTERNAL_MOD_IMPORT,
16
+ PACKAGE_NAME,
17
+ VIRTUAL_MODULE_ID,
18
+ getLocalDbUrl
19
+ };
@@ -0,0 +1,6 @@
1
+ /**
2
+ * This is a modified version of Astro's error map. source:
3
+ * https://github.com/withastro/astro/blob/main/packages/astro/src/content/error-map.ts
4
+ */
5
+ import type { z } from 'astro/zod';
6
+ export declare const errorMap: z.ZodErrorMap;
@@ -0,0 +1,79 @@
1
+ const errorMap = (baseError, ctx) => {
2
+ const baseErrorPath = flattenErrorPath(baseError.path);
3
+ if (baseError.code === "invalid_union") {
4
+ const typeOrLiteralErrByPath = /* @__PURE__ */ new Map();
5
+ for (const unionError of baseError.unionErrors.flatMap((e) => e.errors)) {
6
+ if (unionError.code === "invalid_type" || unionError.code === "invalid_literal") {
7
+ const flattenedErrorPath = flattenErrorPath(unionError.path);
8
+ const typeOrLiteralErr = typeOrLiteralErrByPath.get(flattenedErrorPath);
9
+ if (typeOrLiteralErr) {
10
+ typeOrLiteralErr.expected.push(unionError.expected);
11
+ } else {
12
+ typeOrLiteralErrByPath.set(flattenedErrorPath, {
13
+ code: unionError.code,
14
+ received: unionError.received,
15
+ expected: [unionError.expected]
16
+ });
17
+ }
18
+ }
19
+ }
20
+ const messages = [
21
+ prefix(
22
+ baseErrorPath,
23
+ typeOrLiteralErrByPath.size ? "Did not match union:" : "Did not match union."
24
+ )
25
+ ];
26
+ return {
27
+ message: messages.concat(
28
+ [...typeOrLiteralErrByPath.entries()].filter(([, error]) => error.expected.length === baseError.unionErrors.length).map(
29
+ ([key, error]) => (
30
+ // Avoid printing the key again if it's a base error
31
+ key === baseErrorPath ? `> ${getTypeOrLiteralMsg(error)}` : `> ${prefix(key, getTypeOrLiteralMsg(error))}`
32
+ )
33
+ )
34
+ ).join("\n")
35
+ };
36
+ }
37
+ if (baseError.code === "invalid_literal" || baseError.code === "invalid_type") {
38
+ return {
39
+ message: prefix(
40
+ baseErrorPath,
41
+ getTypeOrLiteralMsg({
42
+ code: baseError.code,
43
+ received: baseError.received,
44
+ expected: [baseError.expected]
45
+ })
46
+ )
47
+ };
48
+ } else if (baseError.message) {
49
+ return { message: prefix(baseErrorPath, baseError.message) };
50
+ } else {
51
+ return { message: prefix(baseErrorPath, ctx.defaultError) };
52
+ }
53
+ };
54
+ const getTypeOrLiteralMsg = (error) => {
55
+ if (error.received === "undefined")
56
+ return "Required";
57
+ const expectedDeduped = new Set(error.expected);
58
+ switch (error.code) {
59
+ case "invalid_type":
60
+ return `Expected type \`${unionExpectedVals(expectedDeduped)}\`, received ${JSON.stringify(
61
+ error.received
62
+ )}`;
63
+ case "invalid_literal":
64
+ return `Expected \`${unionExpectedVals(expectedDeduped)}\`, received ${JSON.stringify(
65
+ error.received
66
+ )}`;
67
+ }
68
+ };
69
+ const prefix = (key, msg) => key.length ? `**${key}**: ${msg}` : msg;
70
+ const unionExpectedVals = (expectedVals) => [...expectedVals].map((expectedVal, idx) => {
71
+ if (idx === 0)
72
+ return JSON.stringify(expectedVal);
73
+ const sep = " | ";
74
+ return `${sep}${JSON.stringify(expectedVal)}`;
75
+ }).join("");
76
+ const flattenErrorPath = (errorPath) => errorPath.join(".");
77
+ export {
78
+ errorMap
79
+ };
@@ -0,0 +1,3 @@
1
+ export declare const unexpectedAstroAdminError: string;
2
+ export declare const authenticationError: string;
3
+ export declare const appTokenError: string;
package/dist/errors.js ADDED
@@ -0,0 +1,15 @@
1
+ import { red } from "kleur/colors";
2
+ const unexpectedAstroAdminError = `${red(
3
+ "Unexpected response from Astro Studio servers."
4
+ )} Try updating your package version. If the problem persists, please contact support.`;
5
+ const authenticationError = `${red(
6
+ "\u26A0\uFE0F Login session invalid or expired."
7
+ )} Please run \`astro login\` again.`;
8
+ const appTokenError = `${red(
9
+ "\u26A0\uFE0F App token invalid or expired."
10
+ )} Please generate a new one from your the Studio dashboard under project settings.`;
11
+ export {
12
+ appTokenError,
13
+ authenticationError,
14
+ unexpectedAstroAdminError
15
+ };
@@ -0,0 +1,3 @@
1
+ export { defineCollection, defineWritableCollection, field } from './config.js';
2
+ export { cli } from './cli/index.js';
3
+ export { integration as default } from './integration.js';
package/dist/index.js ADDED
@@ -0,0 +1,10 @@
1
+ import { defineCollection, defineWritableCollection, field } from "./config.js";
2
+ import { cli } from "./cli/index.js";
3
+ import { integration } from "./integration.js";
4
+ export {
5
+ cli,
6
+ integration as default,
7
+ defineCollection,
8
+ defineWritableCollection,
9
+ field
10
+ };
@@ -0,0 +1,2 @@
1
+ import type { AstroIntegration } from 'astro';
2
+ export declare function integration(): AstroIntegration;
@@ -0,0 +1,68 @@
1
+ import { vitePluginDb } from "./vite-plugin-db.js";
2
+ import { vitePluginInjectEnvTs } from "./vite-plugin-inject-env-ts.js";
3
+ import { typegen } from "./typegen.js";
4
+ import { existsSync } from "fs";
5
+ import { mkdir, rm, writeFile } from "fs/promises";
6
+ import { getLocalDbUrl } from "./consts.js";
7
+ import { createLocalDatabaseClient, setupDbTables } from "./internal.js";
8
+ import { astroConfigWithDbSchema } from "./config.js";
9
+ import { getAstroStudioEnv } from "./utils.js";
10
+ import { appTokenError } from "./errors.js";
11
+ import { errorMap } from "./error-map.js";
12
+ import { dirname } from "path";
13
+ import { fileURLToPath } from "url";
14
+ import { bold } from "kleur/colors";
15
+ function integration() {
16
+ return {
17
+ name: "astro:db",
18
+ hooks: {
19
+ async "astro:config:setup"({ logger, updateConfig, config, command }) {
20
+ if (command === "preview")
21
+ return;
22
+ const configWithDb = astroConfigWithDbSchema.parse(config, { errorMap });
23
+ const collections = configWithDb.db?.collections ?? {};
24
+ const studio = configWithDb.db?.studio ?? false;
25
+ if (!studio && Object.values(collections).some((c) => c.writable)) {
26
+ logger.warn(
27
+ `Writable collections should only be used with Astro Studio. Did you set the ${bold(
28
+ "studio"
29
+ )} flag in your astro config?`
30
+ );
31
+ }
32
+ let dbPlugin;
33
+ if (studio && command === "build") {
34
+ const appToken = getAstroStudioEnv().ASTRO_STUDIO_APP_TOKEN;
35
+ if (!appToken) {
36
+ logger.error(appTokenError);
37
+ process.exit(0);
38
+ }
39
+ dbPlugin = vitePluginDb({ connectToStudio: true, collections, appToken });
40
+ } else {
41
+ const dbUrl = getLocalDbUrl(config.root);
42
+ if (existsSync(dbUrl)) {
43
+ await rm(dbUrl);
44
+ }
45
+ await mkdir(dirname(fileURLToPath(dbUrl)), { recursive: true });
46
+ await writeFile(dbUrl, "");
47
+ const db = await createLocalDatabaseClient({
48
+ collections,
49
+ dbUrl: dbUrl.href,
50
+ seeding: true
51
+ });
52
+ await setupDbTables({ db, collections, logger });
53
+ logger.info("Collections set up \u{1F680}");
54
+ dbPlugin = vitePluginDb({ connectToStudio: false, collections, dbUrl: dbUrl.href });
55
+ }
56
+ updateConfig({
57
+ vite: {
58
+ plugins: [dbPlugin, vitePluginInjectEnvTs(config)]
59
+ }
60
+ });
61
+ await typegen({ collections, root: config.root });
62
+ }
63
+ }
64
+ };
65
+ }
66
+ export {
67
+ integration
68
+ };
@@ -0,0 +1 @@
1
+ export { sql, eq, gt, gte, lt, lte, ne, isNull, isNotNull, inArray, notInArray, exists, notExists, between, notBetween, like, notIlike, not, asc, desc, and, or, } from 'drizzle-orm';
@@ -0,0 +1,48 @@
1
+ import {
2
+ sql,
3
+ eq,
4
+ gt,
5
+ gte,
6
+ lt,
7
+ lte,
8
+ ne,
9
+ isNull,
10
+ isNotNull,
11
+ inArray,
12
+ notInArray,
13
+ exists,
14
+ notExists,
15
+ between,
16
+ notBetween,
17
+ like,
18
+ notIlike,
19
+ not,
20
+ asc,
21
+ desc,
22
+ and,
23
+ or
24
+ } from "drizzle-orm";
25
+ export {
26
+ and,
27
+ asc,
28
+ between,
29
+ desc,
30
+ eq,
31
+ exists,
32
+ gt,
33
+ gte,
34
+ inArray,
35
+ isNotNull,
36
+ isNull,
37
+ like,
38
+ lt,
39
+ lte,
40
+ ne,
41
+ not,
42
+ notBetween,
43
+ notExists,
44
+ notIlike,
45
+ notInArray,
46
+ or,
47
+ sql
48
+ };
@@ -0,0 +1,50 @@
1
+ import type { SqliteRemoteDatabase } from 'drizzle-orm/sqlite-proxy';
2
+ import { type DBCollection, type DBCollections } from './types.js';
3
+ import { type LibSQLDatabase } from 'drizzle-orm/libsql';
4
+ import { type ColumnDataType } from 'drizzle-orm';
5
+ import type { AstroIntegrationLogger } from 'astro';
6
+ export type SqliteDB = SqliteRemoteDatabase;
7
+ export type { AstroTable, AstroText, AstroDate, AstroBoolean, AstroNumber, AstroJson, AstroId, } from './types.js';
8
+ export { createRemoteDatabaseClient } from './utils.js';
9
+ export declare function createLocalDatabaseClient({ collections, dbUrl, seeding, }: {
10
+ dbUrl: string;
11
+ collections: DBCollections;
12
+ seeding: boolean;
13
+ }): Promise<LibSQLDatabase<Record<string, never>>>;
14
+ export declare function setupDbTables({ db, collections, logger, }: {
15
+ db: LibSQLDatabase;
16
+ collections: DBCollections;
17
+ logger: AstroIntegrationLogger;
18
+ }): Promise<void>;
19
+ export declare function getCreateTableQuery(collectionName: string, collection: DBCollection): string;
20
+ export declare function collectionToTable(name: string, collection: DBCollection, isJsonSerializable?: boolean): import("drizzle-orm/sqlite-core").SQLiteTableWithColumns<{
21
+ name: string;
22
+ schema: undefined;
23
+ columns: {
24
+ [x: string]: import("drizzle-orm/sqlite-core").SQLiteColumn<{
25
+ name: string;
26
+ tableName: string;
27
+ dataType: ColumnDataType;
28
+ columnType: string;
29
+ data: unknown;
30
+ driverParam: unknown;
31
+ notNull: false;
32
+ hasDefault: false;
33
+ enumValues: string[] | undefined;
34
+ baseColumn: never;
35
+ }, object>;
36
+ id: import("drizzle-orm/sqlite-core").SQLiteColumn<{
37
+ name: "id";
38
+ tableName: string;
39
+ dataType: "string";
40
+ columnType: "SQLiteText";
41
+ data: string;
42
+ driverParam: string;
43
+ notNull: true;
44
+ hasDefault: true;
45
+ enumValues: [string, ...string[]];
46
+ baseColumn: never;
47
+ }, object>;
48
+ };
49
+ dialect: "sqlite";
50
+ }>;
@@ -0,0 +1,250 @@
1
+ import { createClient } from "@libsql/client";
2
+ import {
3
+ } from "./types.js";
4
+ import { drizzle } from "drizzle-orm/libsql";
5
+ import { bold } from "kleur/colors";
6
+ import {
7
+ sql,
8
+ getTableName
9
+ } from "drizzle-orm";
10
+ import {
11
+ SQLiteAsyncDialect,
12
+ customType,
13
+ integer,
14
+ sqliteTable,
15
+ text
16
+ } from "drizzle-orm/sqlite-core";
17
+ import { z } from "zod";
18
+ import { nanoid } from "nanoid";
19
+ const sqlite = new SQLiteAsyncDialect();
20
+ function isReadableCollection(collection) {
21
+ return !collection.writable;
22
+ }
23
+ function checkIfModificationIsAllowed(collections, Table) {
24
+ const tableName = getTableName(Table);
25
+ const collection = collections[tableName];
26
+ if (!collection.writable) {
27
+ throw new Error(`The [${tableName}] collection is read-only.`);
28
+ }
29
+ }
30
+ import { createRemoteDatabaseClient } from "./utils.js";
31
+ async function createLocalDatabaseClient({
32
+ collections,
33
+ dbUrl,
34
+ seeding
35
+ }) {
36
+ const client = createClient({ url: dbUrl });
37
+ const db = drizzle(client);
38
+ if (seeding)
39
+ return db;
40
+ const { insert: drizzleInsert, update: drizzleUpdate, delete: drizzleDelete } = db;
41
+ return Object.assign(db, {
42
+ insert(Table) {
43
+ checkIfModificationIsAllowed(collections, Table);
44
+ return drizzleInsert.call(this, Table);
45
+ },
46
+ update(Table) {
47
+ checkIfModificationIsAllowed(collections, Table);
48
+ return drizzleUpdate.call(this, Table);
49
+ },
50
+ delete(Table) {
51
+ checkIfModificationIsAllowed(collections, Table);
52
+ return drizzleDelete.call(this, Table);
53
+ }
54
+ });
55
+ }
56
+ async function setupDbTables({
57
+ db,
58
+ collections,
59
+ logger
60
+ }) {
61
+ const setupQueries = [];
62
+ for (const [name, collection] of Object.entries(collections)) {
63
+ const dropQuery = sql.raw(`DROP TABLE IF EXISTS ${name}`);
64
+ const createQuery = sql.raw(getCreateTableQuery(name, collection));
65
+ setupQueries.push(dropQuery, createQuery);
66
+ }
67
+ for (const q of setupQueries) {
68
+ await db.run(q);
69
+ }
70
+ for (const [name, collection] of Object.entries(collections)) {
71
+ if (!isReadableCollection(collection) || !collection.data)
72
+ continue;
73
+ const table = collectionToTable(name, collection);
74
+ try {
75
+ await db.insert(table).values(await collection.data());
76
+ } catch (e) {
77
+ logger.error(
78
+ `Failed to seed ${bold(
79
+ name
80
+ )} data. Did you update to match recent schema changes? Full error:
81
+
82
+ ${e}`
83
+ );
84
+ }
85
+ }
86
+ }
87
+ function getCreateTableQuery(collectionName, collection) {
88
+ let query = `CREATE TABLE ${sqlite.escapeName(collectionName)} (`;
89
+ const colQueries = ['"id" text PRIMARY KEY'];
90
+ for (const [columnName, column] of Object.entries(collection.fields)) {
91
+ const colQuery = `${sqlite.escapeName(columnName)} ${schemaTypeToSqlType(
92
+ column.type
93
+ )}${getModifiers(columnName, column)}`;
94
+ colQueries.push(colQuery);
95
+ }
96
+ query += colQueries.join(", ") + ")";
97
+ return query;
98
+ }
99
+ function schemaTypeToSqlType(type) {
100
+ switch (type) {
101
+ case "date":
102
+ case "text":
103
+ case "json":
104
+ return "text";
105
+ case "number":
106
+ case "boolean":
107
+ return "integer";
108
+ }
109
+ }
110
+ function getModifiers(columnName, column) {
111
+ let modifiers = "";
112
+ if (!column.optional) {
113
+ modifiers += " NOT NULL";
114
+ }
115
+ if (column.unique) {
116
+ modifiers += " UNIQUE";
117
+ }
118
+ if (hasDefault(column)) {
119
+ modifiers += ` DEFAULT ${getDefaultValueSql(columnName, column)}`;
120
+ }
121
+ return modifiers;
122
+ }
123
+ function hasDefault(field) {
124
+ return field.default !== void 0;
125
+ }
126
+ function getDefaultValueSql(columnName, column) {
127
+ switch (column.type) {
128
+ case "boolean":
129
+ return column.default ? "TRUE" : "FALSE";
130
+ case "number":
131
+ return `${column.default}`;
132
+ case "text":
133
+ return sqlite.escapeString(column.default);
134
+ case "date":
135
+ return column.default === "now" ? "CURRENT_TIMESTAMP" : sqlite.escapeString(column.default);
136
+ case "json": {
137
+ let stringified = "";
138
+ try {
139
+ stringified = JSON.stringify(column.default);
140
+ } catch (e) {
141
+ console.info(
142
+ `Invalid default value for column ${bold(
143
+ columnName
144
+ )}. Defaults must be valid JSON when using the \`json()\` type.`
145
+ );
146
+ process.exit(0);
147
+ }
148
+ return sqlite.escapeString(stringified);
149
+ }
150
+ }
151
+ }
152
+ function generateId() {
153
+ return nanoid(12);
154
+ }
155
+ const dateType = customType({
156
+ dataType() {
157
+ return "text";
158
+ },
159
+ toDriver(value) {
160
+ return value.toISOString();
161
+ },
162
+ fromDriver(value) {
163
+ return new Date(value);
164
+ }
165
+ });
166
+ const jsonType = customType({
167
+ dataType() {
168
+ return "text";
169
+ },
170
+ toDriver(value) {
171
+ return JSON.stringify(value);
172
+ },
173
+ fromDriver(value) {
174
+ return JSON.parse(value);
175
+ }
176
+ });
177
+ const initialColumns = {
178
+ id: text("id").primaryKey().$default(() => generateId())
179
+ };
180
+ function collectionToTable(name, collection, isJsonSerializable = true) {
181
+ const columns = {
182
+ // Spread to avoid mutating `initialColumns`
183
+ ...initialColumns
184
+ };
185
+ for (const [fieldName, field] of Object.entries(collection.fields)) {
186
+ columns[fieldName] = columnMapper(fieldName, field, isJsonSerializable);
187
+ }
188
+ const table = sqliteTable(name, columns);
189
+ return table;
190
+ }
191
+ function columnMapper(fieldName, field, isJsonSerializable) {
192
+ let c;
193
+ switch (field.type) {
194
+ case "text": {
195
+ c = text(fieldName);
196
+ if (field.default !== void 0)
197
+ c = c.default(field.default);
198
+ break;
199
+ }
200
+ case "number": {
201
+ c = integer(fieldName);
202
+ if (field.default !== void 0)
203
+ c = c.default(field.default);
204
+ break;
205
+ }
206
+ case "boolean": {
207
+ c = integer(fieldName, { mode: "boolean" });
208
+ if (field.default !== void 0)
209
+ c = c.default(field.default);
210
+ break;
211
+ }
212
+ case "json":
213
+ c = jsonType(fieldName);
214
+ if (field.default !== void 0)
215
+ c = c.default(field.default);
216
+ break;
217
+ case "date": {
218
+ if (isJsonSerializable) {
219
+ c = text(fieldName);
220
+ if (field.default !== void 0) {
221
+ c = c.default(field.default === "now" ? sql`CURRENT_TIMESTAMP` : field.default);
222
+ }
223
+ } else {
224
+ c = dateType(fieldName);
225
+ if (field.default !== void 0) {
226
+ c = c.default(
227
+ field.default === "now" ? sql`CURRENT_TIMESTAMP` : (
228
+ // default comes pre-transformed to an ISO string for D1 storage.
229
+ // parse back to a Date for Drizzle.
230
+ z.coerce.date().parse(field.default)
231
+ )
232
+ );
233
+ }
234
+ }
235
+ break;
236
+ }
237
+ }
238
+ if (!field.optional)
239
+ c = c.notNull();
240
+ if (field.unique)
241
+ c = c.unique();
242
+ return c;
243
+ }
244
+ export {
245
+ collectionToTable,
246
+ createLocalDatabaseClient,
247
+ createRemoteDatabaseClient,
248
+ getCreateTableQuery,
249
+ setupDbTables
250
+ };
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Pulled from the mothership, Astro core ❤️
3
+ *
4
+ * @see https://github.com/withastro/astro/blob/main/packages/astro/src/core/config/config.ts#L121
5
+ */
6
+ export declare function loadAstroConfig(root: string): Promise<Record<string, unknown>>;