Skip to content

Simplify DBAdapter interface and query result types#995

Draft
simolus3 wants to merge 4 commits into
internals-packagefrom
simplify-resultset-interfaces
Draft

Simplify DBAdapter interface and query result types#995
simolus3 wants to merge 4 commits into
internals-packagefrom
simplify-resultset-interfaces

Conversation

@simolus3

Copy link
Copy Markdown
Contributor

DBAdapter is the interface we implement to give a PowerSync SDK access to SQLite. It's a public interface, which means that users can implement it too if they want a custom SDK. However, it's also very annoying to implement, since one needs to write all get(), getOptional(), getAll(), execute(), ... methods by hand. We introduced mixins to help with those classes, but that's still kind of awkward to use since it splits the type hierarchy (one class + another one applying the mixin).

Really, what we want is for users to implement a minimal amount of methods and then get all the others by default. Now that we can afford a breaking change, we can use the right tool for the job: This changes DBAdapter and LockContext to be abstract classes, meaning that users only really need to implement a single method (executeRaw) and get the rest for free.

Specifically, this PR makes three changes:

Result set restructuring

Our current QueryResult interface is heavily inspired from RNQS, which I don't think is the most convenient representation: Rows are represented as JS objects, and accessed on results through a field called _array. There's also a length getter and an item() method to get the nth row (a convenient API for those not knowing arrays exist /s).

Instead, this adds a RawResultSet interface, consisting of a columnNames: string[] field and a rawRows: SqliteValue[][] array (no more any!). This is returned by executeRaw now, giving users access to column names. It also allows a default implementation of execute that groups by column names into JS objects (done lazily in the ResultSet class extending RawResultSet). This replaces a few implementations we had of that in the existing adapter implementations.

For backwards-compatibility, I've kept _array and length. But they're deprecated now.

Table update notifications

On a type level, we had three different representations of update notifications and helpers to convert between them. This normalizes them into a single format, changedTables: string[]. Information about the type of updates (insert, update, delete) was only provided by the OP-SQLite implementation and isn't used anywhere in the SDK.

Migration to abstract classes

The previous mixins used to implement DBAdapter were introduced to share implementation details without a breaking change. Using abstract classes instead gives us a much simpler implementation and avoids having to split everything into two classes to apply the mixin.

One minor caveat is that TriggerDiffHandlerContext (an interface) can no longer implement LockContext, it now exports the context as a field instead.

@changeset-bot

changeset-bot Bot commented Jun 16, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 4fdc836

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 9 packages
Name Type
@powersync/react-native Major
@powersync/web Major
@powersync/op-sqlite Minor
@powersync/node Minor
tauri-plugin-powersync Patch
@powersync/tauri-plugin Patch
@powersync/nuxt Major
@powersync/capacitor Major
@powersync/diagnostics-app Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

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.

1 participant