From 0ccf25cba2bc5da05d681823e8f07b8a32bcdb75 Mon Sep 17 00:00:00 2001 From: Chima Precious Date: Thu, 18 Sep 2025 12:50:25 +0000 Subject: [PATCH 1/2] expose sqlite_changes function --- src/lib.rs | 17 +++++++++++++++++ src/sqlite.rs | 1 + src/transport/mod.rs | 2 ++ src/utils.rs | 5 +++++ 4 files changed, 25 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 1b9204e..e6aaa23 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -89,6 +89,7 @@ pub unsafe extern "C" fn sqlite3_open_v2( connection: connection.unwrap(), transaction_baton: Mutex::new(None), last_insert_rowid: Mutex::new(None), + rows_written: Mutex::new(None), transaction_has_began: Mutex::new(false), delete_hook: Mutex::new(None), insert_hook: Mutex::new(None), @@ -383,6 +384,22 @@ pub unsafe extern "C" fn sqlite3_extended_errcode(_: *mut SQLite3) -> c_int { SQLITE_OK } +#[no_mangle] +pub unsafe extern "C" fn sqlite3_changes(db: *mut SQLite3) -> c_int { + if !is_aligned(db) { + return SQLITE_OK; + } + let db = &mut *db; + + if let Ok(rows_written) = db.rows_written.lock() { + if rows_written.is_some() { + return rows_written.unwrap() as c_int; + } + } + + 0 +} + #[no_mangle] pub unsafe extern "C" fn sqlite3_errmsg(_: *mut SQLite3) -> *const c_char { if let Some(error_entry) = sqlite::get_latest_error() { diff --git a/src/sqlite.rs b/src/sqlite.rs index 3e1ed22..1cf1b8b 100644 --- a/src/sqlite.rs +++ b/src/sqlite.rs @@ -86,6 +86,7 @@ lazy_static! { pub struct SQLite3 { pub connection: transport::DatabaseConnection, // Connection to the database pub last_insert_rowid: Mutex>, // Last inserted row ID + pub rows_written: Mutex>, // Number of rows written pub transaction_baton: Mutex>, // Baton for transaction management pub transaction_has_began: Mutex, // Flag to check if a transaction has started pub update_hook: Mutex>, // Update hook callback diff --git a/src/transport/mod.rs b/src/transport/mod.rs index 5d49348..180c038 100644 --- a/src/transport/mod.rs +++ b/src/transport/mod.rs @@ -51,6 +51,8 @@ pub struct RemoteRow { pub struct QueryResult { pub cols: Vec, pub rows: Vec>, + pub rows_read: Option, + pub rows_written: Option, pub last_insert_rowid: Option, } diff --git a/src/utils.rs b/src/utils.rs index 2dad72d..c263975 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -144,5 +144,10 @@ pub fn get_execution_result<'a>( *last_insert_rowid_lock = Some(last_insert_rowid.parse::().unwrap_or(0)); } + if let Some(rows_written) = &first_execution_result.rows_written { + let mut rows_written_lock = db.rows_written.lock().unwrap(); + *rows_written_lock = Some(*rows_written); + } + Ok(first_execution_result) } From 55efa02b6c49b2b2bdf26447bea1ebedddf7b992 Mon Sep 17 00:00:00 2001 From: Chima Precious Date: Thu, 18 Sep 2025 12:51:57 +0000 Subject: [PATCH 2/2] _ --- bin/libsqlite3_turso.dart | 91 ++++++++++++++++ bin/proxy_server.dart | 44 -------- bin/sqlite_test.dart | 50 --------- lib/database.dart | 24 +++++ pubspec.lock | 218 +++++++++++++++++++++++++++++++++----- pubspec.yaml | 7 +- 6 files changed, 312 insertions(+), 122 deletions(-) create mode 100644 bin/libsqlite3_turso.dart delete mode 100644 bin/proxy_server.dart delete mode 100644 bin/sqlite_test.dart create mode 100644 lib/database.dart diff --git a/bin/libsqlite3_turso.dart b/bin/libsqlite3_turso.dart new file mode 100644 index 0000000..57ec111 --- /dev/null +++ b/bin/libsqlite3_turso.dart @@ -0,0 +1,91 @@ +import 'dart:io'; + +import '../lib/database.dart'; +import 'package:path/path.dart' as path; +import 'package:drift/drift.dart'; + +// ignore: public_member_api_docs +void copyBinaryIfNecessary() { + const libraryName = 'libsqlite3.so'; + final systemBinary = File('/lib/$libraryName')..createSync(recursive: true); + + final customBinary = () { + file({required bool debug}) => File(path.join(Directory.current.path, + 'target', debug ? 'debug' : 'release', libraryName)); + + if (file(debug: false).existsSync()) { + return file(debug: false); + } else if (file(debug: true).existsSync()) { + return file(debug: true); + } else { + throw Exception('No custom SQLite binary found in target directory.'); + } + }(); + + customBinary.copySync(systemBinary.path); +} + +void main() async { + copyBinaryIfNecessary(); + + final database = AppDatabase(); + + await database.transaction(() async { + // Create the table if it doesn't exist + final result = await database.into(database.todoItems).insert( + TodoItemsCompanion.insert( + title: 'todo: setup drift', + content: 'We need to set up drift for our SQLite database.', + ), + ); + + await (database + .update(database.todoItems) + ..where((tbl) => tbl.id.equals(result))) + .write(TodoItemsCompanion(content: const Value('Updated content'))); + + + print('Inserted item with ID: $result'); + }); + + // final allItems = await database.select(database.todoItems).get(); + // for (final item in allItems) { + // print('Item: ${item.title}, Content: ${item.content}'); + // } + + // final server = await HttpServer.bind(InternetAddress.anyIPv4, 8081); + + // var index = 0; + + // server.listen((request) async { + // final isEven = index % 2 == 0; + + // final stopwatch = Stopwatch()..start(); + + // final result = await Future.wait([ + // db.getAll('SELECT * FROM notes WHERE is_deleted = 0'), + // db.getAll( + // 'SELECT * FROM notes WHERE id = ?', + // ['8703e588-c847-4cb6-b250-726db8afb49a'], + // ), + // ]); + // stopwatch.stop(); + + // print('Query took ${stopwatch.elapsedMilliseconds} ms'); + + // request.response + // ..statusCode = HttpStatus.ok + // ..headers.contentType = ContentType.json + // ..write(isEven ? result[0] : result[1]) + // ..close(); + + // index++; + // }); + + // print('Server running on http://${server.address.address}:${server.port}'); + // ProcessSignal.sigterm.watch().listen((_) async { + // await server.close(); + // await db.close(); + // print('Server stopped.'); + // }); +} diff --git a/bin/proxy_server.dart b/bin/proxy_server.dart deleted file mode 100644 index 31039a9..0000000 --- a/bin/proxy_server.dart +++ /dev/null @@ -1,44 +0,0 @@ -import 'dart:convert'; -import 'dart:io'; - -void main() async { - final server = await HttpServer.bind(InternetAddress.anyIPv4, 8080); - - server.listen((request) async { - if (request.uri.path == '/db/auth') { - final response = { - 'db_url': 'staging-db-lhr-08c0519209-simple-tail-globe.turso.io', - 'db_token': - 'eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJhIjoicnciLCJleHAiOjE3NTQ2NzIwMDAsImlhdCI6MTc1NDU4NTYwMCwiaWQiOiJiMTZkZDkxMS05NmE4LTQzYTMtYTg3OC01ZGMzZjQ5MjVlZTkifQ.GrjdkI7SSLG3yTjpqFVzDGOdxs0PNlsvh3sVmkiQ-k0Rkvhv1h_-56tNmHLk_TYruW6vySmpr8UMhbKDN9tdBw', - }; - - request.response - ..statusCode = HttpStatus.ok - ..headers.contentType = ContentType.json - ..write(json.encode(response)) - ..close(); - return; - } - - // Handle the request - if (request.method == 'GET') { - request.response - ..write('Hello from the proxy server!') - ..close(); - } else { - request.response - ..statusCode = HttpStatus.methodNotAllowed - ..write('Method not allowed') - ..close(); - } - }); - - print( - 'Proxy server running on http://${server.address.address}:${server.port}'); - - // Handle server shutdown gracefully - ProcessSignal.sigterm.watch().listen((_) async { - await server.close(); - print('Proxy server stopped.'); - }); -} diff --git a/bin/sqlite_test.dart b/bin/sqlite_test.dart deleted file mode 100644 index e6fbcc4..0000000 --- a/bin/sqlite_test.dart +++ /dev/null @@ -1,50 +0,0 @@ -import 'dart:io'; - -import 'package:sqlite_async/sqlite_async.dart'; -import 'package:path/path.dart' as path; - -final migrations = SqliteMigrations() - ..add(SqliteMigration(1, (tx) async { - await tx.execute( - 'CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)', - ); - })); - -// ignore: public_member_api_docs -void copyBinaryIfNecessary() { - const libraryName = 'libsqlite3.so'; - final systemBinary = File('/lib/$libraryName')..createSync(recursive: true); - - final customBinary = - File(path.join(Directory.current.path, 'target', 'debug', libraryName)); - customBinary.copySync(systemBinary.path); -} - -void main() async { - copyBinaryIfNecessary(); - final db = SqliteDatabase(path: 'simple-nubian'); - - await migrations.migrate(db); - - // // Use execute() or executeBatch() for INSERT/UPDATE/DELETE statements - // await db.executeBatch('INSERT INTO users(name, email) values(?, ?)', [ - // ['Amen', 'oxy@gmail.com'], - // ['Moron', 'moron@gmail.com'] - // ]); - - // var results = await db.getAll('SELECT * FROM users'); - // print('Results: $results'); - - // await db.writeTransaction((tx) async { - // await tx.execute( - // 'INSERT INTO users(name, email) values(?, ?)', - // ['Test3', 'test3@example.com'], - // ); - // await tx.execute( - // 'INSERT INTO users(name, email) values(?, ?)', - // ['Test4', 'test4@example.com'], - // ); - // }); - - // await db.close(); -} diff --git a/lib/database.dart b/lib/database.dart new file mode 100644 index 0000000..a315bb0 --- /dev/null +++ b/lib/database.dart @@ -0,0 +1,24 @@ +import 'package:drift/drift.dart'; +import 'package:drift/native.dart'; +import 'package:sqlite3/sqlite3.dart'; + +part 'database.g.dart'; + +class TodoItems extends Table { + IntColumn get id => integer().autoIncrement()(); + TextColumn get title => text().withLength(min: 6, max: 32)(); + TextColumn get content => text().named('body')(); + DateTimeColumn get createdAt => dateTime().nullable()(); +} + +@DriftDatabase(tables: [TodoItems]) +class AppDatabase extends _$AppDatabase { + AppDatabase() : super(_openConnection()); + + @override + int get schemaVersion => 1; + + static QueryExecutor _openConnection() { + return NativeDatabase.opened(sqlite3.open('simple-nubian.db')); + } +} diff --git a/pubspec.lock b/pubspec.lock index 24c3efe..8e4a723 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -41,6 +41,86 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.2" + build: + dependency: transitive + description: + name: build + sha256: "7174c5d84b0fed00a1f5e7543597b35d67560465ae3d909f0889b8b20419d5e3" + url: "https://pub.dev" + source: hosted + version: "3.0.1" + build_config: + dependency: transitive + description: + name: build_config + sha256: "4ae2de3e1e67ea270081eaee972e1bd8f027d459f249e0f1186730784c2e7e33" + url: "https://pub.dev" + source: hosted + version: "1.1.2" + build_daemon: + dependency: transitive + description: + name: build_daemon + sha256: "8e928697a82be082206edb0b9c99c5a4ad6bc31c9e9b8b2f291ae65cd4a25daa" + url: "https://pub.dev" + source: hosted + version: "4.0.4" + build_resolvers: + dependency: transitive + description: + name: build_resolvers + sha256: "82730bf3d9043366ba8c02e4add05842a10739899520a6a22ddbd22d333bd5bb" + url: "https://pub.dev" + source: hosted + version: "3.0.1" + build_runner: + dependency: "direct dev" + description: + name: build_runner + sha256: "32c6b3d172f1f46b7c4df6bc4a47b8d88afb9e505dd4ace4af80b3c37e89832b" + url: "https://pub.dev" + source: hosted + version: "2.6.1" + build_runner_core: + dependency: transitive + description: + name: build_runner_core + sha256: "4b188774b369104ad96c0e4ca2471e5162f0566ce277771b179bed5eabf2d048" + url: "https://pub.dev" + source: hosted + version: "9.2.1" + built_collection: + dependency: transitive + description: + name: built_collection + sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" + url: "https://pub.dev" + source: hosted + version: "5.1.1" + built_value: + dependency: transitive + description: + name: built_value + sha256: ba95c961bafcd8686d1cf63be864eb59447e795e124d98d6a27d91fcd13602fb + url: "https://pub.dev" + source: hosted + version: "8.11.1" + charcode: + dependency: transitive + description: + name: charcode + sha256: fb0f1107cac15a5ea6ef0a6ef71a807b9e4267c713bb93e00e92d737cc8dbd8a + url: "https://pub.dev" + source: hosted + version: "1.4.0" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff + url: "https://pub.dev" + source: hosted + version: "2.0.3" cli_config: dependency: transitive description: @@ -49,6 +129,22 @@ packages: url: "https://pub.dev" source: hosted version: "0.2.0" + cli_util: + dependency: transitive + description: + name: cli_util + sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c + url: "https://pub.dev" + source: hosted + version: "0.4.2" + code_builder: + dependency: transitive + description: + name: code_builder + sha256: "0ec10bf4a89e4c613960bf1e8b42c64127021740fb21640c29c909826a5eea3e" + url: "https://pub.dev" + source: hosted + version: "4.10.1" collection: dependency: transitive description: @@ -81,6 +177,30 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.6" + dart_style: + dependency: transitive + description: + name: dart_style + sha256: "8a0e5fba27e8ee025d2ffb4ee820b4e6e2cf5e4246a6b1a477eb66866947e0bb" + url: "https://pub.dev" + source: hosted + version: "3.1.1" + drift: + dependency: "direct main" + description: + name: drift + sha256: "6aaea757f53bb035e8a3baedf3d1d53a79d6549a6c13d84f7546509da9372c7c" + url: "https://pub.dev" + source: hosted + version: "2.28.1" + drift_dev: + dependency: "direct dev" + description: + name: drift_dev + sha256: "2fc05ad458a7c562755bf0cae11178dfc58387a416829b78d4da5155a61465fd" + url: "https://pub.dev" + source: hosted + version: "2.28.1" ffi: dependency: transitive description: @@ -97,6 +217,14 @@ packages: url: "https://pub.dev" source: hosted version: "7.0.1" + fixnum: + dependency: transitive + description: + name: fixnum + sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be + url: "https://pub.dev" + source: hosted + version: "1.1.1" frontend_server_client: dependency: transitive description: @@ -113,6 +241,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.3" + graphs: + dependency: transitive + description: + name: graphs + sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0" + url: "https://pub.dev" + source: hosted + version: "2.3.2" http_multi_server: dependency: transitive description: @@ -145,6 +281,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.7.1" + json_annotation: + dependency: transitive + description: + name: json_annotation + sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" + url: "https://pub.dev" + source: hosted + version: "4.9.0" lints: dependency: "direct dev" description: @@ -173,10 +317,10 @@ packages: dependency: transitive description: name: meta - sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c + sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" url: "https://pub.dev" source: hosted - version: "1.16.0" + version: "1.17.0" mime: dependency: transitive description: @@ -185,14 +329,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.0" - mutex: - dependency: transitive - description: - name: mutex - sha256: "8827da25de792088eb33e572115a5eb0d61d61a3c01acbc8bcbe76ed78f1a1f2" - url: "https://pub.dev" - source: hosted - version: "3.1.0" node_preamble: dependency: transitive description: @@ -210,7 +346,7 @@ packages: source: hosted version: "2.2.0" path: - dependency: "direct main" + dependency: transitive description: name: path sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" @@ -233,6 +369,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.2.0" + pubspec_parse: + dependency: transitive + description: + name: pubspec_parse + sha256: "0560ba233314abbed0a48a2956f7f022cce7c3e1e73df540277da7544cad4082" + url: "https://pub.dev" + source: hosted + version: "1.5.0" + recase: + dependency: transitive + description: + name: recase + sha256: e4eb4ec2dcdee52dcf99cb4ceabaffc631d7424ee55e56f280bc039737f89213 + url: "https://pub.dev" + source: hosted + version: "4.1.0" shelf: dependency: transitive description: @@ -265,6 +417,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.1" + source_gen: + dependency: transitive + description: + name: source_gen + sha256: "7b19d6ba131c6eb98bfcbf8d56c1a7002eba438af2e7ae6f8398b2b0f4f381e3" + url: "https://pub.dev" + source: hosted + version: "3.1.0" source_map_stack_trace: dependency: transitive description: @@ -290,29 +450,21 @@ packages: source: hosted version: "1.10.1" sqlite3: - dependency: transitive + dependency: "direct main" description: name: sqlite3 sha256: f393d92c71bdcc118d6203d07c991b9be0f84b1a6f89dd4f7eed348131329924 url: "https://pub.dev" source: hosted version: "2.9.0" - sqlite3_web: + sqlparser: dependency: transitive description: - name: sqlite3_web - sha256: "0f6ebcb4992d1892ac5c8b5ecd22a458ab9c5eb6428b11ae5ecb5d63545844da" + name: sqlparser + sha256: "7c859c803cf7e9a84d6db918bac824545045692bbe94a6386bd3a45132235d09" url: "https://pub.dev" source: hosted - version: "0.3.2" - sqlite_async: - dependency: "direct main" - description: - name: sqlite_async - sha256: "4da3b035bcce83d10beae879c6539e75230826bba95ed440565b6afbdd8b1550" - url: "https://pub.dev" - source: hosted - version: "0.11.8" + version: "0.41.1" stack_trace: dependency: transitive description: @@ -329,6 +481,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + stream_transform: + dependency: transitive + description: + name: stream_transform + sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871 + url: "https://pub.dev" + source: hosted + version: "2.1.1" string_scanner: dependency: transitive description: @@ -369,6 +529,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.6.12" + timing: + dependency: transitive + description: + name: timing + sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe" + url: "https://pub.dev" + source: hosted + version: "1.0.2" typed_data: dependency: transitive description: @@ -434,4 +602,4 @@ packages: source: hosted version: "3.1.3" sdks: - dart: ">=3.5.0 <4.0.0" + dart: ">=3.7.0 <4.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index c3dd30d..8f2e0fc 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -7,10 +7,11 @@ environment: sdk: ^3.3.1 dependencies: - path: ^1.9.1 - sqlite_async: ^0.11.8 - + drift: ^2.28.1 + sqlite3: ^2.9.0 dev_dependencies: + build_runner: ^2.6.1 + drift_dev: ^2.28.1 lints: ^3.0.0 test: ^1.25.8