• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

rogerpadilla / nukak / #502

28 Dec 2025 03:44PM UTC coverage: 97.284% (-0.3%) from 97.544%
#502

push

rogerpadilla
feat: Enhance and standardize `upsert` implementation across all SQL dialects with dedicated update assignment and conflict path handling.

493 of 528 branches covered (93.37%)

Branch coverage included in aggregate %.

27 of 27 new or added lines in 5 files covered. (100.0%)

1 existing line in 1 file now uncovered.

1692 of 1718 relevant lines covered (98.49%)

166.22 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.33
/packages/sqlite/src/sqliteQuerier.ts
1
import type { Database } from 'better-sqlite3';
2
import { AbstractSqlQuerier } from 'nukak/querier';
3✔
3
import type { ExtraOptions, QueryConflictPaths, QueryUpdateResult, Type } from 'nukak/type';
4
import { clone } from 'nukak/util';
3✔
5
import { SqliteDialect } from './sqliteDialect.js';
3✔
6

7
export class SqliteQuerier extends AbstractSqlQuerier {
3✔
8
  constructor(
9
    readonly db: Database,
10
    readonly extra?: ExtraOptions,
11
  ) {
12
    super(new SqliteDialect());
3✔
13
  }
14

15
  override async all<T>(query: string) {
16
    this.extra?.logger?.(query);
551✔
17
    return this.db.prepare<T, T>(query).all();
551✔
18
  }
19

20
  override async run(query: string) {
21
    this.extra?.logger?.(query);
1,070✔
22
    const { changes, lastInsertRowid } = await this.db.prepare(query).run();
1,070✔
23
    const firstId = lastInsertRowid ? Number(lastInsertRowid) - (changes - 1) : undefined;
1,070✔
24
    const ids = firstId
1,070✔
25
      ? Array(changes)
26
          .fill(firstId)
27
          .map((i, index) => i + index)
280✔
28
      : [];
29
    return { changes, ids, firstId } satisfies QueryUpdateResult;
1,070✔
30
  }
31

32
  override async upsertOne<E>(entity: Type<E>, conflictPaths: QueryConflictPaths<E>, payload: E) {
33
    payload = clone(payload);
2✔
34
    const upsert = this.dialect.upsert(entity, conflictPaths, payload);
2✔
35
    const [insertOrIgnore, update] = upsert.split(';');
2✔
36
    const resInsert = await this.run(insertOrIgnore);
2✔
37
    if (resInsert.changes) {
2!
38
      return resInsert;
2✔
39
    }
UNCOV
40
    return this.run(update);
×
41
  }
42

43
  override async release() {
44
    if (this.hasOpenTransaction) {
12✔
45
      throw TypeError('pending transaction');
2✔
46
    }
47
    // no-op
48
  }
49
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc