@astrojs/db 0.11.0 → 0.11.2

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.
@@ -55,8 +55,7 @@ async function getMigrationQueries({
55
55
  }
56
56
  for (const [tableName, newTable] of Object.entries(newSnapshot.schema)) {
57
57
  const oldTable = oldSnapshot.schema[tableName];
58
- if (!oldTable)
59
- continue;
58
+ if (!oldTable) continue;
60
59
  const addedColumns = getAdded(oldTable.columns, newTable.columns);
61
60
  const droppedColumns = getDropped(oldTable.columns, newTable.columns);
62
61
  const notDeprecatedDroppedColumns = Object.fromEntries(
@@ -161,16 +160,14 @@ function getChangeIndexQueries({
161
160
  function getAddedTables(oldTables, newTables) {
162
161
  const added = {};
163
162
  for (const [key, newTable] of Object.entries(newTables.schema)) {
164
- if (!(key in oldTables.schema))
165
- added[key] = newTable;
163
+ if (!(key in oldTables.schema)) added[key] = newTable;
166
164
  }
167
165
  return added;
168
166
  }
169
167
  function getDroppedTables(oldTables, newTables) {
170
168
  const dropped = {};
171
169
  for (const [key, oldTable] of Object.entries(oldTables.schema)) {
172
- if (!(key in newTables.schema))
173
- dropped[key] = oldTable;
170
+ if (!(key in newTables.schema)) dropped[key] = oldTable;
174
171
  }
175
172
  return dropped;
176
173
  }
@@ -222,23 +219,16 @@ function isEmpty(obj) {
222
219
  return Object.keys(obj).length === 0;
223
220
  }
224
221
  function canAlterTableAddColumn(column) {
225
- if (column.schema.unique)
226
- return false;
227
- if (hasRuntimeDefault(column))
228
- return false;
229
- if (!column.schema.optional && !hasDefault(column))
230
- return false;
231
- if (hasPrimaryKey(column))
232
- return false;
233
- if (getReferencesConfig(column))
234
- return false;
222
+ if (column.schema.unique) return false;
223
+ if (hasRuntimeDefault(column)) return false;
224
+ if (!column.schema.optional && !hasDefault(column)) return false;
225
+ if (hasPrimaryKey(column)) return false;
226
+ if (getReferencesConfig(column)) return false;
235
227
  return true;
236
228
  }
237
229
  function canAlterTableDropColumn(column) {
238
- if (column.schema.unique)
239
- return false;
240
- if (hasPrimaryKey(column))
241
- return false;
230
+ if (column.schema.unique) return false;
231
+ if (hasPrimaryKey(column)) return false;
242
232
  return true;
243
233
  }
244
234
  function canRecreateTableWithoutDataLoss(added, updated) {
@@ -260,16 +250,14 @@ function canRecreateTableWithoutDataLoss(added, updated) {
260
250
  function getAdded(oldObj, newObj) {
261
251
  const added = {};
262
252
  for (const [key, value] of Object.entries(newObj)) {
263
- if (!(key in oldObj))
264
- added[key] = value;
253
+ if (!(key in oldObj)) added[key] = value;
265
254
  }
266
255
  return added;
267
256
  }
268
257
  function getDropped(oldObj, newObj) {
269
258
  const dropped = {};
270
259
  for (const [key, value] of Object.entries(oldObj)) {
271
- if (!(key in newObj))
272
- dropped[key] = value;
260
+ if (!(key in newObj)) dropped[key] = value;
273
261
  }
274
262
  return dropped;
275
263
  }
@@ -277,10 +265,8 @@ function getUpdated(oldObj, newObj) {
277
265
  const updated = {};
278
266
  for (const [key, value] of Object.entries(newObj)) {
279
267
  const oldValue = oldObj[key];
280
- if (!oldValue)
281
- continue;
282
- if (deepDiff(oldValue, value))
283
- updated[key] = value;
268
+ if (!oldValue) continue;
269
+ if (deepDiff(oldValue, value)) updated[key] = value;
284
270
  }
285
271
  return updated;
286
272
  }
@@ -288,8 +274,7 @@ function getUpdatedColumns(oldColumns, newColumns) {
288
274
  const updated = {};
289
275
  for (const [key, newColumn] of Object.entries(newColumns)) {
290
276
  let oldColumn = oldColumns[key];
291
- if (!oldColumn)
292
- continue;
277
+ if (!oldColumn) continue;
293
278
  if (oldColumn.type !== newColumn.type && canChangeTypeWithoutQuery(oldColumn, newColumn)) {
294
279
  const asNewColumn = columnSchema.safeParse({
295
280
  type: newColumn.type,
@@ -27,7 +27,7 @@ function printHelp({
27
27
  message.push(
28
28
  linebreak(),
29
29
  ` ${bgGreen(black(` ${commandName} `))} ${green(
30
- `v${"0.11.0"}`
30
+ `v${"0.11.2"}`
31
31
  )} ${headline}`
32
32
  );
33
33
  }
@@ -52,8 +52,7 @@ const errorMap = (baseError, ctx) => {
52
52
  }
53
53
  };
54
54
  const getTypeOrLiteralMsg = (error) => {
55
- if (error.received === "undefined")
56
- return "Required";
55
+ if (error.received === "undefined") return "Required";
57
56
  const expectedDeduped = new Set(error.expected);
58
57
  switch (error.code) {
59
58
  case "invalid_type":
@@ -68,8 +67,7 @@ const getTypeOrLiteralMsg = (error) => {
68
67
  };
69
68
  const prefix = (key, msg) => key.length ? `**${key}**: ${msg}` : msg;
70
69
  const unionExpectedVals = (expectedVals) => [...expectedVals].map((expectedVal, idx) => {
71
- if (idx === 0)
72
- return JSON.stringify(expectedVal);
70
+ if (idx === 0) return JSON.stringify(expectedVal);
73
71
  const sep = " | ";
74
72
  return `${sep}${JSON.stringify(expectedVal)}`;
75
73
  }).join("");
@@ -55,8 +55,7 @@ function astroDBIntegration() {
55
55
  command = _command;
56
56
  root = config.root;
57
57
  output = config.output;
58
- if (command === "preview")
59
- return;
58
+ if (command === "preview") return;
60
59
  let dbPlugin = void 0;
61
60
  const args = parseArgs(process.argv.slice(3));
62
61
  connectToStudio = process.env.ASTRO_INTERNAL_TEST_REMOTE || args["remote"];
@@ -91,8 +90,7 @@ function astroDBIntegration() {
91
90
  });
92
91
  },
93
92
  "astro:config:done": async ({ config }) => {
94
- if (command === "preview")
95
- return;
93
+ if (command === "preview") return;
96
94
  const { dbConfig, dependencies, integrationSeedPaths } = await resolveDbConfig(config);
97
95
  tables.get = () => dbConfig.tables;
98
96
  seedFiles.get = () => integrationSeedPaths;
@@ -122,8 +120,7 @@ function astroDBIntegration() {
122
120
  logger.info(
123
121
  connectToStudio ? "Connected to remote database." : "New local database created."
124
122
  );
125
- if (connectToStudio)
126
- return;
123
+ if (connectToStudio) return;
127
124
  const localSeedPaths = SEED_DEV_FILE_NAME.map(
128
125
  (name) => new URL(name, getDbDirectoryUrl(root))
129
126
  );
@@ -21,16 +21,14 @@ function vitePluginDb(params) {
21
21
  command = resolvedConfig.command;
22
22
  },
23
23
  async resolveId(id) {
24
- if (id !== VIRTUAL_MODULE_ID)
25
- return;
24
+ if (id !== VIRTUAL_MODULE_ID) return;
26
25
  if (params.seedHandler.inProgress) {
27
26
  return resolved.importedFromSeedFile;
28
27
  }
29
28
  return resolved.module;
30
29
  },
31
30
  async load(id) {
32
- if (id !== resolved.module && id !== resolved.importedFromSeedFile)
33
- return;
31
+ if (id !== resolved.module && id !== resolved.importedFromSeedFile) return;
34
32
  if (params.connectToStudio) {
35
33
  return getStudioVirtualModContents({
36
34
  appToken: params.appToken,
@@ -26,8 +26,7 @@ async function setUpEnvTs({
26
26
  if (existsSync(envTsPath)) {
27
27
  let typesEnvContents = await readFile(envTsPath, "utf-8");
28
28
  const dotAstroDir = new URL(".astro/", root);
29
- if (!existsSync(dotAstroDir))
30
- return;
29
+ if (!existsSync(dotAstroDir)) return;
31
30
  const dbTypeReference = getDBTypeReference({ srcDir, dotAstroDir });
32
31
  if (!typesEnvContents.includes(dbTypeReference)) {
33
32
  typesEnvContents = `${dbTypeReference}
@@ -21,8 +21,7 @@ async function resolveDbConfig({
21
21
  const integrationDbConfigPaths = [];
22
22
  const integrationSeedPaths = [];
23
23
  for (const integration of integrations) {
24
- if (!isDbIntegration(integration))
25
- continue;
24
+ if (!isDbIntegration(integration)) continue;
26
25
  const { name, hooks } = integration;
27
26
  if (hooks["astro:db:setup"]) {
28
27
  hooks["astro:db:setup"]({
@@ -107,8 +107,7 @@ function getModifiers(columnName, column) {
107
107
  }
108
108
  function getReferencesConfig(column) {
109
109
  const canHaveReferences = column.type === "number" || column.type === "text";
110
- if (!canHaveReferences)
111
- return void 0;
110
+ if (!canHaveReferences) return void 0;
112
111
  return column.schema.references;
113
112
  }
114
113
  function hasDefault(column) {
@@ -2,7 +2,7 @@ import { createClient } from "@libsql/client";
2
2
  import { drizzle as drizzleLibsql } from "drizzle-orm/libsql";
3
3
  import { drizzle as drizzleProxy } from "drizzle-orm/sqlite-proxy";
4
4
  import { z } from "zod";
5
- import { AstroDbError, safeFetch } from "./utils.js";
5
+ import { DetailedLibsqlError, safeFetch } from "./utils.js";
6
6
  const isWebContainer = !!process.versions?.webcontainer;
7
7
  function applyTransactionNotSupported(db) {
8
8
  Object.assign(db, {
@@ -54,10 +54,12 @@ function createRemoteDatabaseClient(appToken, remoteDbURL) {
54
54
  const json = await res.json();
55
55
  remoteResult = remoteResultSchema.parse(json);
56
56
  } catch (e) {
57
- throw new AstroDbError(await getUnexpectedResponseMessage(res));
57
+ throw new DetailedLibsqlError({
58
+ message: await getUnexpectedResponseMessage(res),
59
+ code: KNOWN_ERROR_CODES.SQL_QUERY_FAILED
60
+ });
58
61
  }
59
- if (method === "run")
60
- return remoteResult;
62
+ if (method === "run") return remoteResult;
61
63
  const rowValues = [];
62
64
  for (const row of remoteResult.rows) {
63
65
  if (row != null && typeof row === "object") {
@@ -90,7 +92,10 @@ function createRemoteDatabaseClient(appToken, remoteDbURL) {
90
92
  const json = await res.json();
91
93
  remoteResults = z.array(remoteResultSchema).parse(json);
92
94
  } catch (e) {
93
- throw new AstroDbError(await getUnexpectedResponseMessage(res));
95
+ throw new DetailedLibsqlError({
96
+ message: await getUnexpectedResponseMessage(res),
97
+ code: KNOWN_ERROR_CODES.SQL_QUERY_FAILED
98
+ });
94
99
  }
95
100
  let results = [];
96
101
  for (const [idx, rawResult] of remoteResults.entries()) {
@@ -126,21 +131,24 @@ const KNOWN_ERROR_CODES = {
126
131
  SQL_QUERY_FAILED: "SQL_QUERY_FAILED"
127
132
  };
128
133
  const getUnexpectedResponseMessage = async (response) => `Unexpected response from remote database:
129
- (Status ${response.status}) ${await response.text()}`;
134
+ (Status ${response.status}) ${await response.clone().text()}`;
130
135
  async function parseRemoteError(response) {
131
136
  let error;
132
137
  try {
133
- error = errorSchema.parse(await response.json()).error;
138
+ error = errorSchema.parse(await response.clone().json()).error;
134
139
  } catch (e) {
135
- return new AstroDbError(await getUnexpectedResponseMessage(response));
140
+ return new DetailedLibsqlError({
141
+ message: await getUnexpectedResponseMessage(response),
142
+ code: KNOWN_ERROR_CODES.SQL_QUERY_FAILED
143
+ });
136
144
  }
137
- let details = error.details?.replace(/.*SQLite error: /, "") ?? `(Code ${error.code})
138
- Error querying remote database.`;
145
+ let baseDetails = error.details?.replace(/.*SQLite error: /, "") ?? "Error querying remote database.";
146
+ const details = baseDetails.slice(baseDetails.indexOf(":") + 1).trim();
139
147
  let hint = `See the Astro DB guide for query and push instructions: https://docs.astro.build/en/guides/astro-db/#query-your-database`;
140
148
  if (error.code === KNOWN_ERROR_CODES.SQL_QUERY_FAILED && details.includes("no such table")) {
141
149
  hint = `Did you run \`astro db push\` to push your latest table schemas?`;
142
150
  }
143
- return new AstroDbError(details, hint);
151
+ return new DetailedLibsqlError({ message: details, code: error.code, hint });
144
152
  }
145
153
  export {
146
154
  createLocalDatabaseClient,
@@ -12,6 +12,7 @@ import { createRemoteDatabaseClient, createLocalDatabaseClient } from "./db-clie
12
12
  function hasPrimaryKey(column) {
13
13
  return "primaryKey" in column.schema && !!column.schema.primaryKey;
14
14
  }
15
+ const isISODateString = (str) => /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z/.test(str);
15
16
  const dateType = customType({
16
17
  dataType() {
17
18
  return "text";
@@ -20,6 +21,9 @@ const dateType = customType({
20
21
  return value.toISOString();
21
22
  },
22
23
  fromDriver(value) {
24
+ if (!isISODateString(value)) {
25
+ value += "Z";
26
+ }
23
27
  return new Date(value);
24
28
  }
25
29
  });
@@ -47,8 +51,7 @@ function asDrizzleTable(name, table) {
47
51
  for (const [indexName, indexProps] of Object.entries(table.indexes ?? {})) {
48
52
  const onColNames = Array.isArray(indexProps.on) ? indexProps.on : [indexProps.on];
49
53
  const onCols = onColNames.map((colName) => ormTable[colName]);
50
- if (!atLeastOne(onCols))
51
- continue;
54
+ if (!atLeastOne(onCols)) continue;
52
55
  indexes[indexName] = index(indexName).on(...onCols);
53
56
  }
54
57
  return indexes;
@@ -65,16 +68,14 @@ function columnMapper(columnName, column) {
65
68
  c = text(columnName);
66
69
  if (column.schema.default !== void 0)
67
70
  c = c.default(handleSerializedSQL(column.schema.default));
68
- if (column.schema.primaryKey === true)
69
- c = c.primaryKey();
71
+ if (column.schema.primaryKey === true) c = c.primaryKey();
70
72
  break;
71
73
  }
72
74
  case "number": {
73
75
  c = integer(columnName);
74
76
  if (column.schema.default !== void 0)
75
77
  c = c.default(handleSerializedSQL(column.schema.default));
76
- if (column.schema.primaryKey === true)
77
- c = c.primaryKey();
78
+ if (column.schema.primaryKey === true) c = c.primaryKey();
78
79
  break;
79
80
  }
80
81
  case "boolean": {
@@ -85,8 +86,7 @@ function columnMapper(columnName, column) {
85
86
  }
86
87
  case "json":
87
88
  c = jsonType(columnName);
88
- if (column.schema.default !== void 0)
89
- c = c.default(column.schema.default);
89
+ if (column.schema.default !== void 0) c = c.default(column.schema.default);
90
90
  break;
91
91
  case "date": {
92
92
  c = dateType(columnName);
@@ -97,10 +97,8 @@ function columnMapper(columnName, column) {
97
97
  break;
98
98
  }
99
99
  }
100
- if (!column.schema.optional)
101
- c = c.notNull();
102
- if (column.schema.unique)
103
- c = c.unique();
100
+ if (!column.schema.optional) c = c.notNull();
101
+ if (column.schema.unique) c = c.unique();
104
102
  return c;
105
103
  }
106
104
  function handleSerializedSQL(def) {
@@ -1,3 +1,4 @@
1
+ import { LibsqlError } from '@libsql/client';
1
2
  import { AstroError } from 'astro/errors';
2
3
  /**
3
4
  * Small wrapper around fetch that throws an error if the response is not OK. Allows for custom error handling as well through the onNotOK callback.
@@ -6,4 +7,15 @@ export declare function safeFetch(url: Parameters<typeof fetch>[0], options?: Pa
6
7
  export declare class AstroDbError extends AstroError {
7
8
  name: string;
8
9
  }
10
+ export declare class DetailedLibsqlError extends LibsqlError {
11
+ name: string;
12
+ hint?: string;
13
+ constructor({ message, code, hint, rawCode, cause, }: {
14
+ message: string;
15
+ code: string;
16
+ hint?: string;
17
+ rawCode?: number;
18
+ cause?: Error;
19
+ });
20
+ }
9
21
  export declare function pathToFileURL(path: string): URL;
@@ -1,3 +1,4 @@
1
+ import { LibsqlError } from "@libsql/client";
1
2
  import { AstroError } from "astro/errors";
2
3
  const isWindows = process?.platform === "win32";
3
4
  async function safeFetch(url, options = {}, onNotOK = () => {
@@ -12,6 +13,20 @@ async function safeFetch(url, options = {}, onNotOK = () => {
12
13
  class AstroDbError extends AstroError {
13
14
  name = "Astro DB Error";
14
15
  }
16
+ class DetailedLibsqlError extends LibsqlError {
17
+ name = "Astro DB Error";
18
+ hint;
19
+ constructor({
20
+ message,
21
+ code,
22
+ hint,
23
+ rawCode,
24
+ cause
25
+ }) {
26
+ super(message, code, rawCode, cause);
27
+ this.hint = hint;
28
+ }
29
+ }
15
30
  function slash(path) {
16
31
  const isExtendedLengthPath = path.startsWith("\\\\?\\");
17
32
  if (isExtendedLengthPath) {
@@ -31,6 +46,7 @@ function pathToFileURL(path) {
31
46
  }
32
47
  export {
33
48
  AstroDbError,
49
+ DetailedLibsqlError,
34
50
  pathToFileURL,
35
51
  safeFetch
36
52
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astrojs/db",
3
- "version": "0.11.0",
3
+ "version": "0.11.2",
4
4
  "description": "Add libSQL and Astro Studio support to your Astro site",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -66,7 +66,7 @@
66
66
  "async-listen": "^3.0.1",
67
67
  "ci-info": "^4.0.0",
68
68
  "deep-diff": "^1.0.2",
69
- "drizzle-orm": "^0.30.9",
69
+ "drizzle-orm": "^0.30.10",
70
70
  "github-slugger": "^2.0.0",
71
71
  "kleur": "^4.1.5",
72
72
  "nanoid": "^5.0.7",
@@ -75,21 +75,21 @@
75
75
  "prompts": "^2.4.2",
76
76
  "strip-ansi": "^7.1.0",
77
77
  "yargs-parser": "^21.1.1",
78
- "zod": "^3.23.5"
78
+ "zod": "^3.23.8"
79
79
  },
80
80
  "devDependencies": {
81
- "@types/chai": "^4.3.14",
81
+ "@types/chai": "^4.3.16",
82
82
  "@types/deep-diff": "^1.0.5",
83
- "@types/diff": "^5.2.0",
83
+ "@types/diff": "^5.2.1",
84
84
  "@types/mocha": "^10.0.6",
85
85
  "@types/prompts": "^2.4.9",
86
86
  "@types/yargs-parser": "^21.0.3",
87
- "chai": "^5.1.0",
87
+ "chai": "^5.1.1",
88
88
  "cheerio": "1.0.0-rc.12",
89
89
  "mocha": "^10.4.0",
90
90
  "typescript": "^5.4.5",
91
- "vite": "^5.2.10",
92
- "astro": "4.7.1",
91
+ "vite": "^5.2.11",
92
+ "astro": "4.8.4",
93
93
  "astro-scripts": "0.0.14"
94
94
  },
95
95
  "scripts": {
@@ -1 +0,0 @@
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';
@@ -1,48 +0,0 @@
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
- };