From ddbde618076804bed90d5bdd6d4f56e2414b8e1b Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Thu, 7 Mar 2024 09:37:19 -0500 Subject: [PATCH 1/7] deps: drizzle preview --- packages/db/package.json | 2 +- pnpm-lock.yaml | 17 +++++++++++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/packages/db/package.json b/packages/db/package.json index 724c923187a9..e0949145aad6 100644 --- a/packages/db/package.json +++ b/packages/db/package.json @@ -62,7 +62,7 @@ "@libsql/client": "^0.4.3", "async-listen": "^3.0.1", "deep-diff": "^1.0.2", - "drizzle-orm": "^0.28.6", + "drizzle-orm": "0.29.5-7888ad6", "kleur": "^4.1.5", "nanoid": "^5.0.1", "open": "^10.0.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 082cbbf7e59d..a4bf1487d999 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3824,8 +3824,8 @@ importers: specifier: ^1.0.2 version: 1.0.2 drizzle-orm: - specifier: ^0.28.6 - version: 0.28.6(@libsql/client@0.4.3) + specifier: 0.29.5-7888ad6 + version: 0.29.5-7888ad6(@libsql/client@0.4.3) kleur: specifier: ^4.1.5 version: 4.1.5 @@ -9943,8 +9943,8 @@ packages: engines: {node: '>=10'} dev: true - /drizzle-orm@0.28.6(@libsql/client@0.4.3): - resolution: {integrity: sha512-yBe+F9htrlYER7uXgDJUQsTHFoIrI5yMm5A0bg0GiZ/kY5jNXTWoEy4KQtg35cE27sw1VbgzoMWHAgCckUUUww==} + /drizzle-orm@0.29.5-7888ad6(@libsql/client@0.4.3): + resolution: {integrity: sha512-G2z2OyUKC1Du1ytTS1BOFmzMkLRdJHY3FvFBF2VmVbGF9b5L8F/2UMbiZRY8Hq0gvY/GD0m/F2wjj5Yezo7zdQ==} peerDependencies: '@aws-sdk/client-rds-data': '>=3' '@cloudflare/workers-types': '>=3' @@ -9954,15 +9954,18 @@ packages: '@planetscale/database': '>=1' '@types/better-sqlite3': '*' '@types/pg': '*' + '@types/react': '>=18' '@types/sql.js': '*' '@vercel/postgres': '*' better-sqlite3: '>=7' bun-types: '*' + expo-sqlite: '>=13.2.0' knex: '*' kysely: '*' mysql2: '>=2' pg: '>=8' postgres: '>=3' + react: '>=18' sql.js: '>=1' sqlite3: '>=5' peerDependenciesMeta: @@ -9982,6 +9985,8 @@ packages: optional: true '@types/pg': optional: true + '@types/react': + optional: true '@types/sql.js': optional: true '@vercel/postgres': @@ -9990,6 +9995,8 @@ packages: optional: true bun-types: optional: true + expo-sqlite: + optional: true knex: optional: true kysely: @@ -10000,6 +10007,8 @@ packages: optional: true postgres: optional: true + react: + optional: true sql.js: optional: true sqlite3: From ac60b88a55ce4edd809301f3c7e02929fa6a66d0 Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Thu, 7 Mar 2024 09:37:28 -0500 Subject: [PATCH 2/7] feat: db.batch and method run handling --- packages/db/src/runtime/db-client.ts | 142 +++++++++++++++++++-------- 1 file changed, 99 insertions(+), 43 deletions(-) diff --git a/packages/db/src/runtime/db-client.ts b/packages/db/src/runtime/db-client.ts index bd892a4dd668..db8535e15ed4 100644 --- a/packages/db/src/runtime/db-client.ts +++ b/packages/db/src/runtime/db-client.ts @@ -15,58 +15,114 @@ export function createLocalDatabaseClient({ dbUrl }: { dbUrl: string }): LibSQLD return db; } +const remoteResultSchema = z.object({ + columns: z.array(z.string()), + columnTypes: z.array(z.string()), + rows: z.array(z.array(z.unknown())), + rowsAffected: z.number(), + lastInsertRowid: z.unknown().optional(), +}); + export function createRemoteDatabaseClient(appToken: string, remoteDbURL: string) { const url = new URL('/db/query', remoteDbURL); - const db = drizzleProxy(async (sql, parameters, method) => { - const requestBody: InStatement = { sql, args: parameters }; - const res = await fetch(url, { - method: 'POST', - headers: { - Authorization: `Bearer ${appToken}`, - 'Content-Type': 'application/json', - }, - body: JSON.stringify(requestBody), - }); - if (!res.ok) { - throw new Error( - `Failed to execute query.\nQuery: ${sql}\nFull error: ${res.status} ${await res.text()}}` - ); - } + const db = drizzleProxy( + async (sql, parameters, method) => { + const requestBody: InStatement = { sql, args: parameters }; + const res = await fetch(url, { + method: 'POST', + headers: { + Authorization: `Bearer ${appToken}`, + 'Content-Type': 'application/json', + }, + body: JSON.stringify(requestBody), + }); + if (!res.ok) { + throw new Error( + `Failed to execute query.\nQuery: ${sql}\nFull error: ${res.status} ${await res.text()}}` + ); + } - const queryResultSchema = z.object({ - rows: z.array(z.unknown()), - }); - let rows: unknown[]; - try { - const json = await res.json(); - rows = queryResultSchema.parse(json).rows; - } catch (e) { - throw new Error( - `Failed to execute query.\nQuery: ${sql}\nFull error: Unexpected JSON response. ${ - e instanceof Error ? e.message : String(e) - }` - ); - } + let remoteResult: z.infer; + try { + const json = await res.json(); + remoteResult = remoteResultSchema.parse(json); + } catch (e) { + throw new Error( + `Failed to execute query.\nQuery: ${sql}\nFull error: Unexpected JSON response. ${ + e instanceof Error ? e.message : String(e) + }` + ); + } - // Drizzle expects each row as an array of its values - const rowValues: unknown[][] = []; + if (method === 'run') return remoteResult; - for (const row of rows) { - if (row != null && typeof row === 'object') { - rowValues.push(Object.values(row)); + // Drizzle expects each row as an array of its values + const rowValues: unknown[][] = []; + + for (const row of remoteResult.rows) { + if (row != null && typeof row === 'object') { + rowValues.push(Object.values(row)); + } } - } - if (method === 'get') { - return { rows: rowValues[0] }; - } + if (method === 'get') { + return { rows: rowValues[0] }; + } - return { rows: rowValues }; - }); + return { rows: rowValues }; + }, + async (queries) => { + const stmts: InStatement[] = queries.map(({ sql, params }) => ({ sql, args: params })); + const res = await fetch(url, { + method: 'POST', + headers: { + Authorization: `Bearer ${appToken}`, + 'Content-Type': 'application/json', + }, + body: JSON.stringify(stmts), + }); + if (!res.ok) { + throw new Error( + `Failed to execute batch queries.\nFull error: ${res.status} ${await res.text()}}` + ); + } + + let remoteResults: z.infer[]; + try { + const json = await res.json(); + remoteResults = z.array(remoteResultSchema).parse(json); + } catch (e) { + throw new Error( + `Failed to execute batch queries.\nFull error: Unexpected JSON response. ${ + e instanceof Error ? e.message : String(e) + }` + ); + } + let results: any[] = []; + for (const [idx, rawResult] of remoteResults.entries()) { + if (queries[idx]?.method === 'run') { + results.push(rawResult); + continue; + } + + // Drizzle expects each row as an array of its values + const rowValues: unknown[][] = []; - (db as any).batch = (_drizzleQueries: Array>) => { - throw new Error('db.batch() is not currently supported.'); - }; + for (const row of rawResult.rows) { + if (row != null && typeof row === 'object') { + rowValues.push(Object.values(row)); + } + } + + if (queries[idx]?.method === 'get') { + results.push({ rows: rowValues[0] }); + } + + results.push({ rows: rowValues }); + } + return results; + } + ); return db; } From e584c0674049f600c37f97f5b30fccac16f5b9b1 Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Thu, 7 Mar 2024 13:25:29 -0500 Subject: [PATCH 3/7] refactor: use db.batch in test fixture --- packages/db/test/fixtures/basics/db/seed.ts | 31 +++++++++++---------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/packages/db/test/fixtures/basics/db/seed.ts b/packages/db/test/fixtures/basics/db/seed.ts index 86736c627666..a1502dc2b478 100644 --- a/packages/db/test/fixtures/basics/db/seed.ts +++ b/packages/db/test/fixtures/basics/db/seed.ts @@ -2,20 +2,21 @@ import { asDrizzleTable } from '@astrojs/db/utils'; import { Themes as ThemesConfig } from './theme'; import { Author, db } from 'astro:db'; +const Themes = asDrizzleTable('Themes', ThemesConfig); export default async function () { - const Themes = asDrizzleTable('Themes', ThemesConfig); - - await db - .insert(Themes) - .values([{ name: 'dracula' }, { name: 'monokai', added: new Date() }]) - .returning({ name: Themes.name }); - await db - .insert(Author) - .values([ - { name: 'Ben' }, - { name: 'Nate' }, - { name: 'Erika' }, - { name: 'Bjorn' }, - { name: 'Sarah' }, - ]); + await db.batch([ + db + .insert(Themes) + .values([{ name: 'dracula' }, { name: 'monokai', added: new Date() }]) + .returning({ name: Themes.name }), + db + .insert(Author) + .values([ + { name: 'Ben' }, + { name: 'Nate' }, + { name: 'Erika' }, + { name: 'Bjorn' }, + { name: 'Sarah' }, + ]), + ]); } From 0ec7857f7b156375f9ac60db564a7792422da606 Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Thu, 7 Mar 2024 13:28:36 -0500 Subject: [PATCH 4/7] deps: bump to drizzle 0.29.5 --- packages/db/package.json | 2 +- pnpm-lock.yaml | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/db/package.json b/packages/db/package.json index e0949145aad6..2b606ef83866 100644 --- a/packages/db/package.json +++ b/packages/db/package.json @@ -62,7 +62,7 @@ "@libsql/client": "^0.4.3", "async-listen": "^3.0.1", "deep-diff": "^1.0.2", - "drizzle-orm": "0.29.5-7888ad6", + "drizzle-orm": "0.29.5", "kleur": "^4.1.5", "nanoid": "^5.0.1", "open": "^10.0.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a4bf1487d999..7e8026cbea02 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3824,8 +3824,8 @@ importers: specifier: ^1.0.2 version: 1.0.2 drizzle-orm: - specifier: 0.29.5-7888ad6 - version: 0.29.5-7888ad6(@libsql/client@0.4.3) + specifier: 0.29.5 + version: 0.29.5(@libsql/client@0.4.3) kleur: specifier: ^4.1.5 version: 4.1.5 @@ -9943,8 +9943,8 @@ packages: engines: {node: '>=10'} dev: true - /drizzle-orm@0.29.5-7888ad6(@libsql/client@0.4.3): - resolution: {integrity: sha512-G2z2OyUKC1Du1ytTS1BOFmzMkLRdJHY3FvFBF2VmVbGF9b5L8F/2UMbiZRY8Hq0gvY/GD0m/F2wjj5Yezo7zdQ==} + /drizzle-orm@0.29.5(@libsql/client@0.4.3): + resolution: {integrity: sha512-jS3+uyzTz4P0Y2CICx8FmRQ1eplURPaIMWDn/yq6k4ShRFj9V7vlJk67lSf2kyYPzQ60GkkNGXcJcwrxZ6QCRw==} peerDependencies: '@aws-sdk/client-rds-data': '>=3' '@cloudflare/workers-types': '>=3' From 0d7b33746a45b43ad3486512faf981370bea8b48 Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Thu, 7 Mar 2024 13:41:54 -0500 Subject: [PATCH 5/7] chore: changeset --- .changeset/weak-weeks-pump.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/weak-weeks-pump.md diff --git a/.changeset/weak-weeks-pump.md b/.changeset/weak-weeks-pump.md new file mode 100644 index 000000000000..96cb77d213cc --- /dev/null +++ b/.changeset/weak-weeks-pump.md @@ -0,0 +1,5 @@ +--- +"@astrojs/db": minor +--- + +Add support for batch queries with `db.batch()`. This includes an internal bump to Drizzle v0.29. From ac85f82ccbedaff5ce4d333996fb67a40fb6d177 Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Thu, 7 Mar 2024 14:26:56 -0500 Subject: [PATCH 6/7] fix: unpin drizzle version --- packages/db/package.json | 2 +- pnpm-lock.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/db/package.json b/packages/db/package.json index 2b606ef83866..31834f8d4c88 100644 --- a/packages/db/package.json +++ b/packages/db/package.json @@ -62,7 +62,7 @@ "@libsql/client": "^0.4.3", "async-listen": "^3.0.1", "deep-diff": "^1.0.2", - "drizzle-orm": "0.29.5", + "drizzle-orm": "^0.29.5", "kleur": "^4.1.5", "nanoid": "^5.0.1", "open": "^10.0.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7e8026cbea02..9ded7e2937db 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3824,7 +3824,7 @@ importers: specifier: ^1.0.2 version: 1.0.2 drizzle-orm: - specifier: 0.29.5 + specifier: ^0.29.5 version: 0.29.5(@libsql/client@0.4.3) kleur: specifier: ^4.1.5 From 0f02294df0e2ed1e925634175b3598ef34b88f72 Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Thu, 7 Mar 2024 14:40:17 -0500 Subject: [PATCH 7/7] fix: db execute should uh... execute --- .../db/src/core/cli/commands/execute/index.ts | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/packages/db/src/core/cli/commands/execute/index.ts b/packages/db/src/core/cli/commands/execute/index.ts index b1aa50cc84f3..14ea6b2cd281 100644 --- a/packages/db/src/core/cli/commands/execute/index.ts +++ b/packages/db/src/core/cli/commands/execute/index.ts @@ -1,7 +1,11 @@ import { existsSync } from 'node:fs'; import type { AstroConfig } from 'astro'; import type { Arguments } from 'yargs-parser'; -import { FILE_NOT_FOUND_ERROR, MISSING_EXECUTE_PATH_ERROR } from '../../../errors.js'; +import { + FILE_NOT_FOUND_ERROR, + MISSING_EXECUTE_PATH_ERROR, + SEED_DEFAULT_EXPORT_ERROR, +} from '../../../errors.js'; import { getLocalVirtualModContents, getStudioVirtualModContents, @@ -46,6 +50,11 @@ export async function cmd({ }); } const { code } = await bundleFile({ virtualModContents, root: astroConfig.root, fileUrl }); - // Executable files use top-level await. Importing will run the file. - await importBundledFile({ code, root: astroConfig.root }); + + const mod = await importBundledFile({ code, root: astroConfig.root }); + if (typeof mod.default !== 'function') { + console.error(SEED_DEFAULT_EXPORT_ERROR); + process.exit(1); + } + await mod.default(); }