mirror of https://github.com/AMT-Cheif/drift.git
163 lines
4.6 KiB
Dart
163 lines
4.6 KiB
Dart
import 'dart:async';
|
|
import 'dart:js';
|
|
|
|
import 'dart:typed_data';
|
|
|
|
// We write our own mapping code to js instead of depending on package:js
|
|
// This way, projects using moor can run on flutter as long as they don't import
|
|
// this file.
|
|
|
|
Completer<SqlJsModule> _moduleCompleter;
|
|
|
|
/// Calls the `initSqlJs` function from the native sql.js library.
|
|
Future<SqlJsModule> initSqlJs() {
|
|
if (_moduleCompleter != null) {
|
|
return _moduleCompleter.future;
|
|
}
|
|
|
|
_moduleCompleter = Completer();
|
|
if (!context.hasProperty('initSqlJs')) {
|
|
return Future.error(
|
|
UnsupportedError('Could not access the sql.js javascript library. '
|
|
'The moor documentation contains instructions on how to setup moor '
|
|
'the web, which might help you fix this.'));
|
|
}
|
|
|
|
(context.callMethod('initSqlJs') as JsObject)
|
|
.callMethod('then', [_handleModuleResolved]);
|
|
|
|
return _moduleCompleter.future;
|
|
}
|
|
|
|
// We're extracting this into its own method so that we don't have to call
|
|
// [allowInterop] on this method or a lambda.
|
|
// todo figure out why dart2js generates invalid js when wrapping this in
|
|
// allowInterop
|
|
void _handleModuleResolved(dynamic module) {
|
|
_moduleCompleter.complete(SqlJsModule._(module as JsObject));
|
|
}
|
|
|
|
/// `sql.js` module from the underlying library
|
|
class SqlJsModule {
|
|
final JsObject _obj;
|
|
SqlJsModule._(this._obj);
|
|
|
|
/// Constructs a new [SqlJsDatabase], optionally from the [data] blob.
|
|
SqlJsDatabase createDatabase([Uint8List data]) {
|
|
final dbObj = _createInternally(data);
|
|
assert(() {
|
|
// set the window.db variable to make debugging easier
|
|
context['db'] = dbObj;
|
|
return true;
|
|
}());
|
|
|
|
return SqlJsDatabase._(dbObj);
|
|
}
|
|
|
|
JsObject _createInternally(Uint8List data) {
|
|
final constructor = _obj['Database'] as JsFunction;
|
|
|
|
if (data != null) {
|
|
return JsObject(constructor, [data]);
|
|
} else {
|
|
return JsObject(constructor);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Dart wrapper around a sql database provided by the sql.js library.
|
|
class SqlJsDatabase {
|
|
final JsObject _obj;
|
|
SqlJsDatabase._(this._obj);
|
|
|
|
/// Returns the `user_version` pragma from sqlite.
|
|
int get userVersion {
|
|
return _selectSingleRowAndColumn('PRAGMA user_version;') as int;
|
|
}
|
|
|
|
/// Sets sqlite's `user_version` pragma to the specified [version].
|
|
set userVersion(int version) {
|
|
run('PRAGMA user_version = $version');
|
|
}
|
|
|
|
/// Calls `prepare` on the underlying js api
|
|
PreparedStatement prepare(String sql) {
|
|
final obj = _obj.callMethod('prepare', [sql]) as JsObject;
|
|
return PreparedStatement._(obj);
|
|
}
|
|
|
|
/// Calls `run(sql)` on the underlying js api
|
|
void run(String sql) {
|
|
_obj.callMethod('run', [sql]);
|
|
}
|
|
|
|
/// Calls `run(sql, args)` on the underlying js api
|
|
void runWithArgs(String sql, List<dynamic> args) {
|
|
final ar = JsArray.from(args);
|
|
_obj.callMethod('run', [sql, ar]);
|
|
}
|
|
|
|
/// Returns the amount of rows affected by the most recent INSERT, UPDATE or
|
|
/// DELETE statement.
|
|
int lastModifiedRows() {
|
|
return _obj.callMethod('getRowsModified') as int;
|
|
}
|
|
|
|
/// The row id of the last inserted row. This counter is reset when calling
|
|
/// [export].
|
|
int lastInsertId() {
|
|
// load insert id. Will return [{columns: [...], values: [[id]]}]
|
|
return _selectSingleRowAndColumn('SELECT last_insert_rowid();') as int;
|
|
}
|
|
|
|
dynamic _selectSingleRowAndColumn(String sql) {
|
|
final results = _obj.callMethod('exec', [sql]) as JsArray;
|
|
final row = results.first as JsObject;
|
|
final data = (row['values'] as JsArray).first as JsArray;
|
|
return data.first;
|
|
}
|
|
|
|
/// Runs `export` on the underlying js api
|
|
Uint8List export() {
|
|
return _obj.callMethod('export') as Uint8List;
|
|
}
|
|
|
|
/// Runs `close` on the underlying js api
|
|
void close() {
|
|
_obj.callMethod('close');
|
|
}
|
|
}
|
|
|
|
/// Dart api wrapping an underlying prepared statement object from the sql.js
|
|
/// library.
|
|
class PreparedStatement {
|
|
final JsObject _obj;
|
|
PreparedStatement._(this._obj);
|
|
|
|
/// Executes this statement with the bound [args].
|
|
void executeWith(List<dynamic> args) {
|
|
_obj.callMethod('bind', [JsArray.from(args)]);
|
|
}
|
|
|
|
/// Performs `step` on the underlying js api
|
|
bool step() {
|
|
return _obj.callMethod('step') as bool;
|
|
}
|
|
|
|
/// Reads the current from the underlying js api
|
|
List<dynamic> currentRow() {
|
|
return _obj.callMethod('get') as JsArray;
|
|
}
|
|
|
|
/// The columns returned by this statement. This will only be available after
|
|
/// [step] has been called once.
|
|
List<String> columnNames() {
|
|
return (_obj.callMethod('getColumnNames') as JsArray).cast<String>();
|
|
}
|
|
|
|
/// Calls `free` on the underlying js api
|
|
void free() {
|
|
_obj.callMethod('free');
|
|
}
|
|
}
|