borogove
created pr with
borogove/sqlite-injectable-driver.1
commented
Changes are available at https://tangled.org/mrry.band/borogove on branch sqlite-injectable-driver.
added borogove/sqlite-injectable-driver.2
1: 981fe7d = 1: 981fe7d Use arrays
2: ef9e639 = 2: ef9e639 Make prepare public, remove formatParam and first
3: f949361 ! 3: a97c836 Allow injectable drivers for Sqlite
commented
browser tests dont pass
added borogove/sqlite-injectable-driver.3
1: 981fe7d = 1: 981fe7d Use arrays
2: ef9e639 ! 2: 11eb826 Make prepare public, remove formatParam and first
3: a97c836 ! 3: 34cee7d Allow injectable drivers for Sqlite
cmds
checkout latest patchset:
ssh pr.pico.sh pull borogove:sqlite-injectable-driver | git am -3checkout specific patchset revision:
ssh pr.pico.sh pull borogove:sqlite-injectable-driver [rev] | git am -3add changes to patch request:
git format-patch main --stdout | ssh pr.pico.sh borogove:sqlite-injectable-driveradd comment to patch request:
ssh pr.pico.sh comment borogove:sqlite-injectable-driver "lgtm!"
Patchset
borogove/sqlite-injectable-driver.3
Allow injectable drivers for Sqlite
Eric Roberts
2026-11-09T19:41:16ZIn Tauri I want to use https://v2.tauri.app/plugin/sql/ so we can put the db on the filesystem. To do that I need to be able to pass in a custom driver in borogove. This does that.
Semantic diff summary
0 added,
0 modified,
0 signature changed,
0 removed
across 0 analyzed files
(2 files skipped: unsupported file type)
+24
-3
borogove/persistence/Sqlite.hx
#
| ... | ... | @@ -34,13 +34,25 @@ typedef InsertColumn = { | |
| 34 | 34 | value:(ChatMessage)->Dynamic | |
| 35 | 35 | } | |
| 36 | 36 | ||
| 37 | + | @:expose | |
| 38 | + | typedef SqliteDriverInterface = { | |
| 39 | + | function exec(sql: String, ?params: Array<Dynamic>): Promise<Array<Dynamic>>; | |
| 40 | + | function execMany(qs: Array<{ sql: String, ?params: Array<Dynamic> }>): Promise<Array<Dynamic>>; | |
| 41 | + | } | |
| 42 | + | ||
| 43 | + | typedef SqliteDriverFactory = (String, (Array<String>->Promise<Array<Dynamic>>)->Promise<Any>)->SqliteDriverInterface; | |
| 44 | + | ||
| 37 | 45 | @:expose | |
| 38 | 46 | #if cpp | |
| 39 | 47 | @:build(HaxeCBridge.expose()) | |
| 40 | 48 | @:build(HaxeSwiftBridge.expose()) | |
| 41 | 49 | #end | |
| 42 | 50 | class Sqlite implements Persistence implements KeyValueStore { | |
| 51 | + | #if js | |
| 52 | + | final db: SqliteDriverInterface; | |
| 53 | + | #else | |
| 43 | 54 | final db: SqliteDriver; | |
| 55 | + | #end | |
| 44 | 56 | final media: MediaStore; | |
| 45 | 57 | final storeMessagesSerialized = new AsyncLock(); | |
| 46 | 58 |
| ... | ... | @@ -85,10 +97,14 @@ class Sqlite implements Persistence implements KeyValueStore { | |
| 85 | 97 | @param media a MediaStore to use for media | |
| 86 | 98 | @returns new persistence layer | |
| 87 | 99 | **/ | |
| 88 | - | public function new(dbfile: String, media: MediaStore) { | |
| 100 | + | public function new( | |
| 101 | + | dbfile: String, | |
| 102 | + | media: MediaStore, | |
| 103 | + | #if js ?driver: SqliteDriverFactory, #end | |
| 104 | + | ) { | |
| 89 | 105 | this.media = media; | |
| 90 | 106 | media.setKV(this); | |
| 91 | - | db = new SqliteDriver(dbfile, (exec) -> { | |
| 107 | + | final migrate = (exec: Array<String>->Promise<Array<Dynamic>>) -> { | |
| 92 | 108 | exec(["PRAGMA user_version"]).then(rows -> { | |
| 93 | 109 | final version = Std.parseInt(rows[0]?.user_version) ?? 0; | |
| 94 | 110 | return Promise.resolve(null).then(_ -> { |
| ... | ... | @@ -387,7 +403,12 @@ class Sqlite implements Persistence implements KeyValueStore { | |
| 387 | 403 | return Promise.resolve(null); | |
| 388 | 404 | }); | |
| 389 | 405 | }); | |
| 390 | - | }); | |
| 406 | + | }; | |
| 407 | + | #if js | |
| 408 | + | db = driver == null ? new SqliteDriver(dbfile, migrate) : driver(dbfile, migrate); | |
| 409 | + | #else | |
| 410 | + | db = new SqliteDriver(dbfile, migrate); | |
| 411 | + | #end | |
| 391 | 412 | } | |
| 392 | 413 | ||
| 393 | 414 | @HaxeCBridge.noemit |
+29
-0
test/TestSqlite.hx
#
| ... | ... | @@ -104,6 +104,35 @@ class TestSqlite extends utest.Test { | |
| 104 | 104 | mediaStore = new MockMediaStore(); | |
| 105 | 105 | persistence = new Sqlite("file:" + ID.unique() + "?mode=memory&cache=shared", mediaStore); | |
| 106 | 106 | } | |
| 107 | + | #if js | |
| 108 | + | public function testInjectedDriver(async: Async) { | |
| 109 | + | var migrated = Promise.resolve(null); | |
| 110 | + | var migrationQueries: Array<String> = []; | |
| 111 | + | final injected = new Sqlite("injected.sqlite3", mediaStore, (file, migrate) -> { | |
| 112 | + | Assert.equals("injected.sqlite3", file); | |
| 113 | + | migrated = migrate(sql -> { | |
| 114 | + | migrationQueries = migrationQueries.concat(sql); | |
| 115 | + | return Promise.resolve([{ user_version: 24 }]); | |
| 116 | + | }); | |
| 117 | + | return { | |
| 118 | + | exec: (sql: String, ?params: Array<Dynamic>) -> { | |
| 119 | + | Assert.equals("SELECT v FROM keyvaluepairs WHERE k=? LIMIT 1", sql); | |
| 120 | + | Assert.equals("key", params[0]); | |
| 121 | + | return Promise.resolve([{ v: "injected value" }]); | |
| 122 | + | }, | |
| 123 | + | execMany: qs -> Promise.resolve([]) | |
| 124 | + | }; | |
| 125 | + | }); | |
| 126 | + | migrated.then(_ -> injected.get("key")).then(value -> { | |
| 127 | + | Assert.same(["PRAGMA user_version"], migrationQueries); | |
| 128 | + | Assert.equals("injected value", value); | |
| 129 | + | async.done(); | |
| 130 | + | }).catchError(e -> { | |
| 131 | + | Assert.fail(Std.string(e)); | |
| 132 | + | async.done(); | |
| 133 | + | }); | |
| 134 | + | } | |
| 135 | + | #end | |
| 107 | 136 | ||
| 108 | 137 | public function testOrder(async: Async) { | |
| 109 | 138 | final account = "alice@example.com"; |