@astrojs/db 0.4.0 → 0.5.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 (57) hide show
  1. package/dist/core/cli/commands/execute/index.d.ts +8 -0
  2. package/dist/core/cli/commands/execute/index.js +32 -0
  3. package/dist/core/cli/commands/gen/index.d.ts +4 -2
  4. package/dist/core/cli/commands/gen/index.js +17 -9
  5. package/dist/core/cli/commands/link/index.d.ts +20 -8
  6. package/dist/core/cli/commands/link/index.js +191 -31
  7. package/dist/core/cli/commands/login/index.d.ts +4 -2
  8. package/dist/core/cli/commands/login/index.js +31 -22
  9. package/dist/core/cli/commands/logout/index.d.ts +1 -6
  10. package/dist/core/cli/commands/logout/index.js +1 -1
  11. package/dist/core/cli/commands/push/index.d.ts +4 -2
  12. package/dist/core/cli/commands/push/index.js +25 -77
  13. package/dist/core/cli/commands/shell/index.d.ts +4 -2
  14. package/dist/core/cli/commands/shell/index.js +3 -1
  15. package/dist/core/cli/commands/verify/index.d.ts +4 -2
  16. package/dist/core/cli/commands/verify/index.js +10 -6
  17. package/dist/core/cli/index.d.ts +1 -1
  18. package/dist/core/cli/index.js +19 -13
  19. package/dist/core/cli/migration-queries.d.ts +1 -1
  20. package/dist/core/cli/migration-queries.js +6 -6
  21. package/dist/core/cli/migrations.d.ts +12 -9
  22. package/dist/core/cli/migrations.js +27 -21
  23. package/dist/core/consts.d.ts +2 -0
  24. package/dist/core/consts.js +4 -0
  25. package/dist/core/errors.d.ts +7 -4
  26. package/dist/core/errors.js +38 -31
  27. package/dist/core/integration/file-url.js +1 -1
  28. package/dist/core/integration/index.js +56 -117
  29. package/dist/core/integration/typegen.js +1 -13
  30. package/dist/core/integration/vite-plugin-db.d.ts +10 -6
  31. package/dist/core/integration/vite-plugin-db.js +68 -23
  32. package/dist/core/integration/vite-plugin-inject-env-ts.d.ts +1 -1
  33. package/dist/core/load-file.d.ts +31 -0
  34. package/dist/core/load-file.js +98 -0
  35. package/dist/core/tokens.js +1 -1
  36. package/dist/core/types.d.ts +832 -5306
  37. package/dist/core/types.js +16 -84
  38. package/dist/core/utils.d.ts +2 -0
  39. package/dist/core/utils.js +8 -0
  40. package/dist/index.d.ts +2 -3
  41. package/dist/index.js +3 -5
  42. package/dist/runtime/config.d.ts +138 -0
  43. package/dist/runtime/config.js +42 -0
  44. package/dist/runtime/db-client.d.ts +2 -9
  45. package/dist/runtime/db-client.js +8 -39
  46. package/dist/runtime/index.d.ts +5 -4
  47. package/dist/runtime/index.js +12 -10
  48. package/dist/{core → runtime}/queries.d.ts +15 -17
  49. package/dist/{core → runtime}/queries.js +64 -80
  50. package/dist/runtime/types.d.ts +3 -3
  51. package/dist/utils.d.ts +1 -0
  52. package/dist/utils.js +4 -0
  53. package/index.d.ts +5 -3
  54. package/package.json +18 -3
  55. package/config-augment.d.ts +0 -4
  56. package/dist/core/integration/load-astro-config.d.ts +0 -6
  57. package/dist/core/integration/load-astro-config.js +0 -79
@@ -1,115 +1,100 @@
1
- import {
2
- } from "../core/types.js";
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 { hasPrimaryKey } from "../runtime/index.js";
7
- import { isSerializedSQL } from "../runtime/types.js";
8
- import { SEED_WRITABLE_IN_PROD_ERROR } from "./errors.js";
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
- async function recreateTables({
15
+ const SEED_DEV_FILE_NAME = ["seed.ts", "seed.js", "seed.mjs", "seed.mts"];
16
+ async function seedLocal({
11
17
  db,
12
- tables
18
+ tables,
19
+ // Glob all potential seed files to catch renames and deletions.
20
+ fileGlob
13
21
  }) {
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;
31
+ });
32
+ return;
33
+ }
34
+ }
35
+ }
36
+ async function recreateTables({ db, tables }) {
14
37
  const setupQueries = [];
15
- for (const [name, collection] of Object.entries(tables)) {
38
+ for (const [name, table] of Object.entries(tables)) {
16
39
  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);
40
+ const createQuery = sql.raw(getCreateTableQuery(name, table));
41
+ const indexQueries = getCreateIndexQueries(name, table);
19
42
  setupQueries.push(dropQuery, createQuery, ...indexQueries.map((s) => sql.raw(s)));
20
43
  }
21
- for (const q of setupQueries) {
22
- await db.run(q);
23
- }
24
- }
25
- async function seedData({
26
- db,
27
- data,
28
- logger,
29
- mode
30
- }) {
31
- try {
32
- const dataFns = Array.isArray(data) ? data : [data];
33
- for (const dataFn of dataFns) {
34
- await dataFn({
35
- seed: async ({ table, writable }, values) => {
36
- if (writable && mode === "build" && process.env.ASTRO_DB_TEST_ENV !== "1") {
37
- (logger ?? console).error(SEED_WRITABLE_IN_PROD_ERROR(getTableName(table)));
38
- process.exit(1);
39
- }
40
- await db.insert(table).values(values);
41
- },
42
- seedReturning: async ({ table, writable }, values) => {
43
- if (writable && mode === "build" && process.env.ASTRO_DB_TEST_ENV !== "1") {
44
- (logger ?? console).error(SEED_WRITABLE_IN_PROD_ERROR(getTableName(table)));
45
- process.exit(1);
46
- }
47
- let result = db.insert(table).values(values).returning();
48
- if (!Array.isArray(values)) {
49
- result = result.get();
50
- }
51
- return result;
52
- },
53
- db,
54
- mode
55
- });
56
- }
57
- } catch (error) {
58
- (logger ?? console).error(
59
- `Failed to seed data. Did you update to match recent schema changes?`
60
- );
61
- (logger ?? console).error(error);
62
- }
44
+ await db.batch([
45
+ db.run(sql`pragma defer_foreign_keys=true;`),
46
+ ...setupQueries.map((q) => db.run(q))
47
+ ]);
63
48
  }
64
- function getCreateTableQuery(collectionName, collection) {
65
- let query = `CREATE TABLE ${sqlite.escapeName(collectionName)} (`;
49
+ function getCreateTableQuery(tableName, table) {
50
+ let query = `CREATE TABLE ${sqlite.escapeName(tableName)} (`;
66
51
  const colQueries = [];
67
- const colHasPrimaryKey = Object.entries(collection.columns).find(
52
+ const colHasPrimaryKey = Object.entries(table.columns).find(
68
53
  ([, column]) => hasPrimaryKey(column)
69
54
  );
70
55
  if (!colHasPrimaryKey) {
71
56
  colQueries.push("_id INTEGER PRIMARY KEY");
72
57
  }
73
- for (const [columnName, column] of Object.entries(collection.columns)) {
58
+ for (const [columnName, column] of Object.entries(table.columns)) {
74
59
  const colQuery = `${sqlite.escapeName(columnName)} ${schemaTypeToSqlType(
75
60
  column.type
76
61
  )}${getModifiers(columnName, column)}`;
77
62
  colQueries.push(colQuery);
78
63
  }
79
- colQueries.push(...getCreateForeignKeyQueries(collectionName, collection));
64
+ colQueries.push(...getCreateForeignKeyQueries(tableName, table));
80
65
  query += colQueries.join(", ") + ")";
81
66
  return query;
82
67
  }
83
- function getCreateIndexQueries(collectionName, collection) {
68
+ function getCreateIndexQueries(tableName, table) {
84
69
  let queries = [];
85
- for (const [indexName, indexProps] of Object.entries(collection.indexes ?? {})) {
70
+ for (const [indexName, indexProps] of Object.entries(table.indexes ?? {})) {
86
71
  const onColNames = asArray(indexProps.on);
87
72
  const onCols = onColNames.map((colName) => sqlite.escapeName(colName));
88
73
  const unique = indexProps.unique ? "UNIQUE " : "";
89
74
  const indexQuery = `CREATE ${unique}INDEX ${sqlite.escapeName(
90
75
  indexName
91
- )} ON ${sqlite.escapeName(collectionName)} (${onCols.join(", ")})`;
76
+ )} ON ${sqlite.escapeName(tableName)} (${onCols.join(", ")})`;
92
77
  queries.push(indexQuery);
93
78
  }
94
79
  return queries;
95
80
  }
96
- function getCreateForeignKeyQueries(collectionName, collection) {
81
+ function getCreateForeignKeyQueries(tableName, table) {
97
82
  let queries = [];
98
- for (const foreignKey of collection.foreignKeys ?? []) {
83
+ for (const foreignKey of table.foreignKeys ?? []) {
99
84
  const columns = asArray(foreignKey.columns);
100
85
  const references = asArray(foreignKey.references);
101
86
  if (columns.length !== references.length) {
102
- throw new Error(
103
- `Foreign key on ${collectionName} is misconfigured. \`columns\` and \`references\` must be the same length.`
104
- );
87
+ throw new Error(FOREIGN_KEY_REFERENCES_LENGTH_ERROR(tableName));
88
+ }
89
+ const firstReference = references[0];
90
+ if (!firstReference) {
91
+ throw new Error(FOREIGN_KEY_REFERENCES_EMPTY_ERROR(tableName));
105
92
  }
106
- const referencedCollection = references[0]?.schema.collection;
107
- if (!referencedCollection) {
108
- throw new Error(
109
- `Foreign key on ${collectionName} is misconfigured. \`references\` cannot be empty.`
110
- );
93
+ const referencedTable = firstReference.schema.collection;
94
+ if (!referencedTable) {
95
+ throw new Error(FOREIGN_KEY_DNE_ERROR(tableName));
111
96
  }
112
- const query = `FOREIGN KEY (${columns.map((f) => sqlite.escapeName(f)).join(", ")}) REFERENCES ${sqlite.escapeName(referencedCollection)}(${references.map((r) => sqlite.escapeName(r.schema.name)).join(", ")})`;
97
+ const query = `FOREIGN KEY (${columns.map((f) => sqlite.escapeName(f)).join(", ")}) REFERENCES ${sqlite.escapeName(referencedTable)}(${references.map((r) => sqlite.escapeName(r.schema.name)).join(", ")})`;
113
98
  queries.push(query);
114
99
  }
115
100
  return queries;
@@ -144,13 +129,11 @@ function getModifiers(columnName, column) {
144
129
  }
145
130
  const references = getReferencesConfig(column);
146
131
  if (references) {
147
- const { collection, name } = references.schema;
148
- if (!collection || !name) {
149
- throw new Error(
150
- `Column ${collection}.${name} references a collection that does not exist. Did you apply the referenced collection to the \`tables\` object in your Astro config?`
151
- );
132
+ const { collection: tableName, name } = references.schema;
133
+ if (!tableName || !name) {
134
+ throw new Error(REFERENCE_DNE_ERROR(columnName));
152
135
  }
153
- modifiers += ` REFERENCES ${sqlite.escapeName(collection)} (${sqlite.escapeName(name)})`;
136
+ modifiers += ` REFERENCES ${sqlite.escapeName(tableName)} (${sqlite.escapeName(name)})`;
154
137
  }
155
138
  return modifiers;
156
139
  }
@@ -206,6 +189,7 @@ function getDefaultValueSql(columnName, column) {
206
189
  }
207
190
  }
208
191
  export {
192
+ SEED_DEV_FILE_NAME,
209
193
  getCreateForeignKeyQueries,
210
194
  getCreateIndexQueries,
211
195
  getCreateTableQuery,
@@ -214,5 +198,5 @@ export {
214
198
  hasDefault,
215
199
  recreateTables,
216
200
  schemaTypeToSqlType,
217
- seedData
201
+ seedLocal
218
202
  };
@@ -1,6 +1,6 @@
1
- import type { ColumnDataType, ColumnBaseConfig } from 'drizzle-orm';
1
+ import type { ColumnBaseConfig, ColumnDataType } from 'drizzle-orm';
2
2
  import type { SQLiteColumn, SQLiteTableWithColumns } from 'drizzle-orm/sqlite-core';
3
- import type { DBColumn, ColumnsConfig } from '../core/types.js';
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';
@@ -0,0 +1 @@
1
+ export { asDrizzleTable } from './runtime/index.js';
package/dist/utils.js ADDED
@@ -0,0 +1,4 @@
1
+ import { asDrizzleTable } from "./runtime/index.js";
2
+ export {
3
+ asDrizzleTable
4
+ };
package/index.d.ts CHANGED
@@ -1,3 +1,5 @@
1
- /// <reference types="./config-augment.d.ts" />
2
- export * from './dist/index.js';
3
- export { default } from './dist/index.js';
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,6 +1,6 @@
1
1
  {
2
2
  "name": "@astrojs/db",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -12,6 +12,10 @@
12
12
  "types": "./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": "^4.4.11",
71
- "astro": "4.4.4",
85
+ "vite": "^5.1.4",
86
+ "astro": "4.4.9",
72
87
  "astro-scripts": "0.0.14"
73
88
  },
74
89
  "scripts": {
@@ -1,4 +0,0 @@
1
- declare namespace Config {
2
- type DBUserConfig = import('./dist/core/types.js').DBUserConfig;
3
- export interface Database extends DBUserConfig {}
4
- }
@@ -1,6 +0,0 @@
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>>;
@@ -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
- };