mirror of https://github.com/AMT-Cheif/drift.git
Create a real example for the web backend
This commit is contained in:
parent
c806a4a7b1
commit
311a47c704
|
@ -0,0 +1,11 @@
|
||||||
|
# See https://github.com/dart-lang/build/tree/master/build_web_compilers#configuration
|
||||||
|
targets:
|
||||||
|
$default:
|
||||||
|
builders:
|
||||||
|
build_web_compilers|entrypoint:
|
||||||
|
generate_for:
|
||||||
|
- web/**.dart
|
||||||
|
options:
|
||||||
|
dart2js_args:
|
||||||
|
- --no-source-maps
|
||||||
|
- -O4
|
|
@ -0,0 +1,47 @@
|
||||||
|
import 'package:moor/moor_web.dart';
|
||||||
|
|
||||||
|
part 'database.g.dart';
|
||||||
|
|
||||||
|
const int _doneEntriesCount = 20;
|
||||||
|
|
||||||
|
@DataClassName('Entry')
|
||||||
|
class TodoEntries extends Table {
|
||||||
|
IntColumn get id => integer().autoIncrement()();
|
||||||
|
|
||||||
|
TextColumn get content => text()();
|
||||||
|
BoolColumn get done => boolean().withDefault(const Constant(false))();
|
||||||
|
}
|
||||||
|
|
||||||
|
@UseMoor(tables: [
|
||||||
|
TodoEntries
|
||||||
|
], queries: {
|
||||||
|
'hiddenEntryCount': 'SELECT COUNT(*) - $_doneEntriesCount AS entries '
|
||||||
|
'FROM todo_entries WHERE done'
|
||||||
|
})
|
||||||
|
class Database extends _$Database {
|
||||||
|
Database() : super(WebDatabase('app', logStatements: true));
|
||||||
|
|
||||||
|
@override
|
||||||
|
final int schemaVersion = 1;
|
||||||
|
|
||||||
|
Stream<List<Entry>> incompleteEntries() {
|
||||||
|
return (select(todoEntries)..where((e) => not(e.done))).watch();
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream<List<Entry>> newestDoneEntries() {
|
||||||
|
return (select(todoEntries)
|
||||||
|
..where((e) => e.done)
|
||||||
|
..orderBy(
|
||||||
|
[(e) => OrderingTerm(expression: e.id, mode: OrderingMode.desc)])
|
||||||
|
..limit(_doneEntriesCount))
|
||||||
|
.watch();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future createTodoEntry(String desc) {
|
||||||
|
return into(todoEntries).insert(TodoEntriesCompanion(content: Value(desc)));
|
||||||
|
}
|
||||||
|
|
||||||
|
Future setCompleted(Entry entry, bool done) {
|
||||||
|
return update(todoEntries).write(entry.copyWith(done: done));
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,32 +7,30 @@ part of 'database.dart';
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
// ignore_for_file: unnecessary_brace_in_string_interps
|
// ignore_for_file: unnecessary_brace_in_string_interps
|
||||||
class TodoEntry extends DataClass implements Insertable<TodoEntry> {
|
class Entry extends DataClass implements Insertable<Entry> {
|
||||||
final int id;
|
final int id;
|
||||||
final String content;
|
final String content;
|
||||||
final DateTime creationDate;
|
final bool done;
|
||||||
TodoEntry(
|
Entry({@required this.id, @required this.content, @required this.done});
|
||||||
{@required this.id, @required this.content, @required this.creationDate});
|
factory Entry.fromData(Map<String, dynamic> data, GeneratedDatabase db,
|
||||||
factory TodoEntry.fromData(Map<String, dynamic> data, GeneratedDatabase db,
|
|
||||||
{String prefix}) {
|
{String prefix}) {
|
||||||
final effectivePrefix = prefix ?? '';
|
final effectivePrefix = prefix ?? '';
|
||||||
final intType = db.typeSystem.forDartType<int>();
|
final intType = db.typeSystem.forDartType<int>();
|
||||||
final stringType = db.typeSystem.forDartType<String>();
|
final stringType = db.typeSystem.forDartType<String>();
|
||||||
final dateTimeType = db.typeSystem.forDartType<DateTime>();
|
final boolType = db.typeSystem.forDartType<bool>();
|
||||||
return TodoEntry(
|
return Entry(
|
||||||
id: intType.mapFromDatabaseResponse(data['${effectivePrefix}id']),
|
id: intType.mapFromDatabaseResponse(data['${effectivePrefix}id']),
|
||||||
content:
|
content:
|
||||||
stringType.mapFromDatabaseResponse(data['${effectivePrefix}content']),
|
stringType.mapFromDatabaseResponse(data['${effectivePrefix}content']),
|
||||||
creationDate: dateTimeType
|
done: boolType.mapFromDatabaseResponse(data['${effectivePrefix}done']),
|
||||||
.mapFromDatabaseResponse(data['${effectivePrefix}creation_date']),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
factory TodoEntry.fromJson(Map<String, dynamic> json,
|
factory Entry.fromJson(Map<String, dynamic> json,
|
||||||
{ValueSerializer serializer = const ValueSerializer.defaults()}) {
|
{ValueSerializer serializer = const ValueSerializer.defaults()}) {
|
||||||
return TodoEntry(
|
return Entry(
|
||||||
id: serializer.fromJson<int>(json['id']),
|
id: serializer.fromJson<int>(json['id']),
|
||||||
content: serializer.fromJson<String>(json['content']),
|
content: serializer.fromJson<String>(json['content']),
|
||||||
creationDate: serializer.fromJson<DateTime>(json['creationDate']),
|
done: serializer.fromJson<bool>(json['done']),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@override
|
@override
|
||||||
|
@ -41,64 +39,61 @@ class TodoEntry extends DataClass implements Insertable<TodoEntry> {
|
||||||
return {
|
return {
|
||||||
'id': serializer.toJson<int>(id),
|
'id': serializer.toJson<int>(id),
|
||||||
'content': serializer.toJson<String>(content),
|
'content': serializer.toJson<String>(content),
|
||||||
'creationDate': serializer.toJson<DateTime>(creationDate),
|
'done': serializer.toJson<bool>(done),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
T createCompanion<T extends UpdateCompanion<TodoEntry>>(bool nullToAbsent) {
|
T createCompanion<T extends UpdateCompanion<Entry>>(bool nullToAbsent) {
|
||||||
return TodoEntriesCompanion(
|
return TodoEntriesCompanion(
|
||||||
id: id == null && nullToAbsent ? const Value.absent() : Value(id),
|
id: id == null && nullToAbsent ? const Value.absent() : Value(id),
|
||||||
content: content == null && nullToAbsent
|
content: content == null && nullToAbsent
|
||||||
? const Value.absent()
|
? const Value.absent()
|
||||||
: Value(content),
|
: Value(content),
|
||||||
creationDate: creationDate == null && nullToAbsent
|
done: done == null && nullToAbsent ? const Value.absent() : Value(done),
|
||||||
? const Value.absent()
|
|
||||||
: Value(creationDate),
|
|
||||||
) as T;
|
) as T;
|
||||||
}
|
}
|
||||||
|
|
||||||
TodoEntry copyWith({int id, String content, DateTime creationDate}) =>
|
Entry copyWith({int id, String content, bool done}) => Entry(
|
||||||
TodoEntry(
|
|
||||||
id: id ?? this.id,
|
id: id ?? this.id,
|
||||||
content: content ?? this.content,
|
content: content ?? this.content,
|
||||||
creationDate: creationDate ?? this.creationDate,
|
done: done ?? this.done,
|
||||||
);
|
);
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return (StringBuffer('TodoEntry(')
|
return (StringBuffer('Entry(')
|
||||||
..write('id: $id, ')
|
..write('id: $id, ')
|
||||||
..write('content: $content, ')
|
..write('content: $content, ')
|
||||||
..write('creationDate: $creationDate')
|
..write('done: $done')
|
||||||
..write(')'))
|
..write(')'))
|
||||||
.toString();
|
.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode => $mrjf($mrjc(
|
int get hashCode => $mrjf(
|
||||||
$mrjc($mrjc(0, id.hashCode), content.hashCode), creationDate.hashCode));
|
$mrjc($mrjc($mrjc(0, id.hashCode), content.hashCode), done.hashCode));
|
||||||
@override
|
@override
|
||||||
bool operator ==(other) =>
|
bool operator ==(other) =>
|
||||||
identical(this, other) ||
|
identical(this, other) ||
|
||||||
(other is TodoEntry &&
|
(other is Entry &&
|
||||||
other.id == id &&
|
other.id == id &&
|
||||||
other.content == content &&
|
other.content == content &&
|
||||||
other.creationDate == creationDate);
|
other.done == done);
|
||||||
}
|
}
|
||||||
|
|
||||||
class TodoEntriesCompanion extends UpdateCompanion<TodoEntry> {
|
class TodoEntriesCompanion extends UpdateCompanion<Entry> {
|
||||||
final Value<int> id;
|
final Value<int> id;
|
||||||
final Value<String> content;
|
final Value<String> content;
|
||||||
final Value<DateTime> creationDate;
|
final Value<bool> done;
|
||||||
const TodoEntriesCompanion({
|
const TodoEntriesCompanion({
|
||||||
this.id = const Value.absent(),
|
this.id = const Value.absent(),
|
||||||
this.content = const Value.absent(),
|
this.content = const Value.absent(),
|
||||||
this.creationDate = const Value.absent(),
|
this.done = const Value.absent(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
class $TodoEntriesTable extends TodoEntries
|
class $TodoEntriesTable extends TodoEntries
|
||||||
with TableInfo<$TodoEntriesTable, TodoEntry> {
|
with TableInfo<$TodoEntriesTable, Entry> {
|
||||||
final GeneratedDatabase _db;
|
final GeneratedDatabase _db;
|
||||||
final String _alias;
|
final String _alias;
|
||||||
$TodoEntriesTable(this._db, [this._alias]);
|
$TodoEntriesTable(this._db, [this._alias]);
|
||||||
|
@ -122,19 +117,17 @@ class $TodoEntriesTable extends TodoEntries
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final VerificationMeta _creationDateMeta =
|
final VerificationMeta _doneMeta = const VerificationMeta('done');
|
||||||
const VerificationMeta('creationDate');
|
GeneratedBoolColumn _done;
|
||||||
GeneratedDateTimeColumn _creationDate;
|
|
||||||
@override
|
@override
|
||||||
GeneratedDateTimeColumn get creationDate =>
|
GeneratedBoolColumn get done => _done ??= _constructDone();
|
||||||
_creationDate ??= _constructCreationDate();
|
GeneratedBoolColumn _constructDone() {
|
||||||
GeneratedDateTimeColumn _constructCreationDate() {
|
return GeneratedBoolColumn('done', $tableName, false,
|
||||||
return GeneratedDateTimeColumn('creation_date', $tableName, false,
|
defaultValue: const Constant(true));
|
||||||
defaultValue: currentDateAndTime);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<GeneratedColumn> get $columns => [id, content, creationDate];
|
List<GeneratedColumn> get $columns => [id, content, done];
|
||||||
@override
|
@override
|
||||||
$TodoEntriesTable get asDslTable => this;
|
$TodoEntriesTable get asDslTable => this;
|
||||||
@override
|
@override
|
||||||
|
@ -156,13 +149,11 @@ class $TodoEntriesTable extends TodoEntries
|
||||||
} else if (content.isRequired && isInserting) {
|
} else if (content.isRequired && isInserting) {
|
||||||
context.missing(_contentMeta);
|
context.missing(_contentMeta);
|
||||||
}
|
}
|
||||||
if (d.creationDate.present) {
|
if (d.done.present) {
|
||||||
context.handle(
|
context.handle(
|
||||||
_creationDateMeta,
|
_doneMeta, done.isAcceptableValue(d.done.value, _doneMeta));
|
||||||
creationDate.isAcceptableValue(
|
} else if (done.isRequired && isInserting) {
|
||||||
d.creationDate.value, _creationDateMeta));
|
context.missing(_doneMeta);
|
||||||
} else if (creationDate.isRequired && isInserting) {
|
|
||||||
context.missing(_creationDateMeta);
|
|
||||||
}
|
}
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
@ -170,9 +161,9 @@ class $TodoEntriesTable extends TodoEntries
|
||||||
@override
|
@override
|
||||||
Set<GeneratedColumn> get $primaryKey => {id};
|
Set<GeneratedColumn> get $primaryKey => {id};
|
||||||
@override
|
@override
|
||||||
TodoEntry map(Map<String, dynamic> data, {String tablePrefix}) {
|
Entry map(Map<String, dynamic> data, {String tablePrefix}) {
|
||||||
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : null;
|
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : null;
|
||||||
return TodoEntry.fromData(data, _db, prefix: effectivePrefix);
|
return Entry.fromData(data, _db, prefix: effectivePrefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -184,9 +175,8 @@ class $TodoEntriesTable extends TodoEntries
|
||||||
if (d.content.present) {
|
if (d.content.present) {
|
||||||
map['content'] = Variable<String, StringType>(d.content.value);
|
map['content'] = Variable<String, StringType>(d.content.value);
|
||||||
}
|
}
|
||||||
if (d.creationDate.present) {
|
if (d.done.present) {
|
||||||
map['creation_date'] =
|
map['done'] = Variable<bool, BoolType>(d.done.value);
|
||||||
Variable<DateTime, DateTimeType>(d.creationDate.value);
|
|
||||||
}
|
}
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
@ -197,10 +187,38 @@ class $TodoEntriesTable extends TodoEntries
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class HiddenEntryCountResult {
|
||||||
|
final int entries;
|
||||||
|
HiddenEntryCountResult({
|
||||||
|
this.entries,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
abstract class _$Database extends GeneratedDatabase {
|
abstract class _$Database extends GeneratedDatabase {
|
||||||
_$Database(QueryExecutor e) : super(const SqlTypeSystem.withDefaults(), e);
|
_$Database(QueryExecutor e) : super(const SqlTypeSystem.withDefaults(), e);
|
||||||
$TodoEntriesTable _todoEntries;
|
$TodoEntriesTable _todoEntries;
|
||||||
$TodoEntriesTable get todoEntries => _todoEntries ??= $TodoEntriesTable(this);
|
$TodoEntriesTable get todoEntries => _todoEntries ??= $TodoEntriesTable(this);
|
||||||
|
HiddenEntryCountResult _rowToHiddenEntryCountResult(QueryRow row) {
|
||||||
|
return HiddenEntryCountResult(
|
||||||
|
entries: row.readInt('entries'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<HiddenEntryCountResult>> hiddenEntryCount(
|
||||||
|
{QueryEngine operateOn}) {
|
||||||
|
return (operateOn ?? this).customSelect(
|
||||||
|
'SELECT COUNT(*) - 20 AS entries FROM todo_entries WHERE done',
|
||||||
|
variables: []).then((rows) => rows.map(_rowToHiddenEntryCountResult).toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream<List<HiddenEntryCountResult>> watchHiddenEntryCount() {
|
||||||
|
return customSelectStream(
|
||||||
|
'SELECT COUNT(*) - 20 AS entries FROM todo_entries WHERE done',
|
||||||
|
variables: [],
|
||||||
|
readsFrom: {todoEntries})
|
||||||
|
.map((rows) => rows.map(_rowToHiddenEntryCountResult).toList());
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<TableInfo> get allTables => [todoEntries];
|
List<TableInfo> get allTables => [todoEntries];
|
||||||
}
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
import 'package:example_web/widgets/home_screen.dart';
|
||||||
|
import 'package:flutter_web/material.dart';
|
||||||
|
|
||||||
|
import 'database/database.dart';
|
||||||
|
|
||||||
|
void launchApp() {
|
||||||
|
runApp(
|
||||||
|
DatabaseProvider(
|
||||||
|
db: Database(),
|
||||||
|
child: MaterialApp(
|
||||||
|
title: 'Moor web!',
|
||||||
|
home: HomeScreen(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class DatabaseProvider extends InheritedWidget {
|
||||||
|
final Database db;
|
||||||
|
|
||||||
|
DatabaseProvider({@required this.db, @required Widget child})
|
||||||
|
: super(child: child);
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool updateShouldNotify(InheritedWidget oldWidget) => false;
|
||||||
|
|
||||||
|
static Database provide(BuildContext ctx) {
|
||||||
|
return (ctx.inheritFromWidgetOfExactType(DatabaseProvider)
|
||||||
|
as DatabaseProvider)
|
||||||
|
?.db;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
import 'package:flutter_web/material.dart';
|
||||||
|
|
||||||
|
import '../main.dart';
|
||||||
|
|
||||||
|
class CreateEntryBar extends StatefulWidget {
|
||||||
|
@override
|
||||||
|
_CreateEntryBarState createState() => _CreateEntryBarState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CreateEntryBarState extends State<CreateEntryBar> {
|
||||||
|
final TextEditingController _controller = TextEditingController();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_controller.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: TextField(
|
||||||
|
controller: _controller,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
border: OutlineInputBorder(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
IconButton(
|
||||||
|
icon: Icon(Icons.add),
|
||||||
|
onPressed: () {
|
||||||
|
final text = _controller.text;
|
||||||
|
_controller.clear();
|
||||||
|
|
||||||
|
DatabaseProvider.provide(context).createTodoEntry(text);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
import 'package:example_web/database/database.dart';
|
||||||
|
import 'package:flutter_web/material.dart';
|
||||||
|
|
||||||
|
import '../main.dart';
|
||||||
|
|
||||||
|
class SliverEntryList extends StatelessWidget {
|
||||||
|
final Stream<List<Entry>> entries;
|
||||||
|
|
||||||
|
const SliverEntryList({Key key, this.entries}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return StreamBuilder<List<Entry>>(
|
||||||
|
stream: entries,
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
final entries = snapshot.data ?? const [];
|
||||||
|
|
||||||
|
return SliverList(
|
||||||
|
delegate: SliverChildBuilderDelegate(
|
||||||
|
(context, index) {
|
||||||
|
final entry = entries[index];
|
||||||
|
|
||||||
|
return _EntryCard(
|
||||||
|
key: ObjectKey(entry.id),
|
||||||
|
entry: entry,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
childCount: entries.length,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _EntryCard extends StatelessWidget {
|
||||||
|
final Entry entry;
|
||||||
|
|
||||||
|
const _EntryCard({Key key, this.entry}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Card(
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
Text(entry.content),
|
||||||
|
Spacer(),
|
||||||
|
Checkbox(
|
||||||
|
value: entry.done,
|
||||||
|
onChanged: (checked) {
|
||||||
|
DatabaseProvider.provide(context).setCompleted(entry, checked);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
import 'package:example_web/main.dart';
|
||||||
|
import 'package:example_web/widgets/entry_list.dart';
|
||||||
|
import 'package:flutter_web/material.dart';
|
||||||
|
|
||||||
|
import 'create_entry_bar.dart';
|
||||||
|
|
||||||
|
class HomeScreen extends StatelessWidget {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final db = DatabaseProvider.provide(context);
|
||||||
|
final headerTheme = Theme.of(context).textTheme.title;
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: const Text('Moor Web'),
|
||||||
|
),
|
||||||
|
body: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 16.0),
|
||||||
|
child: Center(
|
||||||
|
child: ConstrainedBox(
|
||||||
|
constraints: const BoxConstraints(maxWidth: 800),
|
||||||
|
child: CustomScrollView(
|
||||||
|
slivers: <Widget>[
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: CreateEntryBar(),
|
||||||
|
),
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: Text('In progress', style: headerTheme),
|
||||||
|
),
|
||||||
|
SliverEntryList(
|
||||||
|
entries: db.incompleteEntries(),
|
||||||
|
),
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: Text('Complete', style: headerTheme),
|
||||||
|
),
|
||||||
|
SliverEntryList(
|
||||||
|
entries: db.newestDoneEntries(),
|
||||||
|
),
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: StreamBuilder<List<int>>(
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
final hiddenCount = snapshot?.data?.single ?? 0;
|
||||||
|
|
||||||
|
return Text('Not showing $hiddenCount older entries');
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,6 +6,7 @@ environment:
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
moor: ^1.4.0
|
moor: ^1.4.0
|
||||||
|
flutter_web: any
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
moor_generator:
|
moor_generator:
|
||||||
|
@ -17,3 +18,12 @@ dependency_overrides:
|
||||||
path: ../
|
path: ../
|
||||||
moor_generator:
|
moor_generator:
|
||||||
path: ../../moor_generator
|
path: ../../moor_generator
|
||||||
|
|
||||||
|
flutter_web_ui:
|
||||||
|
git:
|
||||||
|
url: https://github.com/flutter/flutter_web.git
|
||||||
|
path: packages/flutter_web_ui
|
||||||
|
flutter_web:
|
||||||
|
git:
|
||||||
|
url: https://github.com/flutter/flutter_web.git
|
||||||
|
path: packages/flutter_web
|
|
@ -0,0 +1,10 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"family": "MaterialIcons",
|
||||||
|
"fonts": [
|
||||||
|
{
|
||||||
|
"asset": "https://fonts.gstatic.com/s/materialicons/v42/flUhRq6tzZclQEJ-Vdg-IuiaDsNcIhQ8tQ.woff2"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
|
@ -1,28 +0,0 @@
|
||||||
import 'package:moor/moor.dart';
|
|
||||||
|
|
||||||
part 'database.g.dart';
|
|
||||||
|
|
||||||
@DataClassName('TodoEntry')
|
|
||||||
class TodoEntries extends Table {
|
|
||||||
IntColumn get id => integer().autoIncrement()();
|
|
||||||
|
|
||||||
TextColumn get content => text()();
|
|
||||||
DateTimeColumn get creationDate =>
|
|
||||||
dateTime().withDefault(currentDateAndTime)();
|
|
||||||
}
|
|
||||||
|
|
||||||
@UseMoor(tables: [TodoEntries])
|
|
||||||
class Database extends _$Database {
|
|
||||||
Database(QueryExecutor e) : super(e);
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get schemaVersion => 1;
|
|
||||||
|
|
||||||
Stream<List<TodoEntry>> watchEntries() {
|
|
||||||
return select(todoEntries).watch();
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<int> insert(String text) {
|
|
||||||
return into(todoEntries).insert(TodoEntriesCompanion(content: Value(text)));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,27 +1,11 @@
|
||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
<html>
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="UTF-8">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<title></title>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<script defer src="main.dart.js" type="application/javascript"></script>
|
||||||
<meta name="scaffolded-by" content="https://github.com/google/stagehand">
|
|
||||||
<title>example_web</title>
|
|
||||||
<link rel="stylesheet" href="styles.css">
|
|
||||||
<link rel="icon" href="favicon.ico">
|
|
||||||
|
|
||||||
<script defer src="main.dart.js"></script>
|
|
||||||
<script src="sql-wasm.js"></script>
|
<script src="sql-wasm.js"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<div id="output"></div>
|
|
||||||
|
|
||||||
<form id="add_todo_form">
|
|
||||||
<input type="text" id="description" />
|
|
||||||
<input type="submit">
|
|
||||||
</form>
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
|
@ -1,18 +1,7 @@
|
||||||
import 'dart:html';
|
import 'package:example_web/main.dart';
|
||||||
|
import 'package:flutter_web_ui/ui.dart' as ui;
|
||||||
import 'package:moor/moor_web.dart';
|
|
||||||
|
|
||||||
import 'database.dart';
|
|
||||||
|
|
||||||
void main() async {
|
void main() async {
|
||||||
final db = Database(WebDatabase('database', logStatements: true));
|
await ui.webOnlyInitializePlatform();
|
||||||
db.watchEntries().listen(print);
|
launchApp();
|
||||||
|
|
||||||
(querySelector('#add_todo_form') as FormElement).onSubmit.listen((e) {
|
|
||||||
final content = querySelector('#description') as InputElement;
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
db.insert(content.value).then((insertId) => print('inserted #$insertId'));
|
|
||||||
content.value = '';
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
@import url(https://fonts.googleapis.com/css?family=Roboto);
|
|
||||||
|
|
||||||
html, body {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
font-family: 'Roboto', sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
#output {
|
|
||||||
padding: 20px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
|
@ -223,6 +223,11 @@ class WebDatabase extends _DatabaseUser {
|
||||||
return databaseInfo.beforeOpenCallback(_BeforeOpenExecutor(_state),
|
return databaseInfo.beforeOpenCallback(_BeforeOpenExecutor(_state),
|
||||||
OpeningDetails(version, databaseInfo.schemaVersion));
|
OpeningDetails(version, databaseInfo.schemaVersion));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (upgradeNeeded) {
|
||||||
|
// assume that a schema version was written in an upgrade => save db
|
||||||
|
_storeDb();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue