|
1 | 1 | import { |
2 | 2 | SQLITE_DETERMINISTIC, |
3 | 3 | SQLITE_DIRECTONLY, |
4 | | - SQLITE_OK, |
| 4 | + SQLITE_DONE, |
5 | 5 | SQLITE_OPEN_CREATE, |
6 | 6 | SQLITE_OPEN_READONLY, |
7 | 7 | SQLITE_OPEN_READWRITE, |
@@ -262,43 +262,88 @@ export async function run( |
262 | 262 | return results |
263 | 263 | } |
264 | 264 |
|
| 265 | +function createRowMapper(sqlite: SQLiteDBCore['sqlite'], stmt: number) { |
| 266 | + const cols = sqlite.column_names(stmt) |
| 267 | + return (row: any[]) => Object.fromEntries(cols.map((key, i) => [key, row[i]])) |
| 268 | +} |
| 269 | + |
| 270 | +export async function query( |
| 271 | + core: SQLiteDBCore, |
| 272 | + sql: string, |
| 273 | + parameters?: SQLiteCompatibleType[], |
| 274 | +): Promise<Record<string, SQLiteCompatibleType>[]> { |
| 275 | + const iterator = core.sqlite.statements(core.pointer, sql)[Symbol.asyncIterator]() |
| 276 | + const { value: stmt } = await iterator.next() |
| 277 | + |
| 278 | + try { |
| 279 | + if (parameters?.length) { |
| 280 | + core.sqlite.bind_collection(stmt, parameters) |
| 281 | + } |
| 282 | + |
| 283 | + const size = core.sqlite.column_count(stmt) |
| 284 | + if (size === 0) { |
| 285 | + await core.sqlite.step(stmt) |
| 286 | + return [] |
| 287 | + } |
| 288 | + |
| 289 | + const mapRow = createRowMapper(core.sqlite, stmt) |
| 290 | + const result = [] |
| 291 | + let idx = 0 |
| 292 | + while ((await core.sqlite.step(stmt)) === SQLITE_ROW) { |
| 293 | + result[idx++] = mapRow(core.sqlite.row(stmt)) |
| 294 | + } |
| 295 | + return result |
| 296 | + } finally { |
| 297 | + await iterator.return?.() |
| 298 | + } |
| 299 | +} |
| 300 | + |
265 | 301 | export async function* iterator( |
266 | 302 | core: SQLiteDBCore, |
267 | 303 | sql: string, |
268 | 304 | parameters?: SQLiteCompatibleType[], |
269 | 305 | chunkSize = 1, |
270 | | -): AsyncIterableIterator<Record<string, SQLiteCompatibleType>[]> { |
| 306 | +): AsyncIterableIterator<Record<string, SQLiteCompatibleType>> { |
271 | 307 | const { sqlite, pointer } = core |
272 | | - // eslint-disable-next-line unicorn/no-new-array |
273 | | - let cache = new Array(chunkSize) |
| 308 | + const cache = new Array(chunkSize) |
274 | 309 | for await (const stmt of sqlite.statements(pointer, sql)) { |
275 | 310 | if (parameters?.length) { |
276 | 311 | sqlite.bind_collection(stmt, parameters) |
277 | 312 | } |
278 | 313 | let idx = 0 |
279 | | - const cols = sqlite.column_names(stmt) |
| 314 | + const mapRow = createRowMapper(core.sqlite, stmt) |
| 315 | + |
280 | 316 | while (1) { |
281 | | - const result = await sqlite.step(stmt) |
282 | | - if (result === SQLITE_ROW) { |
283 | | - const row = sqlite.row(stmt) |
284 | | - cache[idx] = Object.fromEntries(cols.map((key, i) => [key, row[i]])) |
285 | | - if (++idx === chunkSize) { |
286 | | - yield cache.slice(0, idx) |
287 | | - idx = 0 |
288 | | - } |
289 | | - } else if (result === SQLITE_OK) { |
290 | | - if (++idx === chunkSize) { |
291 | | - yield [] |
| 317 | + try { |
| 318 | + const result = await sqlite.step(stmt) |
| 319 | + |
| 320 | + if (result === SQLITE_ROW) { |
| 321 | + cache[idx] = mapRow(core.sqlite.row(stmt)) |
| 322 | + |
| 323 | + if (++idx === chunkSize) { |
| 324 | + for (let i = 0; i < idx; i++) { |
| 325 | + yield cache[i] |
| 326 | + } |
| 327 | + idx = 0 |
| 328 | + } |
| 329 | + } else if (result === SQLITE_DONE) { |
| 330 | + if (idx > 0) { |
| 331 | + for (let i = 0; i < idx; i++) { |
| 332 | + yield cache[i] |
| 333 | + } |
| 334 | + idx = 0 |
| 335 | + } |
| 336 | + break |
292 | 337 | } |
293 | | - } else { |
| 338 | + } finally { |
294 | 339 | if (idx > 0) { |
295 | | - yield cache.slice(0, idx) |
| 340 | + for (let i = 0; i < idx; i++) { |
| 341 | + yield cache[i] |
| 342 | + } |
296 | 343 | } |
297 | | - break |
298 | 344 | } |
299 | 345 | } |
300 | 346 | } |
301 | | - cache = undefined! |
302 | 347 | } |
303 | 348 |
|
304 | 349 | export function parseOpenV2Flag(readonly?: boolean): number { |
|
0 commit comments