Skip to content

Add LibSQL and Turso adapter - #13

Merged
Truta446 merged 3 commits into
Truta446:mainfrom
milekv:agent/libsql-adapter
Aug 13, 2026
Merged

Truta446 merged 3 commits into
Truta446:mainfrom
milekv:agent/libsql-adapter

Conversation

@milekv

@milekv milekv commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Closes #1

What changed

  • Add instrumentLibsql(client) through the nplusone/libsql export.
  • Record string and object execute() calls with positional or named arguments.
  • Record every batch() statement separately while preserving one driver call.
  • Support restoration and repeated instrumentation without double counting.
  • Document the LibSQL and Turso setup.

Validation

  • npm test - 135 tests passing
  • npm run typecheck
  • npm run lint
  • npm run build
  • npm pack --dry-run
  • Exercised against a real @libsql/client in-memory database

@milekv
milekv marked this pull request as ready for review August 13, 2026 07:16
Truta446 and others added 2 commits August 13, 2026 11:49
Wrapping each statement of a batch in its own observe() nests the
timers, so every outer one contains all the inner ones. Measured against
a real @libsql/client: a batch of six reported 2.39ms for a round trip
that took 0.51ms, and the distortion grows with batch size — fifty
statements would report about twenty-five times the truth. A batch loop
is exactly where an N+1 hides, so that number has to be trustworthy.

Drivers report no per-statement timing for a batch, so observeBatch()
runs the round trip once and divides it evenly. Each statement's
duration is an estimate; the sum, which is what a finding reports, is
the measurement.

Co-Authored-By: Claude Opus 5 <[email protected]>
@Truta446
Truta446 merged commit fb8f211 into Truta446:main Aug 13, 2026
2 checks passed
@Truta446

Copy link
Copy Markdown
Owner

Merged — thank you. Clean adapter, and the decision to record each batch() statement separately is the right one: a batch loop is exactly where an N+1 hides, and collapsing it into one record would have made this adapter blind to the case it most needs to catch.

I verified it against a real @libsql/client in-memory database rather than only the fake, since that was the part of #1 I could not take on trust:

1 N+1 detected via execute()                   yes, 6× at line 30
2 named args recorded                          [{"id":3}]
3 batch recorded per statement                 6
  N+1 found inside the batch                   yes, 6×
  batch return value preserved                 6 result sets
  params in order                              [[1],[2],[3],[4],[5],[6]]
4 driver error still propagates                LibsqlError
5 restore stops recording                      yes

All correct. One thing that measurement turned up, which I fixed on merge rather than sending back:

per-statement durations (ms)   [0.271, 0.332, 0.382, 0.419, 0.471, 0.511]

Monotonically increasing. The reduce nests each observe() inside the next, so every outer timer contains all the inner ones — the batch took 0.51ms and the six statements reported 2.39ms between them. It scales with batch size: fifty statements would report roughly twenty-five times the truth.

The nesting is genuinely clever and it preserves ordering and the return value correctly, which is why the tests pass. It is only the timing that suffers, and only for batch().

I added observeBatch() in shared.ts: it runs the round trip once and divides the elapsed time evenly across the statements. Drivers give no per-statement timing for a batch, so each statement's duration is an estimate and the sum — which is what a finding actually reports — is the measurement. There is a regression test with a deliberately slow fake asserting the total cannot exceed the real elapsed time.

Also merged main in, since #14 landed in between and changed the Finding shape.

Shipping in 0.6.0 with a changelog credit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add an adapter for @libsql/client (Turso)

2 participants