@tursodatabase/serverless 0.1.1 → 0.1.3

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.
@@ -11,11 +11,26 @@ import { type SessionConfig } from './session.js';
11
11
  export declare class Statement {
12
12
  private session;
13
13
  private sql;
14
+ private presentationMode;
14
15
  constructor(sessionConfig: SessionConfig, sql: string);
16
+ /**
17
+ * Enable raw mode to return arrays instead of objects.
18
+ *
19
+ * @param raw Enable or disable raw mode. If you don't pass the parameter, raw mode is enabled.
20
+ * @returns This statement instance for chaining
21
+ *
22
+ * @example
23
+ * ```typescript
24
+ * const stmt = client.prepare("SELECT * FROM users WHERE id = ?");
25
+ * const row = await stmt.raw().get([1]);
26
+ * console.log(row); // [1, "Alice", "alice@example.org"]
27
+ * ```
28
+ */
29
+ raw(raw?: boolean): Statement;
15
30
  /**
16
31
  * Executes the prepared statement.
17
32
  *
18
- * @param args - Optional array of parameter values for the SQL statement
33
+ * @param args - Optional array of parameter values or object with named parameters
19
34
  * @returns Promise resolving to the result of the statement
20
35
  *
21
36
  * @example
@@ -25,12 +40,12 @@ export declare class Statement {
25
40
  * console.log(`Inserted user with ID ${result.lastInsertRowid}`);
26
41
  * ```
27
42
  */
28
- run(args?: any[]): Promise<any>;
43
+ run(args?: any): Promise<any>;
29
44
  /**
30
45
  * Execute the statement and return the first row.
31
46
  *
32
- * @param args - Optional array of parameter values for the SQL statement
33
- * @returns Promise resolving to the first row or null if no results
47
+ * @param args - Optional array of parameter values or object with named parameters
48
+ * @returns Promise resolving to the first row or undefined if no results
34
49
  *
35
50
  * @example
36
51
  * ```typescript
@@ -41,11 +56,11 @@ export declare class Statement {
41
56
  * }
42
57
  * ```
43
58
  */
44
- get(args?: any[]): Promise<any>;
59
+ get(args?: any): Promise<any>;
45
60
  /**
46
61
  * Execute the statement and return all rows.
47
62
  *
48
- * @param args - Optional array of parameter values for the SQL statement
63
+ * @param args - Optional array of parameter values or object with named parameters
49
64
  * @returns Promise resolving to an array of all result rows
50
65
  *
51
66
  * @example
@@ -55,14 +70,14 @@ export declare class Statement {
55
70
  * console.log(`Found ${activeUsers.length} active users`);
56
71
  * ```
57
72
  */
58
- all(args?: any[]): Promise<any[]>;
73
+ all(args?: any): Promise<any[]>;
59
74
  /**
60
75
  * Execute the statement and return an async iterator for streaming results.
61
76
  *
62
77
  * This method provides memory-efficient processing of large result sets
63
78
  * by streaming rows one at a time instead of loading everything into memory.
64
79
  *
65
- * @param args - Optional array of parameter values for the SQL statement
80
+ * @param args - Optional array of parameter values or object with named parameters
66
81
  * @returns AsyncGenerator that yields individual rows
67
82
  *
68
83
  * @example
@@ -74,5 +89,10 @@ export declare class Statement {
74
89
  * }
75
90
  * ```
76
91
  */
77
- iterate(args?: any[]): AsyncGenerator<any>;
92
+ iterate(args?: any): AsyncGenerator<any>;
93
+ /**
94
+ * Normalize arguments to handle both single values and arrays.
95
+ * Matches the behavior of the native bindings.
96
+ */
97
+ private normalizeArgs;
78
98
  }
package/dist/statement.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { decodeValue } from './protocol.js';
2
2
  import { Session } from './session.js';
3
+ import { DatabaseError } from './error.js';
3
4
  /**
4
5
  * A prepared SQL statement that can be executed in multiple ways.
5
6
  *
@@ -11,13 +12,31 @@ import { Session } from './session.js';
11
12
  */
12
13
  export class Statement {
13
14
  constructor(sessionConfig, sql) {
15
+ this.presentationMode = 'expanded';
14
16
  this.session = new Session(sessionConfig);
15
17
  this.sql = sql;
16
18
  }
19
+ /**
20
+ * Enable raw mode to return arrays instead of objects.
21
+ *
22
+ * @param raw Enable or disable raw mode. If you don't pass the parameter, raw mode is enabled.
23
+ * @returns This statement instance for chaining
24
+ *
25
+ * @example
26
+ * ```typescript
27
+ * const stmt = client.prepare("SELECT * FROM users WHERE id = ?");
28
+ * const row = await stmt.raw().get([1]);
29
+ * console.log(row); // [1, "Alice", "alice@example.org"]
30
+ * ```
31
+ */
32
+ raw(raw) {
33
+ this.presentationMode = raw === false ? 'expanded' : 'raw';
34
+ return this;
35
+ }
17
36
  /**
18
37
  * Executes the prepared statement.
19
38
  *
20
- * @param args - Optional array of parameter values for the SQL statement
39
+ * @param args - Optional array of parameter values or object with named parameters
21
40
  * @returns Promise resolving to the result of the statement
22
41
  *
23
42
  * @example
@@ -27,15 +46,16 @@ export class Statement {
27
46
  * console.log(`Inserted user with ID ${result.lastInsertRowid}`);
28
47
  * ```
29
48
  */
30
- async run(args = []) {
31
- const result = await this.session.execute(this.sql, args);
49
+ async run(args) {
50
+ const normalizedArgs = this.normalizeArgs(args);
51
+ const result = await this.session.execute(this.sql, normalizedArgs);
32
52
  return { changes: result.rowsAffected, lastInsertRowid: result.lastInsertRowid };
33
53
  }
34
54
  /**
35
55
  * Execute the statement and return the first row.
36
56
  *
37
- * @param args - Optional array of parameter values for the SQL statement
38
- * @returns Promise resolving to the first row or null if no results
57
+ * @param args - Optional array of parameter values or object with named parameters
58
+ * @returns Promise resolving to the first row or undefined if no results
39
59
  *
40
60
  * @example
41
61
  * ```typescript
@@ -46,14 +66,24 @@ export class Statement {
46
66
  * }
47
67
  * ```
48
68
  */
49
- async get(args = []) {
50
- const result = await this.session.execute(this.sql, args);
51
- return result.rows[0] || null;
69
+ async get(args) {
70
+ const normalizedArgs = this.normalizeArgs(args);
71
+ const result = await this.session.execute(this.sql, normalizedArgs);
72
+ const row = result.rows[0];
73
+ if (!row) {
74
+ return undefined;
75
+ }
76
+ if (this.presentationMode === 'raw') {
77
+ // In raw mode, return the row as a plain array (it already is one)
78
+ // The row object is already an array with column properties added
79
+ return [...row];
80
+ }
81
+ return row;
52
82
  }
53
83
  /**
54
84
  * Execute the statement and return all rows.
55
85
  *
56
- * @param args - Optional array of parameter values for the SQL statement
86
+ * @param args - Optional array of parameter values or object with named parameters
57
87
  * @returns Promise resolving to an array of all result rows
58
88
  *
59
89
  * @example
@@ -63,9 +93,19 @@ export class Statement {
63
93
  * console.log(`Found ${activeUsers.length} active users`);
64
94
  * ```
65
95
  */
66
- async all(args = []) {
67
- const result = await this.session.execute(this.sql, args);
68
- return result.rows;
96
+ async all(args) {
97
+ const normalizedArgs = this.normalizeArgs(args);
98
+ const result = await this.session.execute(this.sql, normalizedArgs);
99
+ if (this.presentationMode === 'raw') {
100
+ return result.rows.map((row) => [...row]);
101
+ }
102
+ return result.rows.map((row) => {
103
+ const obj = {};
104
+ result.columns.forEach((col, i) => {
105
+ obj[col] = row[i];
106
+ });
107
+ return obj;
108
+ });
69
109
  }
70
110
  /**
71
111
  * Execute the statement and return an async iterator for streaming results.
@@ -73,7 +113,7 @@ export class Statement {
73
113
  * This method provides memory-efficient processing of large result sets
74
114
  * by streaming rows one at a time instead of loading everything into memory.
75
115
  *
76
- * @param args - Optional array of parameter values for the SQL statement
116
+ * @param args - Optional array of parameter values or object with named parameters
77
117
  * @returns AsyncGenerator that yields individual rows
78
118
  *
79
119
  * @example
@@ -85,8 +125,9 @@ export class Statement {
85
125
  * }
86
126
  * ```
87
127
  */
88
- async *iterate(args = []) {
89
- const { response, entries } = await this.session.executeRaw(this.sql, args);
128
+ async *iterate(args) {
129
+ const normalizedArgs = this.normalizeArgs(args);
130
+ const { response, entries } = await this.session.executeRaw(this.sql, normalizedArgs);
90
131
  let columns = [];
91
132
  for await (const entry of entries) {
92
133
  switch (entry.type) {
@@ -98,14 +139,40 @@ export class Statement {
98
139
  case 'row':
99
140
  if (entry.row) {
100
141
  const decodedRow = entry.row.map(decodeValue);
101
- const rowObject = this.session.createRowObject(decodedRow, columns);
102
- yield rowObject;
142
+ if (this.presentationMode === 'raw') {
143
+ // In raw mode, yield arrays of values
144
+ yield decodedRow;
145
+ }
146
+ else {
147
+ const rowObject = this.session.createRowObject(decodedRow, columns);
148
+ yield rowObject;
149
+ }
103
150
  }
104
151
  break;
105
152
  case 'step_error':
106
153
  case 'error':
107
- throw new Error(entry.error?.message || 'SQL execution failed');
154
+ throw new DatabaseError(entry.error?.message || 'SQL execution failed');
108
155
  }
109
156
  }
110
157
  }
158
+ /**
159
+ * Normalize arguments to handle both single values and arrays.
160
+ * Matches the behavior of the native bindings.
161
+ */
162
+ normalizeArgs(args) {
163
+ // No arguments provided
164
+ if (args === undefined) {
165
+ return [];
166
+ }
167
+ // If it's an array, return as-is
168
+ if (Array.isArray(args)) {
169
+ return args;
170
+ }
171
+ // Check if it's a plain object (for named parameters)
172
+ if (args !== null && typeof args === 'object' && args.constructor === Object) {
173
+ return args;
174
+ }
175
+ // Single value - wrap in array
176
+ return [args];
177
+ }
111
178
  }
@@ -0,0 +1,131 @@
1
+ import { type SessionConfig } from "./session.js";
2
+ /**
3
+ * Transaction mode for controlling transaction behavior.
4
+ */
5
+ export type TransactionMode = "write" | "read" | "deferred";
6
+ /**
7
+ * Transactions use a dedicated session to maintain state across multiple operations.
8
+ * All operations within a transaction are executed atomically - they either all
9
+ * succeed or all fail.
10
+ */
11
+ export declare class Transaction {
12
+ private session;
13
+ private _closed;
14
+ private _committed;
15
+ private _rolledBack;
16
+ private constructor();
17
+ /**
18
+ * Create a new transaction instance.
19
+ *
20
+ * @param sessionConfig - Session configuration
21
+ * @param mode - Transaction mode
22
+ * @returns Promise resolving to a new Transaction instance
23
+ */
24
+ static create(sessionConfig: SessionConfig, mode?: TransactionMode): Promise<Transaction>;
25
+ private initializeTransaction;
26
+ /**
27
+ * Execute a SQL statement within the transaction.
28
+ *
29
+ * @param sql - The SQL statement to execute
30
+ * @param args - Optional array of parameter values
31
+ * @returns Promise resolving to the complete result set
32
+ *
33
+ * @example
34
+ * ```typescript
35
+ * const tx = await client.transaction();
36
+ * const result = await tx.execute("INSERT INTO users (name) VALUES (?)", ["Alice"]);
37
+ * await tx.commit();
38
+ * ```
39
+ */
40
+ execute(sql: string, args?: any[]): Promise<any>;
41
+ /**
42
+ * Execute multiple SQL statements as a batch within the transaction.
43
+ *
44
+ * @param statements - Array of SQL statements to execute
45
+ * @returns Promise resolving to batch execution results
46
+ *
47
+ * @example
48
+ * ```typescript
49
+ * const tx = await client.transaction();
50
+ * await tx.batch([
51
+ * "INSERT INTO users (name) VALUES ('Alice')",
52
+ * "INSERT INTO users (name) VALUES ('Bob')"
53
+ * ]);
54
+ * await tx.commit();
55
+ * ```
56
+ */
57
+ batch(statements: string[]): Promise<any>;
58
+ /**
59
+ * Execute a SQL statement and return the raw response and entries.
60
+ *
61
+ * @param sql - The SQL statement to execute
62
+ * @param args - Optional array of parameter values
63
+ * @returns Promise resolving to the raw response and cursor entries
64
+ */
65
+ executeRaw(sql: string, args?: any[]): Promise<{
66
+ response: any;
67
+ entries: AsyncGenerator<any>;
68
+ }>;
69
+ /**
70
+ * Commit the transaction, making all changes permanent.
71
+ *
72
+ * @returns Promise that resolves when the transaction is committed
73
+ *
74
+ * @example
75
+ * ```typescript
76
+ * const tx = await client.transaction();
77
+ * await tx.execute("INSERT INTO users (name) VALUES (?)", ["Alice"]);
78
+ * await tx.commit(); // Changes are now permanent
79
+ * ```
80
+ */
81
+ commit(): Promise<void>;
82
+ /**
83
+ * Rollback the transaction, undoing all changes.
84
+ *
85
+ * @returns Promise that resolves when the transaction is rolled back
86
+ *
87
+ * @example
88
+ * ```typescript
89
+ * const tx = await client.transaction();
90
+ * try {
91
+ * await tx.execute("INSERT INTO users (name) VALUES (?)", ["Alice"]);
92
+ * await tx.execute("INSERT INTO invalid_table VALUES (1)"); // This will fail
93
+ * await tx.commit();
94
+ * } catch (error) {
95
+ * await tx.rollback(); // Undo the first INSERT
96
+ * }
97
+ * ```
98
+ */
99
+ rollback(): Promise<void>;
100
+ /**
101
+ * Close the transaction without committing or rolling back.
102
+ *
103
+ * This will automatically rollback any uncommitted changes.
104
+ * It's safe to call this method multiple times.
105
+ */
106
+ close(): void;
107
+ /**
108
+ * Check if the transaction is closed.
109
+ *
110
+ * @returns True if the transaction has been committed, rolled back, or closed
111
+ */
112
+ get closed(): boolean;
113
+ /**
114
+ * Check if the transaction has been committed.
115
+ *
116
+ * @returns True if the transaction has been successfully committed
117
+ */
118
+ get committed(): boolean;
119
+ /**
120
+ * Check if the transaction has been rolled back.
121
+ *
122
+ * @returns True if the transaction has been rolled back
123
+ */
124
+ get rolledBack(): boolean;
125
+ /**
126
+ * Check transaction state and throw if it's not valid for operations.
127
+ *
128
+ * @throws Error if the transaction is closed
129
+ */
130
+ private checkState;
131
+ }
@@ -0,0 +1,207 @@
1
+ import { Session } from "./session.js";
2
+ import { DatabaseError } from "./error.js";
3
+ /**
4
+ * Transactions use a dedicated session to maintain state across multiple operations.
5
+ * All operations within a transaction are executed atomically - they either all
6
+ * succeed or all fail.
7
+ */
8
+ export class Transaction {
9
+ constructor(sessionConfig, mode = "deferred") {
10
+ this._closed = false;
11
+ this._committed = false;
12
+ this._rolledBack = false;
13
+ this.session = new Session(sessionConfig);
14
+ }
15
+ /**
16
+ * Create a new transaction instance.
17
+ *
18
+ * @param sessionConfig - Session configuration
19
+ * @param mode - Transaction mode
20
+ * @returns Promise resolving to a new Transaction instance
21
+ */
22
+ static async create(sessionConfig, mode = "deferred") {
23
+ const transaction = new Transaction(sessionConfig, mode);
24
+ await transaction.initializeTransaction(mode);
25
+ return transaction;
26
+ }
27
+ async initializeTransaction(mode) {
28
+ let beginStatement;
29
+ switch (mode) {
30
+ case "write":
31
+ beginStatement = "BEGIN IMMEDIATE";
32
+ break;
33
+ case "read":
34
+ beginStatement = "BEGIN";
35
+ break;
36
+ case "deferred":
37
+ default:
38
+ beginStatement = "BEGIN DEFERRED";
39
+ break;
40
+ }
41
+ await this.session.execute(beginStatement);
42
+ }
43
+ /**
44
+ * Execute a SQL statement within the transaction.
45
+ *
46
+ * @param sql - The SQL statement to execute
47
+ * @param args - Optional array of parameter values
48
+ * @returns Promise resolving to the complete result set
49
+ *
50
+ * @example
51
+ * ```typescript
52
+ * const tx = await client.transaction();
53
+ * const result = await tx.execute("INSERT INTO users (name) VALUES (?)", ["Alice"]);
54
+ * await tx.commit();
55
+ * ```
56
+ */
57
+ async execute(sql, args = []) {
58
+ this.checkState();
59
+ return this.session.execute(sql, args);
60
+ }
61
+ /**
62
+ * Execute multiple SQL statements as a batch within the transaction.
63
+ *
64
+ * @param statements - Array of SQL statements to execute
65
+ * @returns Promise resolving to batch execution results
66
+ *
67
+ * @example
68
+ * ```typescript
69
+ * const tx = await client.transaction();
70
+ * await tx.batch([
71
+ * "INSERT INTO users (name) VALUES ('Alice')",
72
+ * "INSERT INTO users (name) VALUES ('Bob')"
73
+ * ]);
74
+ * await tx.commit();
75
+ * ```
76
+ */
77
+ async batch(statements) {
78
+ this.checkState();
79
+ return this.session.batch(statements);
80
+ }
81
+ /**
82
+ * Execute a SQL statement and return the raw response and entries.
83
+ *
84
+ * @param sql - The SQL statement to execute
85
+ * @param args - Optional array of parameter values
86
+ * @returns Promise resolving to the raw response and cursor entries
87
+ */
88
+ async executeRaw(sql, args = []) {
89
+ this.checkState();
90
+ return this.session.executeRaw(sql, args);
91
+ }
92
+ /**
93
+ * Commit the transaction, making all changes permanent.
94
+ *
95
+ * @returns Promise that resolves when the transaction is committed
96
+ *
97
+ * @example
98
+ * ```typescript
99
+ * const tx = await client.transaction();
100
+ * await tx.execute("INSERT INTO users (name) VALUES (?)", ["Alice"]);
101
+ * await tx.commit(); // Changes are now permanent
102
+ * ```
103
+ */
104
+ async commit() {
105
+ this.checkState();
106
+ try {
107
+ await this.session.execute("COMMIT");
108
+ this._committed = true;
109
+ this._closed = true;
110
+ }
111
+ catch (error) {
112
+ // If commit fails, the transaction is still open
113
+ if (error instanceof Error) {
114
+ throw new DatabaseError(error.message);
115
+ }
116
+ throw new DatabaseError('Transaction commit failed');
117
+ }
118
+ }
119
+ /**
120
+ * Rollback the transaction, undoing all changes.
121
+ *
122
+ * @returns Promise that resolves when the transaction is rolled back
123
+ *
124
+ * @example
125
+ * ```typescript
126
+ * const tx = await client.transaction();
127
+ * try {
128
+ * await tx.execute("INSERT INTO users (name) VALUES (?)", ["Alice"]);
129
+ * await tx.execute("INSERT INTO invalid_table VALUES (1)"); // This will fail
130
+ * await tx.commit();
131
+ * } catch (error) {
132
+ * await tx.rollback(); // Undo the first INSERT
133
+ * }
134
+ * ```
135
+ */
136
+ async rollback() {
137
+ if (this._closed) {
138
+ return; // Already closed, nothing to rollback
139
+ }
140
+ try {
141
+ await this.session.execute("ROLLBACK");
142
+ }
143
+ catch (error) {
144
+ // Rollback errors are generally not critical - the transaction is abandoned anyway
145
+ }
146
+ finally {
147
+ this._rolledBack = true;
148
+ this._closed = true;
149
+ }
150
+ }
151
+ /**
152
+ * Close the transaction without committing or rolling back.
153
+ *
154
+ * This will automatically rollback any uncommitted changes.
155
+ * It's safe to call this method multiple times.
156
+ */
157
+ close() {
158
+ if (!this._closed) {
159
+ // Async rollback - don't wait for it to complete
160
+ this.rollback().catch(() => {
161
+ // Ignore rollback errors on close
162
+ });
163
+ }
164
+ }
165
+ /**
166
+ * Check if the transaction is closed.
167
+ *
168
+ * @returns True if the transaction has been committed, rolled back, or closed
169
+ */
170
+ get closed() {
171
+ return this._closed;
172
+ }
173
+ /**
174
+ * Check if the transaction has been committed.
175
+ *
176
+ * @returns True if the transaction has been successfully committed
177
+ */
178
+ get committed() {
179
+ return this._committed;
180
+ }
181
+ /**
182
+ * Check if the transaction has been rolled back.
183
+ *
184
+ * @returns True if the transaction has been rolled back
185
+ */
186
+ get rolledBack() {
187
+ return this._rolledBack;
188
+ }
189
+ /**
190
+ * Check transaction state and throw if it's not valid for operations.
191
+ *
192
+ * @throws Error if the transaction is closed
193
+ */
194
+ checkState() {
195
+ if (this._closed) {
196
+ if (this._committed) {
197
+ throw new DatabaseError("Transaction has already been committed");
198
+ }
199
+ else if (this._rolledBack) {
200
+ throw new DatabaseError("Transaction has already been rolled back");
201
+ }
202
+ else {
203
+ throw new DatabaseError("Transaction has been closed");
204
+ }
205
+ }
206
+ }
207
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tursodatabase/serverless",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/dist/client.d.ts DELETED
@@ -1,31 +0,0 @@
1
- import { type CursorResponse, type CursorEntry } from './protocol.js';
2
- export interface Config {
3
- url: string;
4
- authToken: string;
5
- }
6
- export declare class Statement {
7
- private connection;
8
- private sql;
9
- private args;
10
- constructor(connection: Connection, sql: string, args?: any[]);
11
- get(): Promise<any>;
12
- all(): Promise<any[]>;
13
- iterate(): AsyncGenerator<any>;
14
- private execute;
15
- }
16
- export declare class Connection {
17
- private config;
18
- private baton;
19
- private baseUrl;
20
- constructor(config: Config);
21
- prepare(sql: string, args?: any[]): Statement;
22
- execute(sql: string, args?: any[]): Promise<any>;
23
- executeRaw(sql: string, args?: any[]): Promise<{
24
- response: CursorResponse;
25
- entries: AsyncGenerator<CursorEntry>;
26
- }>;
27
- private processCursorEntries;
28
- createRowObject(values: any[], columns: string[]): any;
29
- batch(statements: string[], mode?: string): Promise<any>;
30
- }
31
- export declare function connect(config: Config): Connection;