Skip to content

PowerSyncDatabase Get API rework - #107

Draft
LucDeCaf wants to merge 4 commits into
v1from
get-api-rework
Draft

LucDeCaf wants to merge 4 commits into
v1from
get-api-rework

Conversation

@LucDeCaf

@LucDeCaf LucDeCaf commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

Reworks the Get/GetAll/GetOptional APIs to be more flexible and performant, at the cost of needing more manual implementation at times.

API Changes

Getter methods now accept a generic parameter T and a SqlMapper<T> mapper delegate, which is now used to construct the method's result types. This allows us to remove Dapper completely and its reflection-heavy approach, which future-proofs the PowerSync SDK for iOS/iPadOS, lets us define our own completely separate API, and should (pending benchmarks) make the query API faster.
Overloads also exist for the new IFromRow<T> interface, which lets users skip passing the mapper to the query function every time.

This also renames and exposes the previously unused QueryResult class/interface to allow for dynamic/mapper-less row access.

This PR also adds a PowerSync.Common.SourceGenerators package, which currently defines the GenerateSqlMapper attribute class. This provides a default, Dapper-style IFromRow<T> implementation for simple classes, which should help users that liked the flexibility and ease-of-use provided by Dapper.

Examples

Using Dapper (old):

using PowerSync.Common;
// using ...

public class Todo
{
  public string Id { get; set; }
  public string ListId { get; set; }
  public DateTime CreatedAt { get; set; }
  public bool Completed { get; set; }
  // ...
}

// Results are obtained using reflection at runtime and rely on Dapper's internal object mapper
T[] result = db.GetAll<Todo>("SELECT * FROM todos WHERE list_id = ?', ["my_list"]);

Using mapper:

using PowerSync.Common;
// using ...

public class Todo
{
  public string Id { get; set; }
  public string ListId { get; set; }
  public DateTime CreatedAt { get; set; }
  public bool Completed { get; set; }
  // ...
}

List<Todo> result = await db.GetAll<T>(
  "SELECT * FROM todos WHERE list_id = ?",
  ["my_list"],
  // Define a mapper function from IQueryRow to T
  (IQueryRow row) => {
    Todo t = new();
    t.Id = row.GetString("id");
    t.ListId = row.GetString("list_id");
    t.CreatedAt = row.GetDateTime("created_at");
    t.Completed = row.GetBool("completed");
    // ...
    return t;
  }
);

Using IFromRow<T>:

using PowerSync.Common;
// using ...

public class Todo : IFromRow<Todo>
{
  public string Id { get; set; }
  public string ListId { get; set; }
  public DateTime CreatedAt { get; set; }
  public bool Completed { get; set; }
  // ...

  // Static method so that an appropriate constructor can be chosen
  public static Todo FromRow(IQueryRow row)
  {
    Todo t = new();
    t.Id = row.GetString("id");
    t.ListId = row.GetString("list_id");
    t.CreatedAt = row.GetDateTime("created_at");
    t.Completed = row.GetBool("completed");
    // ...
    return t;
  }
}

List<Todo> result = await db.GetAll<Todo>("SELECT * FROM todos WHERE list_id = ?", ["my_list"]);

Using source generators:

using PowerSync.Common;
// using ...

// Include the PowerSync source generators
using PowerSync.Common.SourceGenerators;

[GenerateSqlMapper]
public partial class Todo // class must be partial
{
  public string Id { get; set; }
  public string ListId { get; set; }
  public DateTime CreatedAt { get; set; }
  public bool Completed { get; set; }
  // ...
}

// IFromRow<Todo> implementation is automatically generated
List<Todo> result = await db.GetAll<Todo>("SELECT * FROM todos WHERE list_id = ?", ["my_list"]);

AI usage

I manually defined and rewrote the new API in IDBAdapter.cs. Claude Opus 5.5 implemented the required code changes and source generator package, plus added some tests. I will review and verify all changes before marking this as ready for review.

@LucDeCaf LucDeCaf added the Product Visibility Contains user-facing updates that may need to be documented and/or announced label Nov 3, 2026

This branch has not been deployed

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

Labels

Product Visibility Contains user-facing updates that may need to be documented and/or announced

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant