Remove fluttercommunity mentions for now, parse PK

This commit is contained in:
Simon Binder 2019-03-06 20:26:04 +01:00
parent 0de6005ad7
commit 83f12a71b6
No known key found for this signature in database
GPG Key ID: B807FDF954BA00CF
10 changed files with 103 additions and 32 deletions

View File

@ -1,13 +0,0 @@
# This pubspec file exists so that this repository can show up in the generated list of community
# repositories. It's not meant to serve as an actual pub file.
name: sally
description: Sally is a safe and reactive persistence library for Dart applications
homepage: https://github.com/simolus3/sally
authors:
- Flutter Community <community@flutter.zone>
- Simon Binder <simolus3@gmail.com>
maintainer: Simon Binder (@simolus3)
environment:
sdk: '>=2.0.0 <3.0.0'

View File

@ -0,0 +1,37 @@
import 'package:sally/sally.dart';
// Define tables that can model a database of recipes.
@DataClassName('Category')
class Categories extends Table {
IntColumn get id => integer().autoIncrement()();
TextColumn get description => text().nullable()();
}
class Recipes extends Table {
IntColumn get id => integer().autoIncrement()();
TextColumn get title => text().withLength(max: 16)();
TextColumn get instructions => text()();
IntColumn get category => integer().nullable()();
}
class Ingredients extends Table {
IntColumn get id => integer().autoIncrement()();
TextColumn get name => text()();
IntColumn get caloriesPer100g => integer().named('calories')();
}
class IngredientInRecipes extends Table {
@override
String get tableName => 'recipe_ingredients';
// We can also specify custom primary keys
@override
Set<Column> get primaryKey => {recipe, ingredient};
IntColumn get recipe => integer().autoIncrement()();
IntColumn get ingredient => integer().autoIncrement()();
IntColumn get amountInGrams => integer().named('amount')();
}

View File

@ -40,8 +40,8 @@ class ColumnBuilder<Builder, ResultColumn> {
/// `IntColumn get id = integer((c) => c.named('user_id'))`.
Builder named(String name) => null;
/// Marks this column as being part of a primary key. This is not yet
/// supported by sally.
@Deprecated('Ignored by the generator. Please override primaryKey in your '
'table class instead')
Builder primaryKey() => null;
/// Marks this column as nullable. Nullable columns should not appear in a

View File

@ -20,8 +20,7 @@ abstract class Table {
/// In the future, you can override this to specify a custom primary key. This
/// is not supported by sally at the moment.
@visibleForOverriding
// todo allow custom primary key
PrimaryKey get primaryKey => null;
Set<Column> get primaryKey => null;
/// Use this as the body of a getter to declare a column that holds integers.
/// Example (inside the body of a table class):
@ -57,8 +56,6 @@ abstract class Table {
DateTimeColumnBuilder dateTime() => null;
}
class PrimaryKey {}
/// A class to to be used as an annotation on [Table] classes to customize the
/// name for the data class that will be generated for the table class. The data
/// class is a dart object that will be used to represent a row in the table.

View File

@ -3,7 +3,6 @@ description: Sally is a safe and reactive persistence library for Dart applicati
version: 1.0.0
homepage: https://github.com/simolus3/sally
authors:
- Flutter Community <community@flutter.zone>
- Simon Binder <simolus3@gmail.com>
maintainer: Simon Binder (@simolus3)

View File

@ -2,7 +2,6 @@ name: sally_flutter
description: Flutter implementation of sally, a safe and reactive persistence library for Dart applications
version: 1.0.0
authors:
- Flutter Community <community@flutter.zone>
- Simon Binder <simolus3@gmail.com>
maintainer: Simon Binder (@simolus3)

View File

@ -11,11 +11,13 @@ class SpecifiedTable {
String get tableInfoName => tableInfoNameForTableClass(fromClass);
// todo support primary keys
Set<SpecifiedColumn> get primaryKey => <SpecifiedColumn>{};
/// The set of primary keys, if they have been explicitly defined by
/// overriding `primaryKey` in the table class. `null` if the primary key has
/// not been defined that way.
final Set<SpecifiedColumn> primaryKey;
const SpecifiedTable(
{this.fromClass, this.columns, this.sqlName, this.dartTypeName});
{this.fromClass, this.columns, this.sqlName, this.dartTypeName, this.primaryKey});
}
String tableInfoNameForTableClass(ClassElement fromClass) =>

View File

@ -17,11 +17,15 @@ class TableParser extends ParserBase {
final sqlName = _parseTableName(element);
if (sqlName == null) return null;
final columns = _parseColumns(element);
return SpecifiedTable(
fromClass: element,
columns: _parseColumns(element),
sqlName: escapeIfNeeded(sqlName),
dartTypeName: _readDartTypeName(element));
fromClass: element,
columns: columns,
sqlName: escapeIfNeeded(sqlName),
dartTypeName: _readDartTypeName(element),
primaryKey: _readPrimaryKey(element, columns),
);
}
String _readDartTypeName(ClassElement element) {
@ -64,6 +68,39 @@ class TableParser extends ParserBase {
return tableName;
}
Set<SpecifiedColumn> _readPrimaryKey(ClassElement element, List<SpecifiedColumn> columns) {
final primaryKeyGetter = element.getGetter('primaryKey');
if (primaryKeyGetter == null) {
return null;
}
final ast = generator.loadElementDeclaration(primaryKeyGetter).node as MethodDeclaration;
final body = ast.body;
if (body is! ExpressionFunctionBody) {
generator.errors.add(SallyError(affectedElement: primaryKeyGetter, message: 'This must return a set literal using the => syntax!'));
return null;
}
final expression = (body as ExpressionFunctionBody).expression;
// set expressions {x, y} are parsed as map literals whose values are an empty
// identifier {x: , y: }. yeah.
// todo should we support MapLiteral2 to support the experiments discussed there?
if (expression is! MapLiteral) {
generator.errors.add(SallyError(affectedElement: primaryKeyGetter, message: 'This must return a set literal!'));
return null;
}
final mapLiteral = expression as MapLiteral;
final parsedPrimaryKey = <SpecifiedColumn>{};
for (var entry in mapLiteral.entries) {
final key = entry.key as Identifier;
final column = columns.singleWhere((column) => column.dartGetterName == key.name);
parsedPrimaryKey.add(column);
}
return parsedPrimaryKey;
}
Iterable<MethodDeclaration> _findColumnGetters(ClassElement element) {
return element.fields
.where((field) => isColumn(field.type) && field.getter != null)

View File

@ -1,9 +1,8 @@
name: sally_generator
description: Sally generator generated database code from your table classes
description: Sally generator generates database code from your table classes
version: 1.0.0
homepage: https://github.com/simolus3/sally
authors:
- Flutter Community <community@flutter.zone>
- Simon Binder <simolus3@gmail.com>
maintainer: Simon Binder (@simolus3)

View File

@ -27,6 +27,14 @@ void main() async {
TextColumn get onlyMax => text().withLength(max: 100)();
}
class CustomPrimaryKey extends Table {
IntColumn get partA => integer()();
IntColumn get partB => integer()();
@override
Set<Column> get primaryKey => {partA, partB};
}
class WrongName extends Table {
String constructTableName() {
@ -34,7 +42,7 @@ void main() async {
}
@override
String get tableName => constructTableName();"
String get tableName => constructTableName();
}
''', (r) => r.findLibraryByName('test_parser'));
});
@ -102,4 +110,10 @@ void main() async {
idColumn.features, contains(LimitingTextLength.withLength(max: 100)));
});
});
test('parses custom primary keys', () {
final table = TableParser(generator).parse(testLib.getType('CustomPrimaryKey'));
expect(table.primaryKey, containsAll(table.columns));
});
}