deakjahn / sqflite_web

A web plugin for https://github.com/tekartik/sqflite
Other
37 stars 20 forks source link

Discussion #1

Open deakjahn opened 4 years ago

deakjahn commented 4 years ago

Initial thoughts

We have a very simple example/main opening the database, creating a table, inserting two records then reading those back, finally closing the database. This already runs fine, leaving notes in the console log.

The implementation is rather simple, basing on the ffi example and leaving out unnecessary items (including the env_utils.dart that's completely unnecessary since it can be queried from the system :-) ).

The implementation implements most of the DatabaseExecutor functions except for the transaction/batch handling.

JavaScript

As to the JS side, the plugin registers its own JS file (no need to manually edit the Index.html) and uses RequireJS to load the sql-js library.

Then we load both the main JS and the WASM files from the CDN, and simply use them with the help of the js package. The documentation can be found at https://sql-js.github.io/sql.js/documentation/class/Database.html .

QuentinCG commented 3 years ago

Hello,

Thanks for this POC !

After some tests, here is my feedback on what is still needed to make this project fully compatible with sqflite:


Example to allow this lib to compile with all platform (NOT PERFECT)

main.dart

...
import 'custom_sqflite/factory_wrapper.dart';

...
    Database appDatabase;
    if (kIsWeb) {
      var databaseFactory = DatabaseFactoryGetter().getDatabaseFactory();
      appDatabase = await databaseFactory.openDatabase(inMemoryDatabasePath);
    } else {
      // Initialize database for other platforms here (using sqflite/sqflite_ffi)
    }
...

factory_wrapper.dart

import 'package:sqflite_common/sqlite_api.dart';

import 'factory_stub.dart'
  if(dart.library.html) 'factory_web.dart';

abstract class DatabaseFactoryGetter {
  DatabaseFactory getDatabaseFactory() => getDatabaseFactory();

  factory DatabaseFactoryGetter() => getImplementation();
}

factory_web.dart

import 'factory_wrapper.dart';

import 'package:sqflite/sqlite_api.dart';
import 'package:sqflite_web/sqflite_web.dart';

class WebDatabaseFactoryGetter implements DatabaseFactoryGetter {
  WebDatabaseFactoryGetter();

  DatabaseFactory getDatabaseFactory() {
   return databaseFactoryWeb;
  }
}

DatabaseFactoryGetter getImplementation() => WebDatabaseFactoryGetter();

factory_stub.dart

import 'factory_wrapper.dart';

DatabaseFactoryGetter getImplementation() => throw UnsupportedError(
    "This constructor should not be used on this platform");
deakjahn commented 3 years ago

Sorry but this is clearly and intentionally a web-only extension to Alex's excellent plugin, mainly a proof of concept, providing a code repository if it can be supported later. It was never intended to be a replacement or a standalone version, hence there's no need to make it multiplatform. As much as I remember his last take on the subject, the lack of persistency and cross-tab synchronization are the major obstacles.

If he ever sees it appropriate to incorporate it, that must clearly be done as a federated plugin, not the old and deprecated way you mention.

QuentinCG commented 3 years ago

I fully understand ;) I clearly know my solution is dirty, I just wanted to add info on how to use this project in addition to sqflite if people build a multiplatform solution and don't want their android build to break because they included this project for web "compatibility".

QuentinCG commented 3 years ago

As for now, this project is clearly more than a POC. It is more than working for real project (thanks to #12 and #13).

Its main "issue" is to not be persistent.

I asked sqflite maintainer plan for a potential integration of this web implementation : https://github.com/tekartik/sqflite/issues/570

ghost commented 2 years ago

For persistence across tabs, how about this:

  1. IndexedDB contains three key value pairs.
  2. First key holds db blob thats loaded on app start.
  3. Second key holds a counter which is incremented everytime first key is written to.
  4. Third key contains a boolean value. which acts like a lock to prevent race conditions. A tab or process which acquired lock can die at any time so that need to be worked out.
  5. Now, all processes monitor second key and whenever it changes, they will reload db from first key into memory.
  6. Before writing to db, a process need to ensure no other process is trying to write to first key.
  7. On acquistion of lock via third key, the process will first load db from first key to ensure consistency, rerun sql transaction against it and then writes to first key and frees the lock.
aytunch commented 1 year ago

@deakjahn Hi, I am in the midst of supporting web platform for a mobile project using sqflite. So I got a couple questions. Do this extension have the exact same API as sqflite? Can I just put kIsWeb checks as @QuentinCG showed above and use sqflite_web methods? Is this still being maintained? And is there web persistency or does it just work in memory? (data is lost when web tab is closed) Thanks

deakjahn commented 1 year ago

@aytunch I can't really answer those questions any more. I saw Alex discuss newer web support in some other threads, so my immediate assumption is that there were some major developments in the meantime but I'm not sure of their extent. There's definitely https://pub.dev/packages/sqflite_common_ffi_web and although with an experimental label, it clearly promises persistency. If it turns out that it's indeed solved, I'd be glad to note it here and archive this repo as no longer relevant.

QuentinCG commented 1 year ago

@aytunch

Same as @deakjahn, I switched to sqflite_common_ffi_web as it is maintained officially (even if 'in beta').

Don't forget to add those files to web/ folder when using sqflite_common_ffi_web (you can generate them by following the doc too): sqflite_for_ffi_web.zip

deakjahn commented 1 year ago

Then I'll put that link into the README. Depending on later reactions, I'll probably archive this repo in the near future.