From a0b60531724ea08008fcac17c28222c887a4ba49 Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Sat, 9 Feb 2019 22:12:46 +0100 Subject: [PATCH] Add README --- README.md | 125 ++++++++++++++++++++++++--- example/lib/example.dart | 10 ++- example/lib/example.g.dart | 39 ++++++++- sally/lib/src/runtime/sql_types.dart | 3 +- tool/license.sh | 11 +++ 5 files changed, 175 insertions(+), 13 deletions(-) create mode 100755 tool/license.sh diff --git a/README.md b/README.md index 5afc1b21..fe310663 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,127 @@ -A library for Dart developers. +# Sally +[![Build Status](https://travis-ci.com/simolus3/sally.svg?token=u4VnFEE5xnWVvkE6QsqL&branch=master)](https://travis-ci.com/simolus3/sally) -Created from templates made available by Stagehand under a BSD-style -[license](https://github.com/dart-lang/stagehand/blob/master/LICENSE). +Sally is an easy to use and safe way to persist data for Flutter apps. It features +a fluent Dart DSL to describe tables and will generate matching database code that +can be used to easily read and store your app's data. -## Usage +__Note:__ This library is in development and not yet available for general use on `pub`. -A simple usage example: +## Using this library +#### Adding the dependency +First, let's add sally to your prooject's `pubspec.yaml`: +```yaml +dependencies: + sally: + git: + url: + path: sally/ +dev_dependencies: + sally_generator: + git: + url: + path: sally_generator/ + build_runner: +``` +We're going to use the `sally` library to specify tables and write data. The +`sally_generator` library will take care of generating the necessary code so the +library knows how your table structure looks like. + +#### Declaring tables +You can use the DSL included with this library to specify your libraries with simple +dart code: ```dart import 'package:sally/sally.dart'; -main() { - var awesome = new Awesome(); +// assuming that your file is called filename.dart. This will give an error at first, +// but it's needed for sally to know about the generated code +part 'filename.g.dart'; + +class Todos extends Table { + IntColumn get id => integer().autoIncrement()(); + TextColumn get name => text().withLength(min: 6, max: 10)(); + TextColumn get content => text().named('body')(); + IntColumn get category => integer()(); +} + +class Categories extends Table { + @override + String get tableName => 'todo_categories'; + + IntColumn get id => integer().autoIncrement()(); + TextColumn get description => text()(); +} + +@UseSally(tables: [Todos, Categories]) +class MyDatabase { + } ``` -## Features and bugs +__⚠️ Warning:__ Even though it might look like it, the content of a `Table` class does not support full Dart code. It can only +be used to declare the table name, it's primary keys and columns. The code inside of a table class will never be +executed. Instead, the generator will take a look at your table classes to figure out how their structure looks like. +This won't work if the body of your tables is not constant. This should not be problem, but please be aware of this. -Please file feature requests and bugs at the [issue tracker][tracker]. +#### Generating the code +Sally integrates with the dart `build` system, so you can generate all the code needed with +`flutter packages pub run build_runner build`. If you want to continously rebuild the code +whever you change your code, run `flutter packages pub run build_runner watch` instead. +After running either command once, sally generator will have created a class for your +database and data classes for your entities. To use it, change the `MyDatabase` class as +follows: +```dart +@UseSally(tables: [Todos, Categories]) +class MyDatabase extends _$MyDatabase { + @override + int get schemaVersion => 1; + @override + MigrationStrategy get migration => MigrationStrategy(); +} +``` +You can ignore these two getters there at the moment, the imporant part is that you can +now run your queries with fluent Dart code: +```dart +class MyDatabase extends _$MyDatabase { + // .. the getters that have been defined above still need to be here -[tracker]: http://example.com/issues/replaceme + Future> get allTodoEntries => select(todos).get(); + + Future deleteCategory(Category toDelete) async { + await (delete(todos)..where((entry) => entry.category.equalsVal(category.id))).go(); + await (delete(categories)..where((cat) => cat.id.equalsVal(toDelete.id))).go(); + } +} +``` + +## TODO-List +If you have suggestions for new features or any other questions, feel free to +create an issue. + +##### Before this library can be released +- Insert and update statements +- Custom primary keys +- Stabilize all end-user APIs +- Support default values and expressions, auto-increment +- Implement `==` and `hashCode` in data classes +- Allow custom table names for the generated dart types +##### Definitely planned for the future +- Allow using DAOs instead of having to put everything in the main database +class. +- Auto-updating streams +- Support more Datatypes: We should at least support `DateTime` and `Uint8List`, +supporting floating point numbers as well would be awesome +- Nullable / non-nullable datatypes + - DSL API + - Support in generator + - Use in queries (`IS NOT NULL`) +- Verify constraints (text length, nullability, etc.) before inserting or + deleting data. +- Support Dart VM apps +- References +- Table joins +##### Interesting stuff that would be nice to have +- `GROUP BY` grouping functions +- Support for different database engines + - Support webapps via `AlaSQL` or a different engine \ No newline at end of file diff --git a/example/lib/example.dart b/example/lib/example.dart index 195840f0..b9cb0d19 100644 --- a/example/lib/example.dart +++ b/example/lib/example.dart @@ -12,7 +12,15 @@ class Users extends Table { TextColumn get name => text().withLength(min: 6, max: 32)(); } -@UseSally(tables: [Products, Users]) +class Todos extends Table { + + IntColumn get id => integer().autoIncrement()(); + TextColumn get name => text().withLength(min: 6, max: 10)(); + TextColumn get content => text().named('body')(); + +} + +@UseSally(tables: [Products, Users, Todos]) class ShopDb extends _$ShopDb { Future> allUsers() => select(users).get(); Future> userByName(String name) => diff --git a/example/lib/example.g.dart b/example/lib/example.g.dart index 5e11032a..49fa8db6 100644 --- a/example/lib/example.g.dart +++ b/example/lib/example.g.dart @@ -70,10 +70,47 @@ class _$UsersTable extends Users implements TableInfo { } } +class Todo { + final int id; + final String name; + final String content; + Todo({this.id, this.name, this.content}); +} + +class _$TodosTable extends Todos implements TableInfo { + final GeneratedDatabase db; + _$TodosTable(this.db); + @override + GeneratedIntColumn get id => GeneratedIntColumn('id', false); + @override + GeneratedTextColumn get name => GeneratedTextColumn('name', false); + @override + GeneratedTextColumn get content => GeneratedTextColumn('content', false); + @override + List get $columns => [id, name, content]; + @override + Todos get asDslTable => this; + @override + String get $tableName => 'todos'; + @override + Set get $primaryKey => Set(); + @override + Todo map(Map data) { + final intType = db.typeSystem.forDartType(); + final stringType = db.typeSystem.forDartType(); + return Todo( + id: intType.mapFromDatabaseResponse(data['id']), + name: stringType.mapFromDatabaseResponse(data['name']), + content: stringType.mapFromDatabaseResponse(data['content']), + ); + } +} + abstract class _$ShopDb extends GeneratedDatabase { _$ShopDb() : super(const SqlTypeSystem.withDefaults(), null); _$ProductsTable get products => _$ProductsTable(this); _$UsersTable get users => _$UsersTable(this); + _$TodosTable get todos => _$TodosTable(this); @override - List get allTables => [products, users]; + List get allTables => [products, users, todos]; } diff --git a/sally/lib/src/runtime/sql_types.dart b/sally/lib/src/runtime/sql_types.dart index 7f18d65b..d0ccd610 100644 --- a/sally/lib/src/runtime/sql_types.dart +++ b/sally/lib/src/runtime/sql_types.dart @@ -44,7 +44,8 @@ class StringType extends SqlType { @override String mapToSqlConstant(String content) { - // TODO: implement mapToSqlConstant + // TODO: implement mapToSqlConstant, we would probably have to take care + // of sql injection vulnerabilities here return null; } diff --git a/tool/license.sh b/tool/license.sh new file mode 100755 index 00000000..2cae0b20 --- /dev/null +++ b/tool/license.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +rm -f example/LICENSE +rm -f sally/LICENSE +rm -f sally_flutter/LICENSE +rm -f sally_generator/LICENSE + +cp LICENSE example/LICENSE +cp LICENSE sally/LICENSE +cp LICENSE sally_flutter/LICENSE +cp LICENSE sally_generator/LICENSE