diff --git a/.idea/libraries/Dart_Packages.xml b/.idea/libraries/Dart_Packages.xml
index 015b7d90..ea5b46d5 100644
--- a/.idea/libraries/Dart_Packages.xml
+++ b/.idea/libraries/Dart_Packages.xml
@@ -5,28 +5,27 @@
-
+
-
+
-
+
-
@@ -34,7 +33,6 @@
-
@@ -42,77 +40,69 @@
-
+
-
-
-
-
-
-
-
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
@@ -120,14 +110,13 @@
-
+
-
@@ -135,35 +124,35 @@
-
+
-
+
-
+
-
+
-
+
@@ -184,98 +173,97 @@
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
@@ -283,7 +271,6 @@
-
@@ -291,7 +278,7 @@
-
+
@@ -305,35 +292,34 @@
-
+
-
+
-
+
-
+
-
@@ -341,42 +327,41 @@
-
+
-
+
-
+
-
+
-
+
-
@@ -384,35 +369,35 @@
-
+
-
+
-
+
-
+
-
+
@@ -426,28 +411,28 @@
-
+
-
+
-
+
-
+
@@ -462,7 +447,6 @@
-
@@ -470,7 +454,6 @@
-
@@ -478,14 +461,13 @@
-
+
-
@@ -500,7 +482,7 @@
-
+
@@ -508,14 +490,13 @@
-
+
-
@@ -523,21 +504,20 @@
-
+
-
+
-
@@ -545,7 +525,7 @@
-
+
@@ -559,127 +539,113 @@
-
+
-
+
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/README.md b/README.md
deleted file mode 100644
index fe310663..00000000
--- a/README.md
+++ /dev/null
@@ -1,127 +0,0 @@
-# Sally
-[](https://travis-ci.com/simolus3/sally)
-
-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.
-
-__Note:__ This library is in development and not yet available for general use on `pub`.
-
-## 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';
-
-// 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 {
-
-}
-```
-
-__⚠️ 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.
-
-#### 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
-
- 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/README.md b/README.md
new file mode 120000
index 00000000..f00e0b69
--- /dev/null
+++ b/README.md
@@ -0,0 +1 @@
+sally/README.md
\ No newline at end of file
diff --git a/example/.flutter-plugins b/example/.flutter-plugins
new file mode 100644
index 00000000..3e4cc2a8
--- /dev/null
+++ b/example/.flutter-plugins
@@ -0,0 +1 @@
+sqflite=/home/simon/Android/flutter/.pub-cache/hosted/pub.dartlang.org/sqflite-1.1.0/
diff --git a/example/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java b/example/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java
new file mode 100644
index 00000000..aff2f141
--- /dev/null
+++ b/example/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java
@@ -0,0 +1,25 @@
+package io.flutter.plugins;
+
+import io.flutter.plugin.common.PluginRegistry;
+import com.tekartik.sqflite.SqflitePlugin;
+
+/**
+ * Generated file. Do not edit.
+ */
+public final class GeneratedPluginRegistrant {
+ public static void registerWith(PluginRegistry registry) {
+ if (alreadyRegisteredWith(registry)) {
+ return;
+ }
+ SqflitePlugin.registerWith(registry.registrarFor("com.tekartik.sqflite.SqflitePlugin"));
+ }
+
+ private static boolean alreadyRegisteredWith(PluginRegistry registry) {
+ final String key = GeneratedPluginRegistrant.class.getCanonicalName();
+ if (registry.hasPlugin(key)) {
+ return true;
+ }
+ registry.registrarFor(key);
+ return false;
+ }
+}
diff --git a/example/ios/Runner/GeneratedPluginRegistrant.h b/example/ios/Runner/GeneratedPluginRegistrant.h
new file mode 100644
index 00000000..3b700eb4
--- /dev/null
+++ b/example/ios/Runner/GeneratedPluginRegistrant.h
@@ -0,0 +1,14 @@
+//
+// Generated file. Do not edit.
+//
+
+#ifndef GeneratedPluginRegistrant_h
+#define GeneratedPluginRegistrant_h
+
+#import
+
+@interface GeneratedPluginRegistrant : NSObject
++ (void)registerWithRegistry:(NSObject*)registry;
+@end
+
+#endif /* GeneratedPluginRegistrant_h */
diff --git a/example/ios/Runner/GeneratedPluginRegistrant.m b/example/ios/Runner/GeneratedPluginRegistrant.m
new file mode 100644
index 00000000..8abd91ed
--- /dev/null
+++ b/example/ios/Runner/GeneratedPluginRegistrant.m
@@ -0,0 +1,14 @@
+//
+// Generated file. Do not edit.
+//
+
+#import "GeneratedPluginRegistrant.h"
+#import
+
+@implementation GeneratedPluginRegistrant
+
++ (void)registerWithRegistry:(NSObject*)registry {
+ [SqflitePlugin registerWithRegistrar:[registry registrarForPlugin:@"SqflitePlugin"]];
+}
+
+@end
diff --git a/example/lib/example.g.dart b/example/lib/example.g.dart
index 49fa8db6..0fb49d05 100644
--- a/example/lib/example.g.dart
+++ b/example/lib/example.g.dart
@@ -10,6 +10,12 @@ class Product {
final int id;
final String name;
Product({this.id, this.name});
+ @override
+ int get hashCode => (id.hashCode) * 31 + name.hashCode;
+ @override
+ bool operator ==(other) =>
+ identical(this, other) ||
+ (other is Product && other.id == id && other.name == name);
}
class _$ProductsTable extends Products implements TableInfo {
@@ -42,6 +48,12 @@ class User {
final int id;
final String name;
User({this.id, this.name});
+ @override
+ int get hashCode => (id.hashCode) * 31 + name.hashCode;
+ @override
+ bool operator ==(other) =>
+ identical(this, other) ||
+ (other is User && other.id == id && other.name == name);
}
class _$UsersTable extends Users implements TableInfo {
@@ -75,6 +87,16 @@ class Todo {
final String name;
final String content;
Todo({this.id, this.name, this.content});
+ @override
+ int get hashCode =>
+ ((id.hashCode) * 31 + name.hashCode) * 31 + content.hashCode;
+ @override
+ bool operator ==(other) =>
+ identical(this, other) ||
+ (other is Todo &&
+ other.id == id &&
+ other.name == name &&
+ other.content == content);
}
class _$TodosTable extends Todos implements TableInfo {
@@ -85,7 +107,7 @@ class _$TodosTable extends Todos implements TableInfo {
@override
GeneratedTextColumn get name => GeneratedTextColumn('name', false);
@override
- GeneratedTextColumn get content => GeneratedTextColumn('content', false);
+ GeneratedTextColumn get content => GeneratedTextColumn('body', false);
@override
List get $columns => [id, name, content];
@override
@@ -101,7 +123,7 @@ class _$TodosTable extends Todos implements TableInfo {
return Todo(
id: intType.mapFromDatabaseResponse(data['id']),
name: stringType.mapFromDatabaseResponse(data['name']),
- content: stringType.mapFromDatabaseResponse(data['content']),
+ content: stringType.mapFromDatabaseResponse(data['body']),
);
}
}
diff --git a/example/pubspec.yaml b/example/pubspec.yaml
index 09b3e646..a650e14c 100644
--- a/example/pubspec.yaml
+++ b/example/pubspec.yaml
@@ -5,7 +5,7 @@ description: A sample command-line application.
# author: simon
environment:
- sdk: '>=2.1.0 <3.0.0'
+ sdk: '>=2.0.0 <3.0.0'
dependencies:
sally:
diff --git a/sally/.gitignore b/sally/.gitignore
index dc13152b..d965bf94 100644
--- a/sally/.gitignore
+++ b/sally/.gitignore
@@ -25,6 +25,9 @@ doc/api/
*.js.deps
*.js.map
+android/
+ios/
+
### Intellij ###
.idea/**/*
# End of https://www.gitignore.io/api/dart,intellij
diff --git a/sally/README.md b/sally/README.md
index 5afc1b21..c22ef754 100644
--- a/sally/README.md
+++ b/sally/README.md
@@ -1,22 +1,126 @@
-A library for Dart developers.
+# Sally
+[](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
+- 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/sally_generator/.flutter-plugins b/sally_generator/.flutter-plugins
new file mode 100644
index 00000000..3e4cc2a8
--- /dev/null
+++ b/sally_generator/.flutter-plugins
@@ -0,0 +1 @@
+sqflite=/home/simon/Android/flutter/.pub-cache/hosted/pub.dartlang.org/sqflite-1.1.0/
diff --git a/sally_generator/.gitignore b/sally_generator/.gitignore
index f95ca619..fac28d89 100644
--- a/sally_generator/.gitignore
+++ b/sally_generator/.gitignore
@@ -25,6 +25,9 @@ doc/api/
*.js.deps
*.js.map
+android/
+ios/
+
### Intellij ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
diff --git a/sally_generator/lib/src/writer/data_class_writer.dart b/sally_generator/lib/src/writer/data_class_writer.dart
new file mode 100644
index 00000000..f5a330b6
--- /dev/null
+++ b/sally_generator/lib/src/writer/data_class_writer.dart
@@ -0,0 +1,67 @@
+import 'package:sally_generator/src/model/specified_table.dart';
+
+class DataClassWriter {
+ final SpecifiedTable table;
+
+ DataClassWriter(this.table);
+
+ void writeInto(StringBuffer buffer) {
+ buffer.write('class ${table.dartTypeName} {\n');
+
+ // write individual fields
+ for (var column in table.columns) {
+ buffer.write('final ${column.dartTypeName} ${column.dartGetterName}; \n');
+ }
+
+ // write constructor with named optional fields
+ buffer
+ ..write(table.dartTypeName)
+ ..write('({')
+ ..write(table.columns
+ .map((column) => 'this.${column.dartGetterName}')
+ .join(', '))
+ ..write('});')
+ ..write('@override\n int get hashCode => ');
+
+ if (table.columns.isEmpty) {
+ buffer.write('identityHashCode(this); \n');
+ } else {
+ final fields = table.columns.map((c) => c.dartGetterName).toList();
+ buffer..write(_calculateHashCode(fields))..write('; \n');
+ }
+
+ // override ==
+ // return identical(this, other) || (other is Todo && other.id == id && other.)
+ buffer
+ ..write('@override\nbool operator ==(other) => ')
+ ..write('identical(this, other) || (other is ${table.dartTypeName}');
+
+ if (table.columns.isNotEmpty) {
+ buffer
+ ..write('&&')
+ ..write(table.columns.map((c) {
+ final getter = c.dartGetterName;
+
+ return 'other.$getter == $getter';
+ }).join(' && '));
+ }
+
+ // finish overrides method and class declaration
+ buffer.write(');\n}');
+ }
+
+ /// Recursively creates the implementation for hashCode of the data class,
+ /// assuming it has at least one field. When it has one field, we just return
+ /// the hash code of that field. Otherwise, we multiply it with 31 and add
+ /// the hash code of the next field, and so on.
+ String _calculateHashCode(List fields) {
+ if (fields.length == 1) {
+ return '${fields.last}.hashCode';
+ } else {
+ final last = fields.removeLast();
+ final innerHash = _calculateHashCode(fields);
+
+ return '($innerHash) * 31 + $last.hashCode';
+ }
+ }
+}
diff --git a/sally_generator/lib/src/writer/table_writer.dart b/sally_generator/lib/src/writer/table_writer.dart
index e8eec86b..e21adc98 100644
--- a/sally_generator/lib/src/writer/table_writer.dart
+++ b/sally_generator/lib/src/writer/table_writer.dart
@@ -1,5 +1,6 @@
import 'package:recase/recase.dart';
import 'package:sally_generator/src/model/specified_table.dart';
+import 'package:sally_generator/src/writer/data_class_writer.dart';
class TableWriter {
final SpecifiedTable table;
@@ -12,22 +13,7 @@ class TableWriter {
}
void writeDataClass(StringBuffer buffer) {
- buffer.write('class ${table.dartTypeName} {\n');
-
- // write individual fields
- for (var column in table.columns) {
- buffer.write('final ${column.dartTypeName} ${column.dartGetterName}; \n');
- }
-
- // write constructor with named optional fields
- buffer
- ..write(table.dartTypeName)
- ..write('({')
- ..write(table.columns
- .map((column) => 'this.${column.dartGetterName}')
- .join(', '))
- ..write('});')
- ..write('\n}');
+ DataClassWriter(table).writeInto(buffer);
}
void writeTableInfoClass(StringBuffer buffer) {
diff --git a/sally_generator/pubspec.yaml b/sally_generator/pubspec.yaml
index ff8ab10c..4f73c53c 100644
--- a/sally_generator/pubspec.yaml
+++ b/sally_generator/pubspec.yaml
@@ -5,7 +5,7 @@ description: A starting point for Dart libraries or applications.
# author: Simon Binder
environment:
- sdk: '>=2.1.0 <3.0.0'
+ sdk: '>=2.0.0 <3.0.0'
dependencies:
analyzer: '< 0.35.0'