Skip to content
This repository has been archived by the owner on Apr 24, 2023. It is now read-only.

Commit

Permalink
Merge pull request #13 from FunnyLabz/master
Browse files Browse the repository at this point in the history
Fix 'require.js' load issue while loading web page + add explanation on how to use on web + make it easier to integrate this lib on a project
  • Loading branch information
deakjahn authored Feb 8, 2021
2 parents 072ad54 + f008003 commit 8a3dee8
Show file tree
Hide file tree
Showing 15 changed files with 264 additions and 118 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
.pub-cache/
.pub/
build/
generated_plugin_registrant.dart

# Android related
**/android/**/gradle-wrapper.jar
Expand Down
63 changes: 59 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,63 @@
# sqflite_web

These are the first steps to start a web version of [sqflite](https://pub.dev/packages/sqflite). Right now, it already runs and creates a test database and writes a few records.
This is a web version of [sqflite](https://pub.dev/packages/sqflite).

Please, note that this is experimental. It's not on pub.dev and not automatically endorsed by Sqflite as the web implementation because these are just the first steps to see if it's feasible at all.
There is no persistence and copies of the same app running in different browser tabs would see different, separate databases.
Use it if it fits your requirements and suggest solutions to the missing functionality if you have ideas but don't expect it to be a full Sqflite implementation on the web.

While the code itself is functional, the database stays in the memory. There is no persistence and copies of the same app running in different browser tabs would see different, separate databases.
Use it if it fits your requirements and suggest solutions to the missing functionality if you have ideas but don't expect it to be a full Sqflite implementation on the web.
Please, note that this is experimental. It's not on pub.dev and not automatically endorsed by Sqflite as the web implementation because of the persistency issue.

The example runs and creates a test database and writes a few records on web console (F12->console on most web browser or directly on shell if running in debug).


## Install

`pubspec.yaml`:

```yaml
dependencies:
# Database handling (if you want to support other platforms than web too)
sqflite: ^1.3.2+2

dev_dependencies:
# For sqflite web compatibility (will save the database IN MEMORY => not stored)
sqflite_web:
git:
url: https://github.com/FunnyLabz/sqflite_web.git
ref: master
```
`main.dart` (or any other dart file)

```dart
import 'package:sqflite/sqflite.dart';
import 'package:sqflite_web/sqflite_web.dart';
import 'package:flutter/foundation.dart';
void main() {
(...)
// Open the database and do whatever you want
Database appDatabase;
if (kIsWeb) {
// Use the database from memory (no persistency on web...)
var databaseFactory = databaseFactoryWeb;
appDatabase = await databaseFactory.openDatabase(inMemoryDatabasePath);
} else {
// Other platforms (store on real file)
appDatabase = await databaseFactory.openDatabase((await getApplicationDocumentsDirectory()).path + '/app.db');
}
(...)
}
```

Add this line in `web/index.html`:
```html
<body>
<script src="assets/packages/sqflite_web/assets/require.js" type="application/javascript"></script>
(...)
</body>
```
Note: The `require.js` library will be added dynamically if you forget to add this line in `index.html`
(but this will imply users do a 'refresh' of the web page every time they want to access it because of dynamic include issues).
13 changes: 0 additions & 13 deletions example/lib/generated_plugin_registrant.dart

This file was deleted.

25 changes: 19 additions & 6 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,14 @@ import 'package:sqflite_common/sqlite_api.dart';
import 'package:sqflite_web/sqflite_web.dart';

Future main() async {
print("Opening the database...");
var databaseFactory = databaseFactoryWeb;
var db = await databaseFactory.openDatabase(inMemoryDatabasePath);

print("Setting the version in the database...");
await db.setVersion(10);

print("Create a table in the database...");
await db.execute('''
CREATE TABLE Product (
id INTEGER PRIMARY KEY,
Expand All @@ -27,18 +32,26 @@ Future main() async {

if (ok) {
var result = await db.query('Product');
print(result); // [{columns: [id, title], rows: [[1, Product 1], [2, Product 2], [3, Product 3], [4, Product 4], [5, Product 5]]}]
// [{columns: [id, title], rows: [[1, Product 1], [2, Product 2], [3, Product 3], [4, Product 4], [5, Product 5]]}]
print(result);

print(await db.getVersion()); // 10

var update = await db.update('Product', <String, dynamic>{'title': 'PRODUCT 1'}, where: 'id = ?', whereArgs: [1]);
var update = await db.update(
'Product', <String, dynamic>{'title': 'PRODUCT 1'},
where: 'id = ?', whereArgs: [1]);
print(update);

result = await db.rawQuery('SELECT * FROM Product', []);
print(result); // [{columns: [id, title], rows: [[1, PRODUCT 1], [2, Product 2], [3, Product 3], [4, Product 4], [5, Product 5]]}]

result = await db.rawQuery('SELECT * FROM Product WHERE title = ?', ['PRODUCT 1']);
print(result); // [{columns: [id, title], rows: [[1, PRODUCT 1]]}]
// [{columns: [id, title], rows: [[1, PRODUCT 1], [2, Product 2], [3, Product 3], [4, Product 4], [5, Product 5]]}]
print(result);

result = await db
.rawQuery('SELECT * FROM Product WHERE title = ?', ['PRODUCT 1']);
// [{columns: [id, title], rows: [[1, PRODUCT 1]]}]
print(result);
} else {
print("Failed to do the database transaction...");
}

await db.close();
Expand Down
4 changes: 2 additions & 2 deletions example/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -125,14 +125,14 @@ packages:
name: sqflite_common
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.2+1"
version: "1.0.3+1"
sqflite_web:
dependency: "direct dev"
description:
path: ".."
relative: true
source: path
version: "1.0.1"
version: "1.1.0"
stack_trace:
dependency: transitive
description:
Expand Down
1 change: 1 addition & 0 deletions example/web/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
<link rel="manifest" href="manifest.json">
</head>
<body>
<script src="assets/packages/sqflite_web/assets/require.js" type="application/javascript"></script>
<!-- This script installs service_worker.js to provide PWA functionality to
application. For more information, see:
https://developers.google.com/web/fundamentals/primers/service-workers -->
Expand Down
2 changes: 1 addition & 1 deletion lib/assets/sqflite_web.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ requirejs(['initSqlJs'], function(initSqlJs) {

execute: function(sql) {
var result = sqflite_web.db.exec(sql);
// This supposes we never pass more than one SQL statement at once (it's prohibited if we pass arguments in, anyway). Is this OK?
// This supposes we never pass more than one SQL statement at once (it's prohibited if we pass arguments in, anyway). Is this OK?
return result[0];
},

Expand Down
44 changes: 2 additions & 42 deletions lib/sqflite_web.dart
Original file line number Diff line number Diff line change
@@ -1,42 +1,2 @@
import 'dart:async';
import 'dart:html' as html;

import 'package:flutter_web_plugins/flutter_web_plugins.dart';
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
import 'package:sqflite_common/sqlite_api.dart';
import 'package:sqflite_web/src/database_factory.dart';

/// The database factory to use for Web.
///
/// Check support documentation.
DatabaseFactory get databaseFactoryWeb => databaseFactoryWebImpl;

/// The Web plugin registration.
class SqflitePluginWeb extends PlatformInterface {
static final _readyCompleter = Completer<bool>();

/// Shows if the Sql.js library has been loaded
static Future<bool> isReady;

/// Registers the Web database factory.
static void registerWith(Registrar registrar) {
isReady = _readyCompleter.future;
html.window.addEventListener('sqflite_web_ready', (_) => _readyCompleter.complete(true));

final body = html.window.document.querySelector('body');
// Hot reload would add it again
// ignore: omit_local_variable_types
for (html.ScriptElement script in body.querySelectorAll('script')) {
if (script.src.contains('sqflite_web')) {
script.remove();
}
}

body.append(html.ScriptElement()
..src = 'assets/packages/sqflite_web/assets/require.js'
..type = 'application/javascript');
body.append(html.ScriptElement()
..src = 'assets/packages/sqflite_web/assets/sqflite_web.js'
..type = 'application/javascript');
}
}
export 'src/sqflite_web_stub.dart'
if (dart.library.html) 'src/sqflite_web.dart';
11 changes: 7 additions & 4 deletions lib/src/database_factory.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'package:sqflite_common/sqlite_api.dart';
import 'package:sqflite_web/sqflite_web.dart';
import 'package:sqflite_web/src/sqflite_web_impl.dart';

import 'sqflite_web.dart';
import 'sqflite_web_impl.dart';

DatabaseFactory _databaseFactoryWebImpl;

Expand Down Expand Up @@ -32,8 +33,10 @@ class DatabaseFactoryWeb extends DatabaseFactory {
}

@override
Future<Database> openDatabase(String path, {OpenDatabaseOptions options}) async {
Future<Database> openDatabase(String path,
{OpenDatabaseOptions options}) async {
await SqflitePluginWeb.isReady;
return _db ??= SqfliteWebDatabase(path: path, readOnly: false, logLevel: sqfliteLogLevelNone);
return _db ??= SqfliteWebDatabase(
path: path, readOnly: false, logLevel: sqfliteLogLevelNone);
}
}
59 changes: 59 additions & 0 deletions lib/src/sqflite_web.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import 'dart:async';
import 'dart:html' as html;

import 'package:flutter_web_plugins/flutter_web_plugins.dart';
import 'package:plugin_platform_interface/plugin_platform_interface.dart';

import 'package:sqflite_common/sqlite_api.dart';

import 'database_factory.dart';

/// The database factory to use for Web.
///
/// Check support documentation.
DatabaseFactory get databaseFactoryWeb => databaseFactoryWebImpl;

/// The Web plugin registration.
class SqflitePluginWeb extends PlatformInterface {
static final _readyCompleter = Completer<bool>();

/// Shows if the Sql.js library has been loaded
static Future<bool> isReady;

/// Registers the Web database factory.
static void registerWith(Registrar registrar) {
isReady = _readyCompleter.future;
html.window.addEventListener(
'sqflite_web_ready', (_) => _readyCompleter.complete(true));

final body = html.window.document.querySelector('body');

// Add 'sqflite_web.js' (and 'require.js') dynamically if not already imported
// (this is needed to prevent hot reload or refresh to import it again and again)
var foundRequireJs = false;
var foundSqfliteWebJs = false;
for (html.ScriptElement script in body.querySelectorAll('script')) {
if (script.src
.contains('assets/packages/sqflite_web/assets/require.js')) {
foundRequireJs = true;
}
if (script.src
.contains('assets/packages/sqflite_web/assets/sqflite_web.js')) {
foundSqfliteWebJs = true;
}
}

if (!foundRequireJs) {
print(
"<!> WARNING: Importing 'require.js' from sqlite_web, considere importing it directlty from your html file like this: '<script src=\"assets/packages/sqflite_web/assets/require.js\" type=\"application/javascript\"></script>'");
body.append(html.ScriptElement()
..src = 'assets/packages/sqflite_web/assets/require.js'
..type = 'application/javascript');
}
if (!foundSqfliteWebJs) {
body.append(html.ScriptElement()
..src = 'assets/packages/sqflite_web/assets/sqflite_web.js'
..type = 'application/javascript');
}
}
}
9 changes: 6 additions & 3 deletions lib/src/sqflite_web_exception.dart
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import 'package:meta/meta.dart';
import 'package:sqflite_web/src/sqflite_import.dart';
import 'package:sqflite_web/src/sqflite_web_impl.dart';

import 'sqflite_import.dart';
import 'sqflite_web_impl.dart';

/// Web exception.
class SqfliteWebException extends SqfliteDatabaseException {
/// Web exception.
SqfliteWebException({@required this.code, @required String message, this.details}) : super(message, details);
SqfliteWebException(
{@required this.code, @required String message, this.details})
: super(message, details);

/// The database.
SqfliteWebDatabase database;
Expand Down
Loading

0 comments on commit 8a3dee8

Please sign in to comment.