rado 1.0.10 → 1.0.11

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/README.md CHANGED
@@ -5,200 +5,329 @@
5
5
 
6
6
  Fully typed, lightweight TypeScript query builder.
7
7
 
8
- - Definition via TypeScript types
9
- - Composable queries
10
- - First class JSON columns
11
- - No code generation step
12
- - No dependencies
8
+ ## Features
9
+
10
+ - Fully typed queries using TypeScript
11
+ - Composable and reusable query structures
12
+ - First-class support for JSON columns
13
+ - No code generation step required
14
+ - Zero dependencies
15
+ - Universal query support for multiple database engines
16
+
17
+ ## Installation
13
18
 
14
19
  <pre>npm install <a href="https://www.npmjs.com/package/rado">rado</a></pre>
15
20
 
16
- ## Queries
21
+ ## Quick Start
17
22
 
18
- #### Where
23
+ ```typescript
24
+ import {table} from 'rado'
25
+ import {text, integer} from 'rado/postgres'
26
+ import {connect} from 'rado/driver/pg'
27
+ import {Pool} from 'pg'
28
+
29
+ // Define your schema
30
+ const User = table({
31
+ id: integer().primaryKey(),
32
+ name: text().notNull(),
33
+ email: text().unique()
34
+ })
19
35
 
20
- Conditions can be created by accessing the fields of the table:
36
+ // Connect to the database
37
+ const db = connect(new Pool({
38
+ host: 'localhost',
39
+ database: 'my_database'
40
+ }))
21
41
 
22
- ```ts
23
- import {eq} from 'rado'
24
- eq(User.id, 1) // Compare with a value
25
- eq(User.id, Post.userId) // Compare to fields on other tables
42
+ // Perform a query
43
+ const users = await db.select().from(User)
44
+ console.log(users)
26
45
  ```
27
46
 
28
- Rows can be selected by passing the condition in the where method:
47
+ ## Supported Databases
29
48
 
30
- ```ts
31
- import {eq, or, gt, lt} from 'rado'
32
- db.select().from(User).where(eq(User.id, 1))
33
- // Conditions can be as complex as you want
34
- db.select().from(User).where(or(gt(User.id, 1), lt(User.id, 5)))
35
- ```
49
+ Currently supported drivers:
36
50
 
37
- #### Select
51
+ | `PostgreSQL ` | `import ` |
52
+ | -------------------------- | ------------------------------ |
53
+ | `pg` | `'rado/driver/pg'` |
54
+ | `@electric-sql/pglite` | `'rado/driver/pglite'` |
55
+ | `@neondatabase/serverless` | `'rado/driver/pg'` |
56
+ | `@vercel/postgres` | `'rado/driver/pg'` |
38
57
 
39
- Retrieve a single field
58
+ | `SQLite ` | `import ` |
59
+ | -------------------------- | ------------------------------ |
60
+ | `better-sqlite3` | `'rado/driver/better-sqlite3'` |
61
+ | `bun:sqlite` | `'rado/driver/bun-sqlite'` |
62
+ | `sql.js` | `'rado/driver/sql.js'` |
63
+ | `Cloudflare D1` | `'rado/driver/d1'` |
40
64
 
41
- ```ts
42
- db.select(User.name).from(User)
43
- ```
65
+ | `MySQL ` | `import ` |
66
+ | -------------------------- | ------------------------------ |
67
+ | `mysql2` | `'rado/driver/mysql2'` |
44
68
 
45
- Or an object of data
69
+ Pass an instance of the database to the `connect` function to get started:
46
70
 
47
71
  ```ts
48
- import {eq, include} from 'rado'
49
- db.select({
50
- // Get all user fields: id, username
51
- ...User,
52
- // Aggregate posts of this user
53
- posts: include(db.select().from(Post).where(eq(Post.userId, User.id)))
54
- }).from(User)
72
+ import Database from 'better-sqlite3'
73
+ import {connect} from 'rado/driver/better-sqlite3'
74
+
75
+ const db = connect(new Database('foobar.db'))
55
76
  ```
56
77
 
57
- Join other tables and select fields from either table:
78
+ ## Querying
58
79
 
59
- ```ts
60
- db
61
- .select({
62
- username: User.username
63
- post: Post
64
- })
65
- .from(User)
66
- .innerJoin(Post, eq(Post.userId, User.id))
67
- .where(eq(User.id, 1))
80
+ ### Select
81
+
82
+ Select operations allow you to retrieve data from your database.
83
+
84
+ ```typescript
85
+ // Basic select
86
+ const allUsers = await db.select().from(User)
87
+
88
+ // Select specific columns
89
+ const userNames = await db.select({id: User.id, name: User.name}).from(User)
68
90
  ```
69
91
 
70
- Order, group, limit queries:
92
+ ### Where conditions
71
93
 
72
- ```ts
73
- import {asc} from 'rado'
74
- db.select().from(User)
75
- .orderBy(asc(User.username))
76
- .groupBy(User.id, User.username)
77
- .limit(10, 20)
94
+ Where conditions help you filter your query results.
95
+
96
+ ```typescript
97
+ import {eq, and, or, gt, isNull} from 'rado'
98
+
99
+ // Simple equality
100
+ const john = await db.select().from(User).where(eq(User.name, 'John'))
101
+
102
+ // Complex conditions
103
+ const users = await db.select().from(User)
104
+ .where(
105
+ gt(User.age, 18),
106
+ or(
107
+ eq(User.name, 'Alice'),
108
+ isNull(User.email)
109
+ )
110
+ )
78
111
  ```
79
112
 
80
- #### Insert
113
+ ### Joins
81
114
 
82
- Insert a single row:
115
+ Joins allow you to combine data from multiple tables.
83
116
 
84
- ```ts
85
- db.insert(User).values({username: 'Mario'})
117
+ ```typescript
118
+ const usersWithPosts = await db.select({
119
+ userName: User.name,
120
+ postTitle: Post.title,
121
+ })
122
+ .from(User)
123
+ .leftJoin(Post, eq(User.id, Post.authorId))
86
124
  ```
87
125
 
88
- Insert multiple rows:
126
+ ### Ordering and Grouping
89
127
 
90
- ```ts
91
- db.insert(User).values([{username: 'Mario'}, {username: 'Luigi'}])
128
+ You can order and group your query results:
129
+
130
+ ```typescript
131
+ import {desc, asc, count} from 'rado'
132
+
133
+ const orderedUsers = await db.select()
134
+ .from(User)
135
+ .orderBy(asc(User.name))
136
+
137
+ const userPostCounts = await db.select({
138
+ userName: User.name,
139
+ postCount: count(Post.id)
140
+ })
141
+ .from(User)
142
+ .leftJoin(Post, eq(User.id, Post.authorId))
143
+ .groupBy(User.name)
92
144
  ```
93
145
 
94
- #### Update
146
+ ### Pagination
95
147
 
96
- Set values
148
+ Pagination helps you manage large datasets by retrieving results in smaller chunks:
97
149
 
98
- ```ts
99
- db.update(User)
100
- .set({username: 'Bowser'})
101
- .where(eq(User.id, 1))
150
+ ```typescript
151
+ const pageSize = 10
152
+ const page = 2
153
+
154
+ const paginatedUsers = await db.select()
155
+ .from(User)
156
+ .limit(pageSize)
157
+ .offset((page - 1) * pageSize)
102
158
  ```
103
159
 
104
- Use expressions to update complex values:
160
+ ### JSON columns
105
161
 
106
- ```ts
107
- import {concat} from 'rado/sqlite'
108
- db.update(User)
109
- .set({username: concat(User.username, ' [removed]')})
110
- .where(User.deleted)
162
+ Rado provides first-class support for JSON columns:
163
+
164
+ ```typescript
165
+ import {pgTable, serial, text, jsonb} from 'rado/postgres'
166
+
167
+ const User = pgTable({
168
+ id: serial().primaryKey(),
169
+ name: text(),
170
+ metadata: jsonb<{subscribed: boolean}>()
171
+ })
172
+
173
+ const subscribedUsers = await db.select()
174
+ .from(User)
175
+ .where(eq(User.metadata.subscribed, true))
111
176
  ```
112
177
 
113
- #### Delete
178
+ ### Subqueries
114
179
 
115
- Delete rows
180
+ ```typescript
181
+ const subquery = db.select({authorId: Post.authorId})
182
+ .from(Post)
183
+ .groupBy(Post.authorId)
184
+ .having(gt(count(Post.id), 5))
185
+ .as('authorIds')
116
186
 
117
- ```ts
118
- db.delete(User).where(eq(User.id, 1))
187
+ const prolificAuthors = await db.select()
188
+ .from(User)
189
+ .where(inArray(User.id, subquery))
119
190
  ```
120
191
 
121
- ## Schema definition
192
+ ### Include
122
193
 
123
- ```ts
124
- import * as sqlite from 'rado/sqlite'
125
- import {sqliteTable as table} from 'rado/sqlite'
194
+ Aggregate rows using the `include` function:
126
195
 
127
- const User = table({
128
- id: sqlite.integer().primaryKey(),
129
- userName: sqlite.text('user') // Column names are optional
130
- })
196
+ ```typescript
197
+ import {include} from 'rado'
131
198
 
132
- const Post = table({
133
- id: sqlite.integer().primaryKey(),
134
- userId: sqlite.integer().references(() => User.id),
135
- content: sqlite.text()
136
- })
199
+ const usersWithPosts = await db.select({
200
+ ...User,
201
+ posts: include(
202
+ db.select().from(Post).where(eq(Post.authorId, User.id))
203
+ )
204
+ }).from(User)
137
205
 
138
- const Tag = table({
139
- id: sqlite.integer().primaryKey(),
140
- name: sqlite.text()
141
- })
206
+ // Use include.one for a single related record
207
+ const usersWithLatestPost = await db.select({
208
+ ...User,
209
+ latestPost: include.one(
210
+ db.select()
211
+ .from(Post)
212
+ .where(eq(Post.authorId, User.id))
213
+ .orderBy(desc(Post.createdAt))
214
+ .limit(1)
215
+ )
216
+ }).from(User)
217
+ ```
142
218
 
143
- const PostTags = table({
144
- postId: sqlite.integer().references(() => Post.id),
145
- tagId: sqlite.integer().references(() => Tag.id)
146
- })
219
+ ### SQL Operator
220
+
221
+ The `sql` operator allows you to write raw SQL and interpolate values safely:
222
+
223
+ ```typescript
224
+ import {sql} from 'rado'
225
+
226
+ const minAge = 18
227
+ const adultUsers = await db.select()
228
+ .from(User)
229
+ .where(sql`${User.age} >= ${minAge}`)
147
230
  ```
148
231
 
149
- ## Connections
232
+ ## Modifying Data
150
233
 
151
- Currently supported drivers:
234
+ ### Insert
152
235
 
153
- | `PostgreSQL ` | `import ` |
154
- | -------------------------- | ------------------------------ |
155
- | `pg` | `'rado/driver/pg'` |
156
- | `@electric-sql/pglite` | `'rado/driver/pglite'` |
157
- | `@neondatabase/serverless` | `'rado/driver/pg'` |
158
- | `@vercel/postgres` | `'rado/driver/pg'` |
236
+ Insert operations allow you to add new records to your database:
159
237
 
160
- | `SQLite ` | `import ` |
161
- | -------------------------- | ------------------------------ |
162
- | `better-sqlite3` | `'rado/driver/better-sqlite3'` |
163
- | `bun:sqlite` | `'rado/driver/bun-sqlite'` |
164
- | `sql.js` | `'rado/driver/sql.js'` |
165
- | `Cloudflare D1` | `'rado/driver/d1'` |
238
+ ```typescript
239
+ // Single insert
240
+ const newUser = await db.insert(User)
241
+ .values({name: 'Alice', email: 'alice@example.com'})
242
+ .returning()
166
243
 
167
- | `MySQL ` | `import ` |
168
- | -------------------------- | ------------------------------ |
169
- | `mysql2` | `'rado/driver/mysql2'` |
244
+ // Bulk insert
245
+ const newUsers = await db.insert(User)
246
+ .values([
247
+ {name: 'Bob', email: 'bob@example.com'},
248
+ {name: 'Charlie', email: 'charlie@example.com'},
249
+ ])
250
+ .returning()
251
+ ```
170
252
 
171
- Pass an instance of the database to the `connect` function to get started:
253
+ ### Update
172
254
 
173
- ```ts
174
- import Database from 'better-sqlite3'
175
- import {connect} from 'rado/driver/better-sqlite3'
255
+ Update operations modify existing records:
176
256
 
177
- const db = connect(new Database('foobar.db'))
257
+ ```typescript
258
+ const updatedCount = await db.update(User)
259
+ .set({name: 'Johnny'})
260
+ .where(eq(User.name, 'John'))
178
261
  ```
179
262
 
263
+ ### Delete
180
264
 
181
- #### Run queries
265
+ Delete operations remove records from your database:
182
266
 
183
- Call the connection with a query to retrieve its results:
267
+ ```typescript
268
+ await db.delete(User).where(eq(User.name, 'John'))
269
+ ```
184
270
 
185
- ```ts
186
- // For sync drivers this will be an array:
187
- const posts = db.select().from(Post).all()
188
- // For async drivers this will be a Promise:
189
- const posts = await db.select().from(Post)
271
+ ### Transactions
272
+
273
+ Transactions allow you to group multiple operations into a single atomic unit.
274
+
275
+ ```typescript
276
+ const result = await db.transaction(async (tx) => {
277
+ const user = await tx.insert(User)
278
+ .values({ name: 'Alice', email: 'alice@example.com' })
279
+ .returning()
280
+ const post = await tx.insert(Post)
281
+ .values({ title: 'My First Post', authorId: user.id })
282
+ .returning()
283
+ return {user, post}
284
+ })
190
285
  ```
191
286
 
192
- #### Transactions
287
+ ## Universal Queries
193
288
 
194
- Run transactions within the `transaction` method which will isolate a connection
195
- and can optionally return a result:
289
+ Rado provides a universal query builder that works across different database
290
+ engines, whether they run synchronously or asynchronously. This is useful for
291
+ writing database-agnostic code.
196
292
 
197
- ```ts
198
- const firstUserId = db.transaction(tx => {
199
- const createTable = db.create(User)
200
- tx(createTable)
201
- const insertUser = db.insert(User).values({username: 'Mario'}).returning(User.id)
202
- return tx(insertUser)
293
+ ```typescript
294
+ import {table} from 'rado'
295
+ import {id, text} from 'rado/universal'
296
+
297
+ const User = table('user', {
298
+ id: id(),
299
+ name: text()
203
300
  })
301
+
302
+ const db = process.env.SQLITE ? sqliteDb : postgresDb
303
+
304
+ const userNames = await db.select(User.name).from(User)
204
305
  ```
306
+
307
+ ## Custom Column Types
308
+
309
+ You can define custom column types, such as a boolean column that is stored as a
310
+ tinyint in the database:
311
+
312
+ ```typescript
313
+ import {Column, column, table, sql} from 'rado'
314
+
315
+ export function bool(name?: string): Column<boolean | null> {
316
+ return column({
317
+ name,
318
+ type: sql`tinyint(1)`,
319
+ mapFromDriverValue(value: number): boolean {
320
+ return value === 1
321
+ },
322
+ mapToDriverValue(value: boolean): number {
323
+ return value ? 1 : 0
324
+ }
325
+ })
326
+ }
327
+
328
+ // Usage
329
+ const User = table('user', {
330
+ // ...
331
+ isActive: bool()
332
+ })
333
+ ```
@@ -1,8 +1,10 @@
1
1
  import type { Emitter } from './Emitter.js';
2
2
  import { type HasQuery, type HasSql } from './Internal.js';
3
+ import type { Runtime } from './MetaData.js';
3
4
  export declare class Dialect {
4
5
  #private;
5
- constructor(createEmitter: new () => Emitter);
6
+ runtime: Runtime;
7
+ constructor(runtime: Runtime, createEmitter: new (runtime: Runtime) => Emitter);
6
8
  emit: (input: HasSql | HasQuery) => Emitter;
7
9
  inline: (input: HasSql | HasQuery) => string;
8
10
  }
@@ -5,19 +5,21 @@ import {
5
5
  hasQuery
6
6
  } from "./Internal.js";
7
7
  var Dialect = class {
8
+ runtime;
8
9
  #createEmitter;
9
- constructor(createEmitter) {
10
+ constructor(runtime, createEmitter) {
11
+ this.runtime = runtime;
10
12
  this.#createEmitter = createEmitter;
11
13
  }
12
14
  emit = (input) => {
13
15
  const sql = hasQuery(input) ? getQuery(input) : getSql(input);
14
- const emitter = new this.#createEmitter();
16
+ const emitter = new this.#createEmitter(this.runtime);
15
17
  sql.emitTo(emitter);
16
18
  return emitter;
17
19
  };
18
20
  inline = (input) => {
19
21
  const sql = hasQuery(input) ? getQuery(input) : getSql(input);
20
- const emitter = new this.#createEmitter();
22
+ const emitter = new this.#createEmitter(this.runtime);
21
23
  sql.inlineValues().emitTo(emitter);
22
24
  return emitter.sql;
23
25
  };
@@ -8,6 +8,7 @@ export interface BatchQuery {
8
8
  }
9
9
  export interface DriverSpecs {
10
10
  parsesJson: boolean;
11
+ supportsTransactions: boolean;
11
12
  }
12
13
  export interface PrepareOptions {
13
14
  isSelection: boolean;
@@ -13,17 +13,18 @@ import type { SelectData } from './query/Select.js';
13
13
  import type { UnionData } from './query/Union.js';
14
14
  import type { Update } from './query/Update.js';
15
15
  export declare abstract class Emitter {
16
+ #private;
16
17
  sql: string;
17
18
  protected params: Array<Param>;
18
- get hasParams(): boolean;
19
- bind(inputs?: Record<string, unknown>): Array<unknown>;
20
- processValue(value: unknown): unknown;
21
- abstract runtime: Runtime;
22
19
  abstract emitIdentifier(value: string): void;
23
20
  abstract emitValue(value: unknown): void;
24
21
  abstract emitInline(value: unknown): void;
25
22
  abstract emitJsonPath(path: JsonPath): void;
26
23
  abstract emitPlaceholder(value: string): void;
24
+ constructor(runtime: Runtime);
25
+ get hasParams(): boolean;
26
+ bind(inputs?: Record<string, unknown>): Array<unknown>;
27
+ processValue(value: unknown): unknown;
27
28
  emitIdentifierOrSelf(value: string): void;
28
29
  selfName?: string;
29
30
  emitSelf({ name, inner }: {
@@ -10,8 +10,12 @@ import { Sql, sql } from "./Sql.js";
10
10
  import { callFunction } from "./expr/Functions.js";
11
11
  import { jsonAggregateArray, jsonArray } from "./expr/Json.js";
12
12
  var Emitter = class {
13
+ #runtime;
13
14
  sql = "";
14
15
  params = [];
16
+ constructor(runtime) {
17
+ this.#runtime = runtime;
18
+ }
15
19
  get hasParams() {
16
20
  return this.params.length > 0;
17
21
  }
@@ -85,7 +89,15 @@ var Emitter = class {
85
89
  }).emitTo(this);
86
90
  }
87
91
  emitInsert(insert) {
88
- const { cte, into, values, select, onConflict, returning } = getData(insert);
92
+ const {
93
+ cte,
94
+ into,
95
+ values,
96
+ select,
97
+ onConflict,
98
+ onDuplicateKeyUpdate,
99
+ returning
100
+ } = getData(insert);
89
101
  if (cte) this.emitWith(cte);
90
102
  const table = getTable(into);
91
103
  const tableName = sql.identifier(table.name);
@@ -93,6 +105,7 @@ var Emitter = class {
93
105
  insertInto: sql`${tableName}(${table.listColumns()})`,
94
106
  ...values ? { values } : { "": select },
95
107
  onConflict,
108
+ onDuplicateKeyUpdate,
96
109
  returning
97
110
  }).inlineFields(false).emitTo(this);
98
111
  }
@@ -160,7 +173,7 @@ var Emitter = class {
160
173
  sql`(select ${data.first ? subject : jsonAggregateArray(subject)} from (${inner}) as _)`.emitTo(this);
161
174
  }
162
175
  emitUniversal(runtimes) {
163
- const sql2 = runtimes[this.runtime] ?? runtimes.default;
176
+ const sql2 = runtimes[this.#runtime] ?? runtimes.default;
164
177
  if (!sql2) throw new Error("Unsupported runtime");
165
178
  sql2.emitTo(this);
166
179
  }
@@ -1,5 +1,5 @@
1
1
  import { type HasSql, type HasTable, internalData, internalQuery, internalSelection } from '../Internal.js';
2
- import type { IsPostgres, IsSqlite, QueryMeta } from '../MetaData.js';
2
+ import type { IsMysql, IsPostgres, IsSqlite, QueryMeta } from '../MetaData.js';
3
3
  import { Query, type QueryData } from '../Query.js';
4
4
  import { type Selection, type SelectionInput, type SelectionRow } from '../Selection.js';
5
5
  import { type Sql } from '../Sql.js';
@@ -12,6 +12,7 @@ interface InsertIntoData<Meta extends QueryMeta> extends QueryData<Meta> {
12
12
  export interface InsertData<Meta extends QueryMeta> extends InsertIntoData<Meta> {
13
13
  returning?: Selection;
14
14
  onConflict?: HasSql;
15
+ onDuplicateKeyUpdate?: HasSql;
15
16
  }
16
17
  export declare class Insert<Result, Meta extends QueryMeta = QueryMeta> extends Query<Result, Meta> {
17
18
  readonly [internalData]: InsertData<Meta>;
@@ -27,14 +28,17 @@ export interface OnConflict {
27
28
  target: HasSql | Array<HasSql>;
28
29
  targetWhere?: HasSql<boolean>;
29
30
  }
30
- export interface OnConflictUpdate<Definition extends TableDefinition> extends OnConflict {
31
+ export interface OnConflictSet<Definition extends TableDefinition> {
31
32
  set: TableUpdate<Definition>;
33
+ }
34
+ export interface OnConflictUpdate<Definition extends TableDefinition> extends OnConflict, OnConflictSet<Definition> {
32
35
  setWhere?: HasSql<boolean>;
33
36
  }
34
37
  declare class InsertCanConflict<Definition extends TableDefinition, Meta extends QueryMeta> extends InsertCanReturn<Definition, Meta> {
35
38
  #private;
36
- onConflictDoNothing(this: InsertCanConflict<Definition, IsPostgres>, onConflict?: OnConflict): InsertCanReturn<Definition, Meta>;
37
- onConflictDoUpdate(this: InsertCanConflict<Definition, IsPostgres>, onConflict: OnConflictUpdate<Definition>): InsertCanReturn<Definition, Meta>;
39
+ onConflictDoNothing(this: InsertCanConflict<Definition, IsPostgres | IsSqlite>, onConflict?: OnConflict): InsertCanReturn<Definition, Meta>;
40
+ onConflictDoUpdate(this: InsertCanConflict<Definition, IsPostgres | IsSqlite>, onConflict: OnConflictUpdate<Definition>): InsertCanReturn<Definition, Meta>;
41
+ onDuplicateKeyUpdate(this: InsertCanConflict<Definition, IsMysql>, update: OnConflictSet<Definition>): InsertCanReturn<Definition, Meta>;
38
42
  }
39
43
  export declare class InsertInto<Definition extends TableDefinition, Meta extends QueryMeta> {
40
44
  [internalData]: InsertData<Meta>;
@@ -40,18 +40,27 @@ var InsertCanConflict = class extends InsertCanReturn {
40
40
  onConflictDoUpdate(onConflict) {
41
41
  return this.#onConflict(onConflict);
42
42
  }
43
+ onDuplicateKeyUpdate(update) {
44
+ return new InsertCanReturn({
45
+ ...getData(this),
46
+ onDuplicateKeyUpdate: this.#updateFields(update.set)
47
+ });
48
+ }
49
+ #updateFields(update) {
50
+ return sql.join(
51
+ Object.entries(update).map(
52
+ ([key, value]) => sql`${sql.identifier(key)} = ${input(value)}`
53
+ ),
54
+ sql`, `
55
+ );
56
+ }
43
57
  #onConflict({
44
58
  target,
45
59
  targetWhere,
46
60
  set,
47
61
  setWhere
48
62
  }) {
49
- const update = set && sql.join(
50
- Object.entries(set).map(
51
- ([key, value]) => sql`${sql.identifier(key)} = ${input(value)}`
52
- ),
53
- sql`, `
54
- );
63
+ const update = set && this.#updateFields(set);
55
64
  return new InsertCanReturn({
56
65
  ...getData(this),
57
66
  onConflict: sql.join([
@@ -32,6 +32,7 @@ var BetterSqlite3Driver = class _BetterSqlite3Driver {
32
32
  this.depth = depth;
33
33
  }
34
34
  parsesJson = false;
35
+ supportsTransactions = true;
35
36
  exec(query) {
36
37
  this.client.exec(query);
37
38
  }
@@ -29,6 +29,7 @@ var BunSqliteDriver = class _BunSqliteDriver {
29
29
  this.depth = depth;
30
30
  }
31
31
  parsesJson = false;
32
+ supportsTransactions = true;
32
33
  exec(query) {
33
34
  this.client.exec(query);
34
35
  }
@@ -14,6 +14,7 @@ declare class PreparedStatement implements AsyncStatement {
14
14
  export declare class D1Driver implements AsyncDriver {
15
15
  private client;
16
16
  parsesJson: boolean;
17
+ supportsTransactions: boolean;
17
18
  constructor(client: Client);
18
19
  exec(query: string): Promise<void>;
19
20
  prepare(sql: string, options: PrepareOptions): PreparedStatement;
package/dist/driver/d1.js CHANGED
@@ -17,11 +17,7 @@ var PreparedStatement = class {
17
17
  return this.stmt.bind(...params).first();
18
18
  }
19
19
  async values(params) {
20
- if (this.isSelection) {
21
- const results = await this.stmt.bind(...params).raw();
22
- console.log(results);
23
- return results;
24
- }
20
+ if (this.isSelection) return this.stmt.bind(...params).raw();
25
21
  await this.stmt.bind(...params).run();
26
22
  return [];
27
23
  }
@@ -33,6 +29,7 @@ var D1Driver = class {
33
29
  this.client = client;
34
30
  }
35
31
  parsesJson = false;
32
+ supportsTransactions = false;
36
33
  async exec(query) {
37
34
  await this.client.exec(query);
38
35
  }
@@ -42,10 +39,11 @@ var D1Driver = class {
42
39
  async close() {
43
40
  }
44
41
  async batch(queries) {
45
- const results = [];
46
- for (const { sql, params, isSelection } of queries)
47
- results.push(await this.prepare(sql, { isSelection }).values(params));
48
- return results;
42
+ const stmts = queries.map(
43
+ ({ sql, params }) => this.client.prepare(sql).bind(...params)
44
+ );
45
+ const rows = await this.client.batch(stmts);
46
+ return rows.map((row) => row.results);
49
47
  }
50
48
  async transaction() {
51
49
  throw new Error("Transactions are not supported in D1");
@@ -19,6 +19,7 @@ export declare class Mysql2Driver implements AsyncDriver {
19
19
  private client;
20
20
  private depth;
21
21
  parsesJson: boolean;
22
+ supportsTransactions: boolean;
22
23
  constructor(client: Queryable, depth?: number);
23
24
  exec(query: string): Promise<void>;
24
25
  prepare(sql: string, options?: PrepareOptions): PreparedStatement;
@@ -38,6 +38,7 @@ var Mysql2Driver = class _Mysql2Driver {
38
38
  this.depth = depth;
39
39
  }
40
40
  parsesJson = true;
41
+ supportsTransactions = true;
41
42
  async exec(query) {
42
43
  await this.client.query(query);
43
44
  }
@@ -17,6 +17,7 @@ export declare class PgDriver implements AsyncDriver {
17
17
  private client;
18
18
  private depth;
19
19
  parsesJson: boolean;
20
+ supportsTransactions: boolean;
20
21
  constructor(client: Queryable, depth?: number);
21
22
  exec(query: string): Promise<void>;
22
23
  prepare(sql: string, options?: PrepareOptions): PreparedStatement;
package/dist/driver/pg.js CHANGED
@@ -46,6 +46,7 @@ var PgDriver = class _PgDriver {
46
46
  this.depth = depth;
47
47
  }
48
48
  parsesJson = true;
49
+ supportsTransactions = true;
49
50
  async exec(query) {
50
51
  await this.client.query(query);
51
52
  }
@@ -16,6 +16,7 @@ export declare class PGliteDriver implements AsyncDriver {
16
16
  private client;
17
17
  private depth;
18
18
  parsesJson: boolean;
19
+ supportsTransactions: boolean;
19
20
  constructor(client: Queryable, depth?: number);
20
21
  exec(query: string): Promise<void>;
21
22
  close(): Promise<void>;
@@ -35,6 +35,7 @@ var PGliteDriver = class _PGliteDriver {
35
35
  this.depth = depth;
36
36
  }
37
37
  parsesJson = true;
38
+ supportsTransactions = true;
38
39
  async exec(query) {
39
40
  await this.client.exec(query);
40
41
  }
@@ -42,6 +42,7 @@ var SqlJsDriver = class _SqlJsDriver {
42
42
  this.depth = depth;
43
43
  }
44
44
  parsesJson = false;
45
+ supportsTransactions = true;
45
46
  exec(query) {
46
47
  this.client.exec(query);
47
48
  }
@@ -9,6 +9,7 @@ var SINGLE_QUOTE = "'";
9
9
  var ESCAPE_SINGLE_QUOTE = "''";
10
10
  var MATCH_SINGLE_QUOTE = /'/g;
11
11
  var mysqlDialect = new Dialect(
12
+ "mysql",
12
13
  class extends Emitter {
13
14
  runtime = "mysql";
14
15
  paramIndex = 0;
@@ -9,6 +9,7 @@ var SINGLE_QUOTE = "'";
9
9
  var ESCAPE_SINGLE_QUOTE = "''";
10
10
  var MATCH_SINGLE_QUOTE = /'/g;
11
11
  var postgresDialect = new Dialect(
12
+ "postgres",
12
13
  class extends Emitter {
13
14
  runtime = "postgres";
14
15
  paramIndex = 0;
@@ -9,8 +9,8 @@ var SINGLE_QUOTE = "'";
9
9
  var ESCAPE_SINGLE_QUOTE = "''";
10
10
  var MATCH_SINGLE_QUOTE = /'/g;
11
11
  var sqliteDialect = new Dialect(
12
+ "sqlite",
12
13
  class extends Emitter {
13
- runtime = "sqlite";
14
14
  processValue(value) {
15
15
  return typeof value === "boolean" ? value ? 1 : 0 : value;
16
16
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rado",
3
- "version": "1.0.10",
3
+ "version": "1.0.11",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "scripts": {