@pineliner/odb-client 1.0.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.
- package/README.md +316 -0
- package/dist/core/client.d.ts +110 -0
- package/dist/core/client.d.ts.map +1 -0
- package/dist/core/http-client.d.ts +37 -0
- package/dist/core/http-client.d.ts.map +1 -0
- package/dist/core/sql-parser.d.ts +70 -0
- package/dist/core/sql-parser.d.ts.map +1 -0
- package/dist/core/transaction.d.ts +60 -0
- package/dist/core/transaction.d.ts.map +1 -0
- package/dist/index.cjs +1052 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +992 -0
- package/dist/service/service-client.d.ts +151 -0
- package/dist/service/service-client.d.ts.map +1 -0
- package/dist/types.d.ts +75 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +44 -0
- package/src/core/client.ts +277 -0
- package/src/core/http-client.ts +200 -0
- package/src/core/sql-parser.ts +330 -0
- package/src/core/transaction.ts +425 -0
- package/src/index.ts +51 -0
- package/src/service/service-client.ts +316 -0
- package/src/types.ts +127 -0
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
import type { Transaction, QueryResult, TransactionCallback, SQLFragment } from '../types.ts';
|
|
2
|
+
import type { HTTPClient } from './http-client.ts';
|
|
3
|
+
import { SQLParser } from './sql-parser.ts';
|
|
4
|
+
import { QueryError } from '../types.ts';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Create a transaction function similar to the main sql function
|
|
8
|
+
*/
|
|
9
|
+
export function createTransaction(httpClient: HTTPClient): Transaction {
|
|
10
|
+
let isCommitted = false;
|
|
11
|
+
let isRolledBack = false;
|
|
12
|
+
const queries: Array<{ sql: string; params: any[] }> = [];
|
|
13
|
+
|
|
14
|
+
const checkTransactionState = (): void => {
|
|
15
|
+
if (isCommitted) {
|
|
16
|
+
throw new QueryError('Transaction has already been committed');
|
|
17
|
+
}
|
|
18
|
+
if (isRolledBack) {
|
|
19
|
+
throw new QueryError('Transaction has been rolled back');
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const isReadQuery = (sql: string): boolean => {
|
|
24
|
+
const trimmed = sql.trim().toUpperCase();
|
|
25
|
+
return trimmed.startsWith('SELECT') ||
|
|
26
|
+
trimmed.startsWith('WITH') ||
|
|
27
|
+
trimmed.startsWith('EXPLAIN') ||
|
|
28
|
+
trimmed.startsWith('PRAGMA');
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// Create the callable transaction function with context awareness
|
|
32
|
+
const txFunction = <T = any>(sql: TemplateStringsArray | any, ...values: any[]): Promise<QueryResult<T>> | SQLFragment => {
|
|
33
|
+
checkTransactionState();
|
|
34
|
+
|
|
35
|
+
// Handle template string queries (returns Promise)
|
|
36
|
+
if (Array.isArray(sql) && (('raw' in sql) || (typeof sql[0] === 'string' && values.length >= 0))) {
|
|
37
|
+
const parsed = SQLParser.parse(sql, values);
|
|
38
|
+
|
|
39
|
+
// For read queries, execute immediately
|
|
40
|
+
if (isReadQuery(parsed.sql)) {
|
|
41
|
+
return httpClient.query<T>(parsed.sql, parsed.params);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// For write queries, queue them for batch execution
|
|
45
|
+
queries.push(parsed);
|
|
46
|
+
|
|
47
|
+
// Return a placeholder result for queued queries
|
|
48
|
+
return Promise.resolve({
|
|
49
|
+
rows: [],
|
|
50
|
+
rowsAffected: 0,
|
|
51
|
+
executionTime: 0
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Handle direct object/array inputs (returns SQLFragment for composing)
|
|
56
|
+
const parsed = SQLParser.parse(sql, values);
|
|
57
|
+
return {
|
|
58
|
+
text: parsed.sql,
|
|
59
|
+
values: parsed.params
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
// Attach utility methods to the transaction function
|
|
64
|
+
txFunction.raw = (text: string): string => SQLParser.raw(text);
|
|
65
|
+
txFunction.identifier = (name: string): string => SQLParser.identifier(name);
|
|
66
|
+
|
|
67
|
+
txFunction.commit = async (): Promise<void> => {
|
|
68
|
+
checkTransactionState();
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
// Execute BEGIN
|
|
72
|
+
await httpClient.query('BEGIN');
|
|
73
|
+
|
|
74
|
+
// Execute all queued queries
|
|
75
|
+
for (const query of queries) {
|
|
76
|
+
await httpClient.query(query.sql, query.params);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Commit the transaction
|
|
80
|
+
await httpClient.query('COMMIT');
|
|
81
|
+
|
|
82
|
+
isCommitted = true;
|
|
83
|
+
} catch (error) {
|
|
84
|
+
// Rollback on any error
|
|
85
|
+
try {
|
|
86
|
+
await httpClient.query('ROLLBACK');
|
|
87
|
+
} catch (rollbackError) {
|
|
88
|
+
// Ignore rollback errors
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
isRolledBack = true;
|
|
92
|
+
throw new QueryError(
|
|
93
|
+
`Transaction failed: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
94
|
+
undefined,
|
|
95
|
+
undefined,
|
|
96
|
+
error instanceof Error ? error : undefined
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
txFunction.rollback = async (): Promise<void> => {
|
|
102
|
+
checkTransactionState();
|
|
103
|
+
|
|
104
|
+
try {
|
|
105
|
+
// If we have any queries, we need to actually rollback
|
|
106
|
+
if (queries.length > 0) {
|
|
107
|
+
await httpClient.query('ROLLBACK');
|
|
108
|
+
}
|
|
109
|
+
} finally {
|
|
110
|
+
isRolledBack = true;
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
txFunction.savepoint = async <T = any>(callback: (sql: Transaction) => Promise<T>): Promise<T> => {
|
|
115
|
+
checkTransactionState();
|
|
116
|
+
|
|
117
|
+
// For batched transactions, create a sub-transaction that shares the same logic
|
|
118
|
+
// but manages its own query queue for savepoint isolation
|
|
119
|
+
let savepointCommitted = false;
|
|
120
|
+
const savepointQueries: Array<{ sql: string; params: any[] }> = [];
|
|
121
|
+
|
|
122
|
+
// Create a savepoint transaction that collects queries locally
|
|
123
|
+
const savepointTx = <U = any>(sql: TemplateStringsArray | any, ...values: any[]): Promise<QueryResult<U>> | SQLFragment => {
|
|
124
|
+
if (isCommitted || isRolledBack) {
|
|
125
|
+
throw new QueryError('Transaction is no longer active');
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Handle template string queries (returns Promise)
|
|
129
|
+
if (Array.isArray(sql) && 'raw' in sql && typeof sql[0] === 'string') {
|
|
130
|
+
const parsed = SQLParser.parse(sql, values);
|
|
131
|
+
|
|
132
|
+
// For read queries, execute immediately
|
|
133
|
+
if (isReadQuery(parsed.sql)) {
|
|
134
|
+
return httpClient.query<U>(parsed.sql, parsed.params);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// For write queries, queue them in the savepoint queue
|
|
138
|
+
savepointQueries.push(parsed);
|
|
139
|
+
|
|
140
|
+
// Return a placeholder result for queued queries
|
|
141
|
+
return Promise.resolve({
|
|
142
|
+
rows: [],
|
|
143
|
+
rowsAffected: 0,
|
|
144
|
+
executionTime: 0
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Handle direct object/array inputs (returns SQLFragment for composing)
|
|
149
|
+
const parsed = SQLParser.parse(sql, values);
|
|
150
|
+
return {
|
|
151
|
+
text: parsed.sql,
|
|
152
|
+
values: parsed.params
|
|
153
|
+
};
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
// Attach utility methods to the savepoint transaction
|
|
157
|
+
(savepointTx as any).raw = (text: string): string => SQLParser.raw(text);
|
|
158
|
+
(savepointTx as any).identifier = (name: string): string => SQLParser.identifier(name);
|
|
159
|
+
(savepointTx as any).commit = async (): Promise<void> => {
|
|
160
|
+
savepointCommitted = true;
|
|
161
|
+
};
|
|
162
|
+
(savepointTx as any).rollback = async (): Promise<void> => {
|
|
163
|
+
// Rollback just clears the savepoint queries
|
|
164
|
+
savepointQueries.length = 0;
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
try {
|
|
168
|
+
// Execute the callback with the savepoint transaction
|
|
169
|
+
const result = await callback(savepointTx as Transaction);
|
|
170
|
+
|
|
171
|
+
// If successful, commit the savepoint by adding queries to main transaction
|
|
172
|
+
if (savepointCommitted || savepointQueries.length > 0) {
|
|
173
|
+
queries.push(...savepointQueries);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return result;
|
|
177
|
+
} catch (error) {
|
|
178
|
+
// On error, we don't add the savepoint queries to our queue
|
|
179
|
+
// This simulates a rollback to savepoint
|
|
180
|
+
throw error;
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
return txFunction as Transaction;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Transaction implementation for ODBLite
|
|
189
|
+
* Note: SQLite transactions are simulated at the client level since ODBLite
|
|
190
|
+
* operates on individual queries. This provides a familiar API but doesn't
|
|
191
|
+
* provide true ACID guarantees across multiple HTTP requests.
|
|
192
|
+
*/
|
|
193
|
+
export class ODBLiteTransaction {
|
|
194
|
+
private httpClient: HTTPClient;
|
|
195
|
+
private isCommitted = false;
|
|
196
|
+
private isRolledBack = false;
|
|
197
|
+
private queries: Array<{ sql: string; params: any[] }> = [];
|
|
198
|
+
|
|
199
|
+
constructor(httpClient: HTTPClient) {
|
|
200
|
+
this.httpClient = httpClient;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Execute a query within the transaction
|
|
205
|
+
* For SQLite, we'll queue queries and execute them in batch on commit
|
|
206
|
+
*/
|
|
207
|
+
async sql<T = any>(sql: TemplateStringsArray, ...values: any[]): Promise<QueryResult<T>> {
|
|
208
|
+
this.checkTransactionState();
|
|
209
|
+
|
|
210
|
+
const parsed = SQLParser.parse(sql, values);
|
|
211
|
+
|
|
212
|
+
// For read queries, execute immediately
|
|
213
|
+
if (this.isReadQuery(parsed.sql)) {
|
|
214
|
+
return await this.httpClient.query<T>(parsed.sql, parsed.params);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// For write queries, queue them for batch execution
|
|
218
|
+
this.queries.push(parsed);
|
|
219
|
+
|
|
220
|
+
// Return a placeholder result for queued queries
|
|
221
|
+
return {
|
|
222
|
+
rows: [],
|
|
223
|
+
rowsAffected: 0,
|
|
224
|
+
executionTime: 0
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Commit the transaction by executing all queued queries
|
|
230
|
+
*/
|
|
231
|
+
async commit(): Promise<void> {
|
|
232
|
+
this.checkTransactionState();
|
|
233
|
+
|
|
234
|
+
try {
|
|
235
|
+
// Execute BEGIN
|
|
236
|
+
await this.httpClient.query('BEGIN');
|
|
237
|
+
|
|
238
|
+
// Execute all queued queries
|
|
239
|
+
for (const query of this.queries) {
|
|
240
|
+
await this.httpClient.query(query.sql, query.params);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Commit the transaction
|
|
244
|
+
await this.httpClient.query('COMMIT');
|
|
245
|
+
|
|
246
|
+
this.isCommitted = true;
|
|
247
|
+
} catch (error) {
|
|
248
|
+
// Rollback on any error
|
|
249
|
+
try {
|
|
250
|
+
await this.httpClient.query('ROLLBACK');
|
|
251
|
+
} catch (rollbackError) {
|
|
252
|
+
// Ignore rollback errors
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
this.isRolledBack = true;
|
|
256
|
+
throw new QueryError(
|
|
257
|
+
`Transaction failed: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
258
|
+
undefined,
|
|
259
|
+
undefined,
|
|
260
|
+
error instanceof Error ? error : undefined
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Rollback the transaction
|
|
267
|
+
*/
|
|
268
|
+
async rollback(): Promise<void> {
|
|
269
|
+
this.checkTransactionState();
|
|
270
|
+
|
|
271
|
+
try {
|
|
272
|
+
// If we have any queries, we need to actually rollback
|
|
273
|
+
if (this.queries.length > 0) {
|
|
274
|
+
await this.httpClient.query('ROLLBACK');
|
|
275
|
+
}
|
|
276
|
+
} finally {
|
|
277
|
+
this.isRolledBack = true;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Check if transaction is still active
|
|
283
|
+
*/
|
|
284
|
+
private checkTransactionState(): void {
|
|
285
|
+
if (this.isCommitted) {
|
|
286
|
+
throw new QueryError('Transaction has already been committed');
|
|
287
|
+
}
|
|
288
|
+
if (this.isRolledBack) {
|
|
289
|
+
throw new QueryError('Transaction has been rolled back');
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Determine if a query is a read operation
|
|
295
|
+
*/
|
|
296
|
+
private isReadQuery(sql: string): boolean {
|
|
297
|
+
const trimmed = sql.trim().toUpperCase();
|
|
298
|
+
return trimmed.startsWith('SELECT') ||
|
|
299
|
+
trimmed.startsWith('WITH') ||
|
|
300
|
+
trimmed.startsWith('EXPLAIN') ||
|
|
301
|
+
trimmed.startsWith('PRAGMA');
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Create a simple transaction function that executes immediately
|
|
307
|
+
* This is more suitable for HTTP-based databases where true transactions
|
|
308
|
+
* across multiple requests are not practical
|
|
309
|
+
*/
|
|
310
|
+
export function createSimpleTransaction(httpClient: HTTPClient): Transaction {
|
|
311
|
+
let isActive = true;
|
|
312
|
+
|
|
313
|
+
// Create the callable transaction function with context awareness
|
|
314
|
+
const txFunction = <T = any>(sql: TemplateStringsArray | any, ...values: any[]): Promise<QueryResult<T>> | SQLFragment => {
|
|
315
|
+
if (!isActive) {
|
|
316
|
+
throw new QueryError('Transaction is no longer active');
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// Handle template string queries (returns Promise)
|
|
320
|
+
if (Array.isArray(sql) && (('raw' in sql) || (typeof sql[0] === 'string' && values.length >= 0))) {
|
|
321
|
+
const parsed = SQLParser.parse(sql, values);
|
|
322
|
+
return httpClient.query<T>(parsed.sql, parsed.params);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// Handle direct object/array inputs (returns SQLFragment for composing)
|
|
326
|
+
const parsed = SQLParser.parse(sql, values);
|
|
327
|
+
return {
|
|
328
|
+
text: parsed.sql,
|
|
329
|
+
values: parsed.params
|
|
330
|
+
};
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
// Attach utility methods to the transaction function
|
|
334
|
+
txFunction.raw = (text: string): string => SQLParser.raw(text);
|
|
335
|
+
txFunction.identifier = (name: string): string => SQLParser.identifier(name);
|
|
336
|
+
|
|
337
|
+
// Add execute method for compatibility
|
|
338
|
+
txFunction.execute = async <T = any>(sql: string | { sql: string; args?: any[] }, args?: any[]): Promise<QueryResult<T>> => {
|
|
339
|
+
if (!isActive) {
|
|
340
|
+
throw new QueryError('Transaction is no longer active');
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
if (typeof sql === 'string') {
|
|
344
|
+
return await httpClient.query<T>(sql, args || []);
|
|
345
|
+
} else {
|
|
346
|
+
return await httpClient.query<T>(sql.sql, sql.args || []);
|
|
347
|
+
}
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
// Add query method for compatibility
|
|
351
|
+
txFunction.query = async <T = any>(sql: string, params: any[] = []): Promise<QueryResult<T>> => {
|
|
352
|
+
if (!isActive) {
|
|
353
|
+
throw new QueryError('Transaction is no longer active');
|
|
354
|
+
}
|
|
355
|
+
return await httpClient.query<T>(sql, params);
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
txFunction.commit = async (): Promise<void> => {
|
|
359
|
+
isActive = false;
|
|
360
|
+
// No-op for simple transactions
|
|
361
|
+
};
|
|
362
|
+
|
|
363
|
+
txFunction.rollback = async (): Promise<void> => {
|
|
364
|
+
isActive = false;
|
|
365
|
+
// No-op for simple transactions - individual queries are atomic
|
|
366
|
+
};
|
|
367
|
+
|
|
368
|
+
txFunction.savepoint = async <T = any>(callback: (sql: Transaction) => Promise<T>): Promise<T> => {
|
|
369
|
+
if (!isActive) {
|
|
370
|
+
throw new QueryError('Transaction is no longer active');
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// Create a nested transaction for the savepoint
|
|
374
|
+
const savepointTx = createSimpleTransaction(httpClient);
|
|
375
|
+
|
|
376
|
+
try {
|
|
377
|
+
// Execute the callback with the savepoint transaction
|
|
378
|
+
const result = await callback(savepointTx);
|
|
379
|
+
|
|
380
|
+
// Commit the savepoint (no-op for simple transactions)
|
|
381
|
+
await savepointTx.commit();
|
|
382
|
+
|
|
383
|
+
return result;
|
|
384
|
+
} catch (error) {
|
|
385
|
+
// Rollback the savepoint on error
|
|
386
|
+
await savepointTx.rollback();
|
|
387
|
+
throw error;
|
|
388
|
+
}
|
|
389
|
+
};
|
|
390
|
+
|
|
391
|
+
return txFunction as Transaction;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* Simple transaction implementation that executes immediately
|
|
396
|
+
* This is more suitable for HTTP-based databases where true transactions
|
|
397
|
+
* across multiple requests are not practical
|
|
398
|
+
*/
|
|
399
|
+
export class SimpleTransaction {
|
|
400
|
+
private httpClient: HTTPClient;
|
|
401
|
+
private isActive = true;
|
|
402
|
+
|
|
403
|
+
constructor(httpClient: HTTPClient) {
|
|
404
|
+
this.httpClient = httpClient;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
async sql<T = any>(sql: TemplateStringsArray, ...values: any[]): Promise<QueryResult<T>> {
|
|
408
|
+
if (!this.isActive) {
|
|
409
|
+
throw new QueryError('Transaction is no longer active');
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
const parsed = SQLParser.parse(sql, values);
|
|
413
|
+
return await this.httpClient.query<T>(parsed.sql, parsed.params);
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
async commit(): Promise<void> {
|
|
417
|
+
this.isActive = false;
|
|
418
|
+
// No-op for simple transactions
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
async rollback(): Promise<void> {
|
|
422
|
+
this.isActive = false;
|
|
423
|
+
// No-op for simple transactions - individual queries are atomic
|
|
424
|
+
}
|
|
425
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// Main entry point for ODB Client
|
|
2
|
+
import { ODBLiteClient } from './core/client.ts';
|
|
3
|
+
|
|
4
|
+
// Core query client exports (postgres.js-like interface)
|
|
5
|
+
export { ODBLiteClient, odblite } from './core/client.ts';
|
|
6
|
+
export { ODBLiteTransaction, SimpleTransaction } from './core/transaction.ts';
|
|
7
|
+
export { HTTPClient } from './core/http-client.ts';
|
|
8
|
+
export { SQLParser, sql, fragment } from './core/sql-parser.ts';
|
|
9
|
+
|
|
10
|
+
// Service management exports (high-level tenant database management)
|
|
11
|
+
export { ServiceClient } from './service/service-client.ts';
|
|
12
|
+
|
|
13
|
+
// Export all types
|
|
14
|
+
export type {
|
|
15
|
+
ODBLiteConfig,
|
|
16
|
+
ODBLiteConnection,
|
|
17
|
+
QueryResult,
|
|
18
|
+
Transaction,
|
|
19
|
+
SQLFragment,
|
|
20
|
+
PreparedQuery,
|
|
21
|
+
QueryParameter,
|
|
22
|
+
PrimitiveType,
|
|
23
|
+
Row
|
|
24
|
+
} from './types.ts';
|
|
25
|
+
|
|
26
|
+
// Export service client types
|
|
27
|
+
export type {
|
|
28
|
+
ServiceClientConfig,
|
|
29
|
+
ODBLiteDatabase,
|
|
30
|
+
ODBLiteNode
|
|
31
|
+
} from './service/service-client.ts';
|
|
32
|
+
|
|
33
|
+
// Export error classes
|
|
34
|
+
export {
|
|
35
|
+
ODBLiteError,
|
|
36
|
+
ConnectionError,
|
|
37
|
+
QueryError
|
|
38
|
+
} from './types.ts';
|
|
39
|
+
|
|
40
|
+
// Export static utility functions for easy access
|
|
41
|
+
export const {
|
|
42
|
+
raw,
|
|
43
|
+
identifier,
|
|
44
|
+
where,
|
|
45
|
+
insertValues,
|
|
46
|
+
updateSet,
|
|
47
|
+
join
|
|
48
|
+
} = ODBLiteClient;
|
|
49
|
+
|
|
50
|
+
// Default export for convenient usage
|
|
51
|
+
export { odblite as default } from './core/client.ts';
|