Skip to content

Commit 2c696e4

Browse files
committed
Add get and getOptional.
1 parent 2077f8d commit 2c696e4

File tree

2 files changed

+131
-42
lines changed

2 files changed

+131
-42
lines changed

src/api.ts

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,36 @@ export interface QueryInterface {
9191
options?: QueryOptions & ReserveConnectionOptions
9292
): Promise<T[]>;
9393

94+
/**
95+
* Get a single row.
96+
*
97+
* Throws an exception if the query returns no results.
98+
*
99+
* @param query
100+
* @param args
101+
* @param options
102+
*/
103+
get<T extends SqliteRowObject>(
104+
query: string,
105+
args?: SqliteArguments,
106+
options?: QueryOptions & ReserveConnectionOptions
107+
): Promise<T>;
108+
109+
/**
110+
* Get a single row.
111+
*
112+
* Returns null if the query returns no results.
113+
*
114+
* @param query
115+
* @param args
116+
* @param options
117+
*/
118+
getOptional<T extends SqliteRowObject>(
119+
query: string,
120+
args?: SqliteArguments,
121+
options?: QueryOptions & ReserveConnectionOptions
122+
): Promise<T | null>;
123+
94124
pipeline(options?: ReserveConnectionOptions): QueryPipeline;
95125
}
96126

@@ -201,11 +231,6 @@ export interface ResultSet<T extends SqliteRowObject = SqliteRowObject> {
201231
}
202232

203233
export interface SqliteQuery<T extends SqliteRowObject> {
204-
/**
205-
* Returns a query that can be used in a transaction.
206-
*/
207-
in(transaction: SqliteTransaction): SqliteQuery<T>;
208-
209234
executeStreamed(options?: StreamedExecuteOptions): AsyncGenerator<ResultSet>;
210235

211236
execute(options?: ExecuteOptions): Promise<ResultSet<T>>;
@@ -216,6 +241,20 @@ export interface SqliteQuery<T extends SqliteRowObject> {
216241
* Same as execute, but returns an array of row objects directly.
217242
*/
218243
select(options?: QueryOptions): Promise<T[]>;
244+
245+
/**
246+
* Get a single row.
247+
*
248+
* Throws an exception if the results contain no rows.
249+
*/
250+
get(options?: QueryOptions): Promise<T>;
251+
252+
/**
253+
* Get a single row.
254+
*
255+
* Returns null if the results contain no rows.
256+
*/
257+
getOptional(options?: QueryOptions): Promise<T | null>;
219258
}
220259

221260
export interface PreparedQuery<T extends SqliteRowObject> {
@@ -264,7 +303,9 @@ export interface QueryPipeline {
264303
execute(query: string | PreparedQuery<any>, args?: SqliteArguments): void;
265304

266305
/**
267-
* Flush all existing queries.
306+
* Flush all existing queries, wait for the last query to complete.
307+
*
308+
* TODO: define error handling.
268309
*/
269310
flush(): Promise<void>;
270311

src/impl.ts

Lines changed: 84 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,32 @@ export class ConnectionPoolImpl
112112
}
113113
}
114114

115+
async get<T extends SqliteRowObject>(
116+
query: string,
117+
args?: SqliteArguments | undefined,
118+
options?: (QueryOptions & ReserveConnectionOptions) | undefined
119+
): Promise<T> {
120+
const r = await this.reserveConnection({ readonly: true, ...options });
121+
try {
122+
return r.connection.get(query, args, options);
123+
} finally {
124+
await r.release();
125+
}
126+
}
127+
128+
async getOptional<T extends SqliteRowObject>(
129+
query: string,
130+
args?: SqliteArguments | undefined,
131+
options?: (QueryOptions & ReserveConnectionOptions) | undefined
132+
): Promise<T | null> {
133+
const r = await this.reserveConnection({ readonly: true, ...options });
134+
try {
135+
return r.connection.getOptional(query, args, options);
136+
} finally {
137+
await r.release();
138+
}
139+
}
140+
115141
async withReservedConnection<T>(
116142
callback: (connection: SqliteConnection) => Promise<T>,
117143
options?: ReserveConnectionOptions | undefined
@@ -164,7 +190,7 @@ export class ReservedConnectionImpl implements ReservedSqliteConnection {
164190
args?: SqliteArguments,
165191
options?: ReserveConnectionOptions | undefined
166192
): SqliteQuery<T> {
167-
return new QueryImpl<T>(this, sql, args);
193+
return new QueryImpl<T>(this.connection, sql, args);
168194
}
169195

170196
prepare<T extends SqliteRowObject>(
@@ -229,6 +255,22 @@ export class ReservedConnectionImpl implements ReservedSqliteConnection {
229255
): Promise<T[]> {
230256
return this.connection.select(query, args, options);
231257
}
258+
259+
get<T extends SqliteRowObject>(
260+
query: string,
261+
args?: SqliteArguments,
262+
options?: QueryOptions & ReserveConnectionOptions
263+
): Promise<T> {
264+
return this.connection.get(query, args, options);
265+
}
266+
267+
getOptional<T extends SqliteRowObject>(
268+
query: string,
269+
args?: SqliteArguments,
270+
options?: QueryOptions & ReserveConnectionOptions
271+
): Promise<T | null> {
272+
return this.connection.getOptional(query, args, options);
273+
}
232274
}
233275

234276
export class ConnectionImpl implements SqliteConnection {
@@ -394,6 +436,27 @@ export class ConnectionImpl implements SqliteConnection {
394436
const rs = await this.execute<T>(query, args, options);
395437
return rs.rows;
396438
}
439+
440+
async get<T extends SqliteRowObject>(
441+
query: string,
442+
args?: SqliteArguments,
443+
options?: (QueryOptions & ReserveConnectionOptions) | undefined
444+
): Promise<T> {
445+
const row = await this.getOptional<T>(query, args, options);
446+
if (row == null) {
447+
throw new Error('Query returned 0 rows');
448+
}
449+
return row;
450+
}
451+
452+
async getOptional<T extends SqliteRowObject>(
453+
query: string,
454+
args?: SqliteArguments,
455+
options?: (QueryOptions & ReserveConnectionOptions) | undefined
456+
): Promise<T | null> {
457+
const rs = await this.execute<T>(query, args, options);
458+
return rs.rows[0] ?? null;
459+
}
397460
}
398461

399462
export class TransactionImpl implements SqliteTransaction {
@@ -453,32 +516,21 @@ export class TransactionImpl implements SqliteTransaction {
453516
): Promise<T[]> {
454517
return this.con.select(query, args, options);
455518
}
456-
}
457-
458-
class RawResultSetImpl<T extends SqliteRowObject> implements ResultSet<T> {
459-
columns: (keyof T)[];
460-
cells: SqliteValue[][];
461-
private _rowObjects: T[] | undefined;
462-
463-
rowId?: number;
464-
changes?: number;
465519

466-
constructor(columns: string[], rows?: SqliteValue[][]) {
467-
this.columns = columns as any[] as (keyof T)[];
468-
this.cells = rows ?? [];
520+
get<T extends SqliteRowObject>(
521+
query: string,
522+
args?: SqliteArguments,
523+
options?: (QueryOptions & ReserveConnectionOptions) | undefined
524+
): Promise<T> {
525+
return this.con.get(query, args, options);
469526
}
470527

471-
get rows() {
472-
if (this._rowObjects == null) {
473-
this._rowObjects = this.cells.map((row) => {
474-
return Object.fromEntries(
475-
this.columns.map((column, i) => {
476-
return [column, row[i]];
477-
})
478-
) as T;
479-
});
480-
}
481-
return this._rowObjects;
528+
getOptional<T extends SqliteRowObject>(
529+
query: string,
530+
args?: SqliteArguments,
531+
options?: (QueryOptions & ReserveConnectionOptions) | undefined
532+
): Promise<T | null> {
533+
return this.con.getOptional(query, args, options);
482534
}
483535
}
484536

@@ -514,10 +566,6 @@ class QueryImpl<T extends SqliteRowObject> implements SqliteQuery<T> {
514566
public args: SqliteArguments
515567
) {}
516568

517-
in(transaction: SqliteTransaction): SqliteQuery<T> {
518-
return new QueryImpl<T>(transaction, this.sql, this.args);
519-
}
520-
521569
executeStreamed(
522570
options?: StreamedExecuteOptions | undefined
523571
): AsyncGenerator<ResultSet<any>, any, unknown> {
@@ -531,6 +579,14 @@ class QueryImpl<T extends SqliteRowObject> implements SqliteQuery<T> {
531579
select(options?: QueryOptions | undefined): Promise<T[]> {
532580
return this.context.select(this.sql, this.args, options);
533581
}
582+
583+
get(options?: QueryOptions | undefined): Promise<T> {
584+
return this.context.get(this.sql, this.args, options);
585+
}
586+
587+
getOptional(options?: QueryOptions | undefined): Promise<T | null> {
588+
return this.context.getOptional(this.sql, this.args, options);
589+
}
534590
}
535591

536592
class ConnectionPoolPreparedQueryImpl<T extends SqliteRowObject>
@@ -560,10 +616,6 @@ class ConnectionPoolPreparedQueryImpl<T extends SqliteRowObject>
560616
}
561617
}
562618

563-
in(context: QueryInterface): SqliteQuery<T> {
564-
throw new Error('Method not implemented.');
565-
}
566-
567619
async *executeStreamed(
568620
args?: SqliteArguments,
569621
options?: StreamedExecuteOptions | undefined
@@ -647,10 +699,6 @@ class ConnectionPreparedQueryImpl<T extends SqliteRowObject>
647699
};
648700
}
649701

650-
in(context: QueryInterface): SqliteQuery<T> {
651-
throw new Error('Method not implemented.');
652-
}
653-
654702
async *executeStreamed(
655703
args?: SqliteArguments,
656704
options?: StreamedExecuteOptions | undefined

0 commit comments

Comments
 (0)