diff --git a/.idea/.name b/.idea/.name
new file mode 100644
index 00000000..80e9d968
--- /dev/null
+++ b/.idea/.name
@@ -0,0 +1 @@
+orm
\ No newline at end of file
diff --git a/.idea/dbnavigator.xml b/.idea/dbnavigator.xml
new file mode 100644
index 00000000..11ef66c4
--- /dev/null
+++ b/.idea/dbnavigator.xml
@@ -0,0 +1,451 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/orm.iml b/.idea/orm.iml
index ab4131d2..d4c62765 100644
--- a/.idea/orm.iml
+++ b/.idea/orm.iml
@@ -1,24 +1,14 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
diff --git a/.idea/runConfigurations/postgres__build_dart.xml b/.idea/runConfigurations/postgres__build_dart.xml
index 8fec7c79..406d1d50 100644
--- a/.idea/runConfigurations/postgres__build_dart.xml
+++ b/.idea/runConfigurations/postgres__build_dart.xml
@@ -1,7 +1,7 @@
-
-
+
+
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
index de2210c9..cf34b7d5 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1 +1,7 @@
-language: dart
\ No newline at end of file
+language: dart
+script: bash tool/.travis.sh
+before_script:
+ - psql -c 'create database angel_orm_test;' -U postgres
+ - psql -c "CREATE USER angel_orm WITH PASSWORD 'angel_orm';" -U postgres
+services:
+ - postgresql
\ No newline at end of file
diff --git a/README.md b/README.md
index 8f176569..197966f9 100644
--- a/README.md
+++ b/README.md
@@ -2,15 +2,31 @@
[![Pub](https://img.shields.io/pub/v/angel_orm.svg)](https://pub.dartlang.org/packages/angel_orm)
[![build status](https://travis-ci.org/angel-dart/orm.svg)](https://travis-ci.org/angel-dart/orm)
-**This project is currently in the early stages, and may change at any given
-time without warning.**
-
Source-generated PostgreSQL ORM for use with the
[Angel framework](https://angel-dart.github.io).
Now you can combine the power and flexibility of Angel with a strongly-typed ORM.
-Currently supported:
-* PostgreSQL
+* [Usage](#usage)
+* [Model Definitions](#models)
+* [MVC Example](#example)
+* [Relationships](#relations)
+
+# Usage
+You'll need these dependencies in your `pubspec.yaml`:
+```yaml
+dependencies:
+ angel_orm: ^1.0.0-alpha
+dev_dependencies:
+ angel_orm_generator: ^1.0.0-alpha
+ build_runner: ^0.3.0
+```
+
+`package:angel_orm_generator` exports two classes that you can include
+in a `package:build` flow:
+* `PostgreORMGenerator` - Fueled by `package:source_gen`; include this within a `GeneratorBuilder`.
+* `SQLMigrationGenerator` - This is its own `Builder`; it generates a SQL schema, as well as a SQL script to drop a generated table.
+
+You should pass an `InputSet` containing your project's models.
# Models
Your model, courtesy of `package:angel_serialize`:
@@ -38,6 +54,13 @@ Models can use the `@Alias()` annotation; `package:angel_orm` obeys it.
After building, you'll have access to a `Query` class with strongly-typed methods that
allow to run asynchronous queries without a headache.
+**IMPORTANT:** The ORM *assumes* that you are using `package:angel_serialize`, and will only generate code
+designed for such a workflow. Save yourself a headache and build models with `angel_serialize`:
+
+https://github.com/angel-dart/serialize
+
+# Example
+
MVC just got a whole lot easier:
```dart
@@ -91,7 +114,7 @@ class CarService extends Controller {
```
# Relations
-**NOTE**: This is not yet implemented.
+**NOTE**: This is not yet implemented. Expect to see more documentation about this soon.
* `@HasOne()`
* `@HasMany()`
diff --git a/.analysis-options b/angel_orm/.analysis-options
similarity index 100%
rename from .analysis-options
rename to angel_orm/.analysis-options
diff --git a/angel_orm/.gitignore b/angel_orm/.gitignore
new file mode 100644
index 00000000..99e7978e
--- /dev/null
+++ b/angel_orm/.gitignore
@@ -0,0 +1,56 @@
+# See https://www.dartlang.org/tools/private-files.html
+
+# Files and directories created by pub
+.packages
+.pub/
+build/
+# If you're building an application, you may want to check-in your pubspec.lock
+pubspec.lock
+
+# Directory created by dartdoc
+# If you don't generate documentation locally you can remove this line.
+doc/api/
+### JetBrains template
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
+# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
+
+# User-specific stuff:
+.idea/**/workspace.xml
+.idea/**/tasks.xml
+.idea/dictionaries
+
+# Sensitive or high-churn files:
+.idea/**/dataSources/
+.idea/**/dataSources.ids
+.idea/**/dataSources.xml
+.idea/**/dataSources.local.xml
+.idea/**/sqlDataSources.xml
+.idea/**/dynamic.xml
+.idea/**/uiDesigner.xml
+
+# Gradle:
+.idea/**/gradle.xml
+.idea/**/libraries
+
+# Mongo Explorer plugin:
+.idea/**/mongoSettings.xml
+
+## File-based project format:
+*.iws
+
+## Plugin-specific files:
+
+# IntelliJ
+/out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+fabric.properties
diff --git a/LICENSE b/angel_orm/LICENSE
similarity index 100%
rename from LICENSE
rename to angel_orm/LICENSE
diff --git a/angel_orm/README.md b/angel_orm/README.md
new file mode 100644
index 00000000..5546e559
--- /dev/null
+++ b/angel_orm/README.md
@@ -0,0 +1,7 @@
+# angel_orm
+Runtime support for Angel's ORM. Includes SQL expression generators, as well
+as a friendly `PostgreSQLConnectionPool` class that you can use to pool connections
+to a PostgreSQL database.
+
+For documentation about the ORM, head to the main project repo:
+https://github.com/angel-dart/orm
\ No newline at end of file
diff --git a/lib/angel_orm.dart b/angel_orm/lib/angel_orm.dart
similarity index 100%
rename from lib/angel_orm.dart
rename to angel_orm/lib/angel_orm.dart
diff --git a/lib/src/annotations.dart b/angel_orm/lib/src/annotations.dart
similarity index 100%
rename from lib/src/annotations.dart
rename to angel_orm/lib/src/annotations.dart
diff --git a/lib/src/migration.dart b/angel_orm/lib/src/migration.dart
similarity index 100%
rename from lib/src/migration.dart
rename to angel_orm/lib/src/migration.dart
diff --git a/lib/src/pool.dart b/angel_orm/lib/src/pool.dart
similarity index 100%
rename from lib/src/pool.dart
rename to angel_orm/lib/src/pool.dart
diff --git a/lib/src/query.dart b/angel_orm/lib/src/query.dart
similarity index 100%
rename from lib/src/query.dart
rename to angel_orm/lib/src/query.dart
diff --git a/lib/src/relations.dart b/angel_orm/lib/src/relations.dart
similarity index 100%
rename from lib/src/relations.dart
rename to angel_orm/lib/src/relations.dart
diff --git a/angel_orm/pubspec.yaml b/angel_orm/pubspec.yaml
new file mode 100644
index 00000000..f1453319
--- /dev/null
+++ b/angel_orm/pubspec.yaml
@@ -0,0 +1,11 @@
+name: angel_orm
+version: 1.0.0-alpha
+description: Runtime support for Angel's ORM.
+author: Tobe O
+homepage: https://github.com/angel-dart/orm
+environment:
+ sdk: ">=1.19.0"
+dependencies:
+ intl: ^0.15.1
+ pool: ^1.0.0
+ postgres: ^0.9.5
\ No newline at end of file
diff --git a/angel_orm_generator/.analysis-options b/angel_orm_generator/.analysis-options
new file mode 100644
index 00000000..518eb901
--- /dev/null
+++ b/angel_orm_generator/.analysis-options
@@ -0,0 +1,2 @@
+analyzer:
+ strong-mode: true
\ No newline at end of file
diff --git a/angel_orm_generator/.gitignore b/angel_orm_generator/.gitignore
new file mode 100644
index 00000000..99e7978e
--- /dev/null
+++ b/angel_orm_generator/.gitignore
@@ -0,0 +1,56 @@
+# See https://www.dartlang.org/tools/private-files.html
+
+# Files and directories created by pub
+.packages
+.pub/
+build/
+# If you're building an application, you may want to check-in your pubspec.lock
+pubspec.lock
+
+# Directory created by dartdoc
+# If you don't generate documentation locally you can remove this line.
+doc/api/
+### JetBrains template
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
+# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
+
+# User-specific stuff:
+.idea/**/workspace.xml
+.idea/**/tasks.xml
+.idea/dictionaries
+
+# Sensitive or high-churn files:
+.idea/**/dataSources/
+.idea/**/dataSources.ids
+.idea/**/dataSources.xml
+.idea/**/dataSources.local.xml
+.idea/**/sqlDataSources.xml
+.idea/**/dynamic.xml
+.idea/**/uiDesigner.xml
+
+# Gradle:
+.idea/**/gradle.xml
+.idea/**/libraries
+
+# Mongo Explorer plugin:
+.idea/**/mongoSettings.xml
+
+## File-based project format:
+*.iws
+
+## Plugin-specific files:
+
+# IntelliJ
+/out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+fabric.properties
diff --git a/angel_orm_generator/LICENSE b/angel_orm_generator/LICENSE
new file mode 100644
index 00000000..89074fd3
--- /dev/null
+++ b/angel_orm_generator/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2017 The Angel Framework
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/angel_orm_generator/README.md b/angel_orm_generator/README.md
new file mode 100644
index 00000000..9ba833f7
--- /dev/null
+++ b/angel_orm_generator/README.md
@@ -0,0 +1,8 @@
+# angel_orm_generator
+Source code generators for Angel's ORM.
+This package can generate:
+* A strongly-typed ORM
+* SQL migration scripts
+
+For documentation about the ORM, head to the main project repo:
+https://github.com/angel-dart/orm
\ No newline at end of file
diff --git a/lib/builder.dart b/angel_orm_generator/lib/angel_orm_generator.dart
similarity index 100%
rename from lib/builder.dart
rename to angel_orm_generator/lib/angel_orm_generator.dart
diff --git a/lib/src/builder/postgres/build_context.dart b/angel_orm_generator/lib/src/builder/postgres/build_context.dart
similarity index 90%
rename from lib/src/builder/postgres/build_context.dart
rename to angel_orm_generator/lib/src/builder/postgres/build_context.dart
index c67377a1..9efe8a12 100644
--- a/lib/src/builder/postgres/build_context.dart
+++ b/angel_orm_generator/lib/src/builder/postgres/build_context.dart
@@ -1,18 +1,14 @@
import 'package:analyzer/dart/element/element.dart';
-import 'package:angel_serialize/build_context.dart' as serialize;
-import 'package:angel_serialize/context.dart' as serialize;
+import 'package:angel_orm/angel_orm.dart';
+import 'package:angel_serialize_generator/src/find_annotation.dart';
+import 'package:angel_serialize_generator/build_context.dart' as serialize;
+import 'package:angel_serialize_generator/context.dart' as serialize;
import 'package:build/build.dart';
import 'package:inflection/inflection.dart';
import 'package:recase/recase.dart';
-import '../../annotations.dart';
-import '../../migration.dart';
-import '../../relations.dart';
-import 'package:angel_serialize/src/find_annotation.dart';
-import 'package:source_gen/src/annotation.dart';
import 'package:source_gen/source_gen.dart';
import 'postgres_build_context.dart';
-// TODO: Should add id, createdAt, updatedAt...
PostgresBuildContext buildContext(
ClassElement clazz,
ORM annotation,
diff --git a/lib/src/builder/postgres/migration.dart b/angel_orm_generator/lib/src/builder/postgres/migration.dart
similarity index 87%
rename from lib/src/builder/postgres/migration.dart
rename to angel_orm_generator/lib/src/builder/postgres/migration.dart
index 6f3d9644..b6461361 100644
--- a/lib/src/builder/postgres/migration.dart
+++ b/angel_orm_generator/lib/src/builder/postgres/migration.dart
@@ -1,19 +1,9 @@
import 'dart:async';
import 'package:analyzer/dart/element/element.dart';
-import 'package:angel_serialize/angel_serialize.dart';
+import 'package:angel_orm/angel_orm.dart';
import 'package:build/build.dart';
-import 'package:code_builder/dart/async.dart';
-import 'package:code_builder/dart/core.dart';
-import 'package:code_builder/code_builder.dart';
-import 'package:inflection/inflection.dart';
-import 'package:path/path.dart' as p;
-import 'package:recase/recase.dart';
import 'package:source_gen/src/annotation.dart';
import 'package:source_gen/src/utils.dart';
-import 'package:source_gen/source_gen.dart';
-import '../../annotations.dart';
-import '../../migration.dart';
-import 'package:angel_serialize/src/find_annotation.dart';
import 'build_context.dart';
import 'postgres_build_context.dart';
diff --git a/lib/src/builder/postgres/postgres.dart b/angel_orm_generator/lib/src/builder/postgres/postgres.dart
similarity index 82%
rename from lib/src/builder/postgres/postgres.dart
rename to angel_orm_generator/lib/src/builder/postgres/postgres.dart
index da0202ba..56b035a2 100644
--- a/lib/src/builder/postgres/postgres.dart
+++ b/angel_orm_generator/lib/src/builder/postgres/postgres.dart
@@ -1,19 +1,14 @@
import 'dart:async';
import 'package:analyzer/dart/element/element.dart';
-import 'package:angel_serialize/angel_serialize.dart';
+import 'package:angel_orm/angel_orm.dart';
import 'package:build/build.dart';
-import 'package:code_builder/dart/async.dart';
import 'package:code_builder/dart/core.dart';
import 'package:code_builder/code_builder.dart';
-import 'package:inflection/inflection.dart';
import 'package:path/path.dart' as p;
import 'package:recase/recase.dart';
import 'package:source_gen/src/annotation.dart';
import 'package:source_gen/src/utils.dart';
import 'package:source_gen/source_gen.dart';
-import '../../annotations.dart';
-import '../../migration.dart';
-import 'package:angel_serialize/src/find_annotation.dart';
import 'build_context.dart';
import 'postgres_build_context.dart';
@@ -154,6 +149,12 @@ class PostgresORMGenerator extends GeneratorForAnnotation {
// Add insert()...
clazz.addMethod(buildInsertMethod(ctx), asStatic: true);
+ // Add insertX()
+ clazz.addMethod(buildInsertModelMethod(ctx), asStatic: true);
+
+ // Add updateX()
+ clazz.addMethod(buildUpdateModelMethod(ctx), asStatic: true);
+
// Add getAll() => new TodoQuery().get();
clazz.addMethod(
new MethodBuilder('getAll',
@@ -315,7 +316,7 @@ class PostgresORMGenerator extends GeneratorForAnnotation {
}
void _addReturning(StringBuffer buf, PostgresBuildContext ctx) {
- buf.write(' RETURNING (');
+ buf.write(' RETURNING ');
int i = 0;
ctx.fields.forEach((field) {
if (i++ > 0) buf.write(', ');
@@ -323,7 +324,7 @@ class PostgresORMGenerator extends GeneratorForAnnotation {
buf.write('"$name"');
});
- buf.write(');');
+ buf.write(';');
}
void _ensureDates(MethodBuilder meth, PostgresBuildContext ctx) {
@@ -424,6 +425,44 @@ class PostgresORMGenerator extends GeneratorForAnnotation {
genericTypes: [new TypeBuilder(ctx.modelClassName)]));
meth.addPositional(
parameter('connection', [new TypeBuilder('PostgreSQLConnection')]));
+ var buf = reference('buf'), whereClause = reference('whereClause');
+
+ meth.addStatement(varField('buf',
+ value: lib$core.StringBuffer
+ .newInstance([literal('DELETE FROM "${ctx.tableName}"')])));
+ meth.addStatement(varField('whereClause',
+ value: reference('where').invoke('toWhereClause', [])));
+
+ var ifStmt = ifThen(whereClause.notEquals(literal(null)), [
+ buf.invoke('write', [literal(' ') + whereClause])
+ ]);
+ meth.addStatement(ifStmt);
+
+ for (var relation in RELATIONS) {
+ var ref = reference('_$relation');
+ var upper = relation.toUpperCase();
+ ifStmt.addStatement(ifThen(ref.property('isNotEmpty'), [
+ buf.invoke('write', [
+ literal(' $upper (') +
+ ref.invoke('join', [literal(', ')]) +
+ literal(')')
+ ])
+ ]));
+ }
+
+ var litBuf = new StringBuffer();
+ _addReturning(litBuf, ctx);
+ meth.addStatement(buf.invoke('write', [literal(litBuf.toString())]));
+
+ var streamController = new TypeBuilder('StreamController',
+ genericTypes: [new TypeBuilder(ctx.modelClassName)]);
+ meth.addStatement(varField('ctrl',
+ type: streamController, value: streamController.newInstance([])));
+
+ var future =
+ reference('connection').invoke('query', [buf.invoke('toString', [])]);
+ _invokeStreamClosure(future, meth);
+
return meth;
}
@@ -438,32 +477,21 @@ class PostgresORMGenerator extends GeneratorForAnnotation {
var id = reference('id');
var connection = reference('connection');
- var beforeDelete = reference('__ormBeforeDelete__');
var result = reference('result');
- // var __ormBeforeDelete__ = await XQuery.getOne(id, connection);
- meth.addStatement(varField('__ormBeforeDelete__',
- value: new TypeBuilder(ctx.queryClassName)
- .invoke('getOne', [id, connection]).asAwait()));
+ var buf = new StringBuffer('DELETE FROM "${ctx.tableName}" WHERE id = @id');
+ _addReturning(buf, ctx);
// await connection.execute('...');
meth.addStatement(varField('result',
- value: connection.invoke('execute', [
- literal('DELETE FROM "${ctx.tableName}" WHERE id = @id;')
+ value: connection.invoke('query', [
+ literal(buf.toString())
], namedArguments: {
'substitutionValues': map({'id': id})
}).asAwait()));
- meth.addStatement(ifThen(result.notEquals(literal(1)), [
- lib$core.StateError.newInstance([
- literal('DELETE query deleted ') +
- result +
- literal(' row(s), instead of exactly 1 row.')
- ])
- ]));
-
- // return __ormBeforeDelete__
- meth.addStatement(beforeDelete.asReturn());
+ meth.addStatement(
+ reference('parseRow').call([result[literal(0)]]).asReturn());
return meth;
}
@@ -501,43 +529,85 @@ class PostgresORMGenerator extends GeneratorForAnnotation {
}
});
- buf.write(');');
+ buf.write(')');
// meth.addStatement(lib$core.print.call([literal(buf.toString())]));
+ _addReturning(buf, ctx);
_ensureDates(meth, ctx);
var substitutionValues = _buildSubstitutionValues(ctx);
- // connection.execute...
- var connection = reference('connection'), nRows = reference('nRows');
- meth.addStatement(varField('nRows',
- value: connection.invoke('execute', [
- literal(buf.toString())
+ var connection = reference('connection');
+ var query = literal(buf.toString());
+ var result = reference('result');
+ meth.addStatement(varField('result',
+ value: connection.invoke('query', [
+ query
], namedArguments: {
'substitutionValues': map(substitutionValues)
}).asAwait()));
+ meth.addStatement(
+ reference('parseRow').call([result[literal(0)]]).asReturn());
+ return meth;
+ }
- meth.addStatement(ifThen(nRows < literal(1), [
- lib$core.StateError.newInstance([
- literal('Insertion into "${ctx.tableName}" table failed.')
- ]).asThrow()
+ MethodBuilder buildInsertModelMethod(PostgresBuildContext ctx) {
+ var rc = new ReCase(ctx.modelClassName);
+ var meth = new MethodBuilder('insert${rc.pascalCase}',
+ returnType: new TypeBuilder('Future',
+ genericTypes: [new TypeBuilder(ctx.modelClassName)]));
+
+ meth.addPositional(
+ parameter('connection', [new TypeBuilder('PostgreSQLConnection')]));
+ meth.addPositional(
+ parameter(rc.snakeCase, [new TypeBuilder(ctx.modelClassName)]));
+
+ Map args = {};
+ var ref = reference(rc.snakeCase);
+
+ ctx.fields.forEach((f) {
+ if (f.name != 'id') args[f.name] = ref.property(f.name);
+ });
+
+ meth.addStatement(new TypeBuilder(ctx.queryClassName)
+ .invoke('insert', [reference('connection')], namedArguments: args)
+ .asReturn());
+
+ return meth;
+ }
+
+ MethodBuilder buildUpdateModelMethod(PostgresBuildContext ctx) {
+ var rc = new ReCase(ctx.modelClassName);
+ var meth = new MethodBuilder('update${rc.pascalCase}',
+ returnType: new TypeBuilder('Future',
+ genericTypes: [new TypeBuilder(ctx.modelClassName)]));
+
+ meth.addPositional(
+ parameter('connection', [new TypeBuilder('PostgreSQLConnection')]));
+ meth.addPositional(
+ parameter(rc.snakeCase, [new TypeBuilder(ctx.modelClassName)]));
+
+ // var query = new XQuery();
+ var ref = reference(rc.snakeCase);
+ var query = reference('query');
+ meth.addStatement(varField('query',
+ value: new TypeBuilder(ctx.queryClassName).newInstance([])));
+
+ // query.where.id.equals(x.id);
+ meth.addStatement(query.property('where').property('id').invoke('equals', [
+ lib$core.int.invoke('parse', [ref.property('id')])
]));
- // Query the last value...
- /*
- var currval = await connection.query("SELECT * FROM cars WHERE id = currval(pg_get_serial_sequence('cars', 'id'));");
- print(currval);
- return parseRow(currval[0]);
- */
+ // return query.update(connection, ...).first;
+ Map args = {};
+ ctx.fields.forEach((f) {
+ if (f.name != 'id') args[f.name] = ref.property(f.name);
+ });
+
+ var update =
+ query.invoke('update', [reference('connection')], namedArguments: args);
+ meth.addStatement(update.property('first').asReturn());
- var currVal = reference('currVal');
- meth.addStatement(varField('currVal',
- value: connection.invoke('query', [
- literal(
- 'SELECT * FROM "${ctx.tableName}" WHERE id = currval(pg_get_serial_sequence(\'${ctx.tableName}\', \'id\'));')
- ]).asAwait()));
- meth.addStatement(
- reference('parseRow').call([currVal[literal(0)]]).asReturn());
return meth;
}
diff --git a/lib/src/builder/postgres/postgres_build_context.dart b/angel_orm_generator/lib/src/builder/postgres/postgres_build_context.dart
similarity index 92%
rename from lib/src/builder/postgres/postgres_build_context.dart
rename to angel_orm_generator/lib/src/builder/postgres/postgres_build_context.dart
index 3b6da148..9a52805a 100644
--- a/lib/src/builder/postgres/postgres_build_context.dart
+++ b/angel_orm_generator/lib/src/builder/postgres/postgres_build_context.dart
@@ -1,11 +1,9 @@
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/generated/resolver.dart';
+import 'package:angel_orm/angel_orm.dart';
+import 'package:angel_serialize_generator/context.dart';
import 'package:build/build.dart';
-import 'package:angel_serialize/context.dart';
-import '../../annotations.dart';
-import '../../migration.dart';
-import '../../relations.dart';
class PostgresBuildContext extends BuildContext {
DartType _dateTimeTypeCache;
diff --git a/angel_orm_generator/pubspec.yaml b/angel_orm_generator/pubspec.yaml
new file mode 100644
index 00000000..eb3b7f5e
--- /dev/null
+++ b/angel_orm_generator/pubspec.yaml
@@ -0,0 +1,20 @@
+name: angel_orm_generator
+version: 1.0.0-alpha
+description: Code generators for Angel's ORM.
+author: Tobe O
+homepage: https://github.com/angel-dart/orm
+environment:
+ sdk: ">=1.19.0"
+dependencies:
+ angel_orm: ^1.0.0-alpha
+ angel_serialize_generator: ^1.0.0-alpha
+ code_builder: ^1.0.0
+ inflection: ^0.4.1
+ recase: ^1.0.0
+ source_gen: ^0.6.0
+dev_dependencies:
+ angel_diagnostics: ^1.0.0
+ angel_framework: ^1.0.0
+ angel_test: ^1.0.0
+ build_runner: ^0.3.0
+ test: ^0.12.0
\ No newline at end of file
diff --git a/test/car_test.dart b/angel_orm_generator/test/car_test.dart
similarity index 75%
rename from test/car_test.dart
rename to angel_orm_generator/test/car_test.dart
index 131f4e66..626202d4 100644
--- a/test/car_test.dart
+++ b/angel_orm_generator/test/car_test.dart
@@ -106,12 +106,26 @@ main() {
expect(cars, isEmpty);
});
- test('delete', () async {
- var query = new CarQuery();
+ test('delete stream', () async {
+ var query = new CarQuery()..where.make.equals('Ferrari');
var cars = await query.delete(connection).toList();
expect(cars, hasLength(1));
expect(cars.first.toJson(), ferrari.toJson());
});
+
+ test('update', () async {
+ var query = new CarQuery()..where.id.equals(int.parse(ferrari.id));
+ var cars = await query.update(connection, make: 'Hyundai').toList();
+ expect(cars, hasLength(1));
+ expect(cars.first.make, 'Hyundai');
+ });
+
+ test('update car', () async {
+ var cloned = ferrari.clone()..make = 'Angel';
+ var car = await CarQuery.updateCar(connection, cloned);
+ print(car.toJson());
+ expect(car.toJson(), cloned.toJson());
+ });
});
});
@@ -126,8 +140,25 @@ main() {
expect(car.make, 'Honda');
expect(car.description, 'Hello');
expect(car.familyFriendly, isTrue);
- expect(DATE_YMD_HMS.format(car.recalledAt), DATE_YMD_HMS.format(recalledAt));
+ expect(
+ DATE_YMD_HMS.format(car.recalledAt), DATE_YMD_HMS.format(recalledAt));
expect(car.createdAt, allOf(isNotNull, equals(car.updatedAt)));
});
+
+ test('insert car', () async {
+ var recalledAt = new DateTime.now();
+ var beetle = new Car(
+ make: 'Beetle',
+ description: 'Herbie',
+ familyFriendly: true,
+ recalledAt: recalledAt);
+ var car = await CarQuery.insertCar(connection, beetle);
+ print(car.toJson());
+ expect(car.make, beetle.make);
+ expect(car.description, beetle.description);
+ expect(car.familyFriendly, beetle.familyFriendly);
+ expect(DATE_YMD_HMS.format(car.recalledAt),
+ DATE_YMD_HMS.format(beetle.recalledAt));
+ });
});
}
diff --git a/test/common.dart b/angel_orm_generator/test/common.dart
similarity index 100%
rename from test/common.dart
rename to angel_orm_generator/test/common.dart
diff --git a/test/models/author.dart b/angel_orm_generator/test/models/author.dart
similarity index 100%
rename from test/models/author.dart
rename to angel_orm_generator/test/models/author.dart
diff --git a/test/models/author.down.g.sql b/angel_orm_generator/test/models/author.down.g.sql
similarity index 100%
rename from test/models/author.down.g.sql
rename to angel_orm_generator/test/models/author.down.g.sql
diff --git a/test/models/author.g.dart b/angel_orm_generator/test/models/author.g.dart
similarity index 95%
rename from test/models/author.g.dart
rename to angel_orm_generator/test/models/author.g.dart
index bce01bc1..3c2642ae 100644
--- a/test/models/author.g.dart
+++ b/angel_orm_generator/test/models/author.g.dart
@@ -46,4 +46,8 @@ class Author extends _Author {
};
static Author parse(Map map) => new Author.fromJson(map);
+
+ Author clone() {
+ return new Author.fromJson(toJson());
+ }
}
diff --git a/test/models/author.orm.g.dart b/angel_orm_generator/test/models/author.orm.g.dart
similarity index 72%
rename from test/models/author.orm.g.dart
rename to angel_orm_generator/test/models/author.orm.g.dart
index a313c229..a690bdbd 100644
--- a/test/models/author.orm.g.dart
+++ b/angel_orm_generator/test/models/author.orm.g.dart
@@ -95,8 +95,7 @@ class AuthorQuery {
var __ormNow__ = new DateTime.now();
var ctrl = new StreamController();
connection.query(
- buf.toString() +
- ' RETURNING ("id", "name", "created_at", "updated_at");',
+ buf.toString() + ' RETURNING "id", "name", "created_at", "updated_at";',
substitutionValues: {
'name': name,
'createdAt': createdAt != null ? createdAt : __ormNow__,
@@ -108,38 +107,69 @@ class AuthorQuery {
return ctrl.stream;
}
- Stream delete(PostgreSQLConnection connection) async {}
+ Stream delete(PostgreSQLConnection connection) {
+ var buf = new StringBuffer('DELETE FROM "authors"');
+ var whereClause = where.toWhereClause();
+ if (whereClause != null) {
+ buf.write(' ' + whereClause);
+ if (_and.isNotEmpty) {
+ buf.write(' AND (' + _and.join(', ') + ')');
+ }
+ if (_or.isNotEmpty) {
+ buf.write(' OR (' + _or.join(', ') + ')');
+ }
+ if (_not.isNotEmpty) {
+ buf.write(' NOT (' + _not.join(', ') + ')');
+ }
+ }
+ buf.write(' RETURNING "id", "name", "created_at", "updated_at";');
+ StreamController ctrl = new StreamController();
+ connection.query(buf.toString()).then((rows) {
+ rows.map(parseRow).forEach(ctrl.add);
+ ctrl.close();
+ }).catchError(ctrl.addError);
+ return ctrl.stream;
+ }
static Future deleteOne(
int id, PostgreSQLConnection connection) async {
- var __ormBeforeDelete__ = await AuthorQuery.getOne(id, connection);
- var result = await connection.execute(
- 'DELETE FROM "authors" WHERE id = @id;',
+ var result = await connection.query(
+ 'DELETE FROM "authors" WHERE id = @id RETURNING "id", "name", "created_at", "updated_at";',
substitutionValues: {'id': id});
- if (result != 1) {
- new StateError('DELETE query deleted ' +
- result +
- ' row(s), instead of exactly 1 row.');
- }
- return __ormBeforeDelete__;
+ return parseRow(result[0]);
}
static Future insert(PostgreSQLConnection connection,
{String name, DateTime createdAt, DateTime updatedAt}) async {
var __ormNow__ = new DateTime.now();
- var nRows = await connection.execute(
- 'INSERT INTO "authors" ("name", "created_at", "updated_at") VALUES (@name, @createdAt, @updatedAt);',
+ var result = await connection.query(
+ 'INSERT INTO "authors" ("name", "created_at", "updated_at") VALUES (@name, @createdAt, @updatedAt) RETURNING "id", "name", "created_at", "updated_at";',
substitutionValues: {
'name': name,
'createdAt': createdAt != null ? createdAt : __ormNow__,
'updatedAt': updatedAt != null ? updatedAt : __ormNow__
});
- if (nRows < 1) {
- throw new StateError('Insertion into "authors" table failed.');
- }
- var currVal = await connection.query(
- 'SELECT * FROM "authors" WHERE id = currval(pg_get_serial_sequence(\'authors\', \'id\'));');
- return parseRow(currVal[0]);
+ return parseRow(result[0]);
+ }
+
+ static Future insertAuthor(
+ PostgreSQLConnection connection, Author author) {
+ return AuthorQuery.insert(connection,
+ name: author.name,
+ createdAt: author.createdAt,
+ updatedAt: author.updatedAt);
+ }
+
+ static Future updateAuthor(
+ PostgreSQLConnection connection, Author author) {
+ var query = new AuthorQuery();
+ query.where.id.equals(int.parse(author.id));
+ return query
+ .update(connection,
+ name: author.name,
+ createdAt: author.createdAt,
+ updatedAt: author.updatedAt)
+ .first;
}
static Stream getAll(PostgreSQLConnection connection) =>
diff --git a/test/models/author.up.g.sql b/angel_orm_generator/test/models/author.up.g.sql
similarity index 100%
rename from test/models/author.up.g.sql
rename to angel_orm_generator/test/models/author.up.g.sql
diff --git a/test/models/book.dart b/angel_orm_generator/test/models/book.dart
similarity index 100%
rename from test/models/book.dart
rename to angel_orm_generator/test/models/book.dart
diff --git a/test/models/book.down.g.sql b/angel_orm_generator/test/models/book.down.g.sql
similarity index 100%
rename from test/models/book.down.g.sql
rename to angel_orm_generator/test/models/book.down.g.sql
diff --git a/test/models/book.g.dart b/angel_orm_generator/test/models/book.g.dart
similarity index 95%
rename from test/models/book.g.dart
rename to angel_orm_generator/test/models/book.g.dart
index 0df44c1c..7f2c01df 100644
--- a/test/models/book.g.dart
+++ b/angel_orm_generator/test/models/book.g.dart
@@ -51,4 +51,8 @@ class Book extends _Book {
};
static Book parse(Map map) => new Book.fromJson(map);
+
+ Book clone() {
+ return new Book.fromJson(toJson());
+ }
}
diff --git a/test/models/book.orm.g.dart b/angel_orm_generator/test/models/book.orm.g.dart
similarity index 73%
rename from test/models/book.orm.g.dart
rename to angel_orm_generator/test/models/book.orm.g.dart
index c460ea48..20e2e17b 100644
--- a/test/models/book.orm.g.dart
+++ b/angel_orm_generator/test/models/book.orm.g.dart
@@ -97,8 +97,7 @@ class BookQuery {
var __ormNow__ = new DateTime.now();
var ctrl = new StreamController();
connection.query(
- buf.toString() +
- ' RETURNING ("id", "name", "created_at", "updated_at");',
+ buf.toString() + ' RETURNING "id", "name", "created_at", "updated_at";',
substitutionValues: {
'name': name,
'createdAt': createdAt != null ? createdAt : __ormNow__,
@@ -110,36 +109,64 @@ class BookQuery {
return ctrl.stream;
}
- Stream delete(PostgreSQLConnection connection) async {}
+ Stream delete(PostgreSQLConnection connection) {
+ var buf = new StringBuffer('DELETE FROM "books"');
+ var whereClause = where.toWhereClause();
+ if (whereClause != null) {
+ buf.write(' ' + whereClause);
+ if (_and.isNotEmpty) {
+ buf.write(' AND (' + _and.join(', ') + ')');
+ }
+ if (_or.isNotEmpty) {
+ buf.write(' OR (' + _or.join(', ') + ')');
+ }
+ if (_not.isNotEmpty) {
+ buf.write(' NOT (' + _not.join(', ') + ')');
+ }
+ }
+ buf.write(' RETURNING "id", "name", "created_at", "updated_at";');
+ StreamController ctrl = new StreamController();
+ connection.query(buf.toString()).then((rows) {
+ rows.map(parseRow).forEach(ctrl.add);
+ ctrl.close();
+ }).catchError(ctrl.addError);
+ return ctrl.stream;
+ }
static Future deleteOne(int id, PostgreSQLConnection connection) async {
- var __ormBeforeDelete__ = await BookQuery.getOne(id, connection);
- var result = await connection.execute('DELETE FROM "books" WHERE id = @id;',
+ var result = await connection.query(
+ 'DELETE FROM "books" WHERE id = @id RETURNING "id", "name", "created_at", "updated_at";',
substitutionValues: {'id': id});
- if (result != 1) {
- new StateError('DELETE query deleted ' +
- result +
- ' row(s), instead of exactly 1 row.');
- }
- return __ormBeforeDelete__;
+ return parseRow(result[0]);
}
static Future insert(PostgreSQLConnection connection,
{String name, DateTime createdAt, DateTime updatedAt}) async {
var __ormNow__ = new DateTime.now();
- var nRows = await connection.execute(
- 'INSERT INTO "books" ("name", "created_at", "updated_at") VALUES (@name, @createdAt, @updatedAt);',
+ var result = await connection.query(
+ 'INSERT INTO "books" ("name", "created_at", "updated_at") VALUES (@name, @createdAt, @updatedAt) RETURNING "id", "name", "created_at", "updated_at";',
substitutionValues: {
'name': name,
'createdAt': createdAt != null ? createdAt : __ormNow__,
'updatedAt': updatedAt != null ? updatedAt : __ormNow__
});
- if (nRows < 1) {
- throw new StateError('Insertion into "books" table failed.');
- }
- var currVal = await connection.query(
- 'SELECT * FROM "books" WHERE id = currval(pg_get_serial_sequence(\'books\', \'id\'));');
- return parseRow(currVal[0]);
+ return parseRow(result[0]);
+ }
+
+ static Future insertBook(PostgreSQLConnection connection, Book book) {
+ return BookQuery.insert(connection,
+ name: book.name, createdAt: book.createdAt, updatedAt: book.updatedAt);
+ }
+
+ static Future updateBook(PostgreSQLConnection connection, Book book) {
+ var query = new BookQuery();
+ query.where.id.equals(int.parse(book.id));
+ return query
+ .update(connection,
+ name: book.name,
+ createdAt: book.createdAt,
+ updatedAt: book.updatedAt)
+ .first;
}
static Stream getAll(PostgreSQLConnection connection) =>
diff --git a/test/models/book.up.g.sql b/angel_orm_generator/test/models/book.up.g.sql
similarity index 100%
rename from test/models/book.up.g.sql
rename to angel_orm_generator/test/models/book.up.g.sql
diff --git a/test/models/car.dart b/angel_orm_generator/test/models/car.dart
similarity index 100%
rename from test/models/car.dart
rename to angel_orm_generator/test/models/car.dart
diff --git a/test/models/car.down.g.sql b/angel_orm_generator/test/models/car.down.g.sql
similarity index 100%
rename from test/models/car.down.g.sql
rename to angel_orm_generator/test/models/car.down.g.sql
diff --git a/test/models/car.g.dart b/angel_orm_generator/test/models/car.g.dart
similarity index 97%
rename from test/models/car.g.dart
rename to angel_orm_generator/test/models/car.g.dart
index 2425d12e..fd3f30f5 100644
--- a/test/models/car.g.dart
+++ b/angel_orm_generator/test/models/car.g.dart
@@ -72,4 +72,8 @@ class Car extends _Car {
};
static Car parse(Map map) => new Car.fromJson(map);
+
+ Car clone() {
+ return new Car.fromJson(toJson());
+ }
}
diff --git a/test/models/car.orm.g.dart b/angel_orm_generator/test/models/car.orm.g.dart
similarity index 76%
rename from test/models/car.orm.g.dart
rename to angel_orm_generator/test/models/car.orm.g.dart
index 827edc82..a4783e56 100644
--- a/test/models/car.orm.g.dart
+++ b/angel_orm_generator/test/models/car.orm.g.dart
@@ -104,7 +104,7 @@ class CarQuery {
var ctrl = new StreamController();
connection.query(
buf.toString() +
- ' RETURNING ("id", "make", "description", "family_friendly", "recalled_at", "created_at", "updated_at");',
+ ' RETURNING "id", "make", "description", "family_friendly", "recalled_at", "created_at", "updated_at";',
substitutionValues: {
'make': make,
'description': description,
@@ -120,10 +120,24 @@ class CarQuery {
}
Stream delete(PostgreSQLConnection connection) {
- var query = 'DELETE FROM "cars" RETURNING ("id", "make", "description", "family_friendly", "recalled_at", "created_at", "updated_at");';
+ var buf = new StringBuffer('DELETE FROM "cars"');
+ var whereClause = where.toWhereClause();
+ if (whereClause != null) {
+ buf.write(' ' + whereClause);
+ if (_and.isNotEmpty) {
+ buf.write(' AND (' + _and.join(', ') + ')');
+ }
+ if (_or.isNotEmpty) {
+ buf.write(' OR (' + _or.join(', ') + ')');
+ }
+ if (_not.isNotEmpty) {
+ buf.write(' NOT (' + _not.join(', ') + ')');
+ }
+ }
+ buf.write(
+ ' RETURNING "id", "make", "description", "family_friendly", "recalled_at", "created_at", "updated_at";');
StreamController ctrl = new StreamController();
- connection.execute(query).then((rows) {
- print('Rows: $rows');
+ connection.query(buf.toString()).then((rows) {
rows.map(parseRow).forEach(ctrl.add);
ctrl.close();
}).catchError(ctrl.addError);
@@ -131,15 +145,10 @@ class CarQuery {
}
static Future deleteOne(int id, PostgreSQLConnection connection) async {
- var __ormBeforeDelete__ = await CarQuery.getOne(id, connection);
- var result = await connection.execute('DELETE FROM "cars" WHERE id = @id;',
+ var result = await connection.query(
+ 'DELETE FROM "cars" WHERE id = @id RETURNING "id", "make", "description", "family_friendly", "recalled_at", "created_at", "updated_at";',
substitutionValues: {'id': id});
- if (result != 1) {
- new StateError('DELETE query deleted ' +
- result +
- ' row(s), instead of exactly 1 row.');
- }
- return __ormBeforeDelete__;
+ return parseRow(result[0]);
}
static Future insert(PostgreSQLConnection connection,
@@ -150,8 +159,8 @@ class CarQuery {
DateTime createdAt,
DateTime updatedAt}) async {
var __ormNow__ = new DateTime.now();
- var nRows = await connection.execute(
- 'INSERT INTO "cars" ("make", "description", "family_friendly", "recalled_at", "created_at", "updated_at") VALUES (@make, @description, @familyFriendly, @recalledAt, @createdAt, @updatedAt);',
+ var result = await connection.query(
+ 'INSERT INTO "cars" ("make", "description", "family_friendly", "recalled_at", "created_at", "updated_at") VALUES (@make, @description, @familyFriendly, @recalledAt, @createdAt, @updatedAt) RETURNING "id", "make", "description", "family_friendly", "recalled_at", "created_at", "updated_at";',
substitutionValues: {
'make': make,
'description': description,
@@ -160,12 +169,31 @@ class CarQuery {
'createdAt': createdAt != null ? createdAt : __ormNow__,
'updatedAt': updatedAt != null ? updatedAt : __ormNow__
});
- if (nRows < 1) {
- throw new StateError('Insertion into "cars" table failed.');
- }
- var currVal = await connection.query(
- 'SELECT * FROM "cars" WHERE id = currval(pg_get_serial_sequence(\'cars\', \'id\'));');
- return parseRow(currVal[0]);
+ return parseRow(result[0]);
+ }
+
+ static Future insertCar(PostgreSQLConnection connection, Car car) {
+ return CarQuery.insert(connection,
+ make: car.make,
+ description: car.description,
+ familyFriendly: car.familyFriendly,
+ recalledAt: car.recalledAt,
+ createdAt: car.createdAt,
+ updatedAt: car.updatedAt);
+ }
+
+ static Future updateCar(PostgreSQLConnection connection, Car car) {
+ var query = new CarQuery();
+ query.where.id.equals(int.parse(car.id));
+ return query
+ .update(connection,
+ make: car.make,
+ description: car.description,
+ familyFriendly: car.familyFriendly,
+ recalledAt: car.recalledAt,
+ createdAt: car.createdAt,
+ updatedAt: car.updatedAt)
+ .first;
}
static Stream getAll(PostgreSQLConnection connection) =>
diff --git a/test/models/car.up.g.sql b/angel_orm_generator/test/models/car.up.g.sql
similarity index 100%
rename from test/models/car.up.g.sql
rename to angel_orm_generator/test/models/car.up.g.sql
diff --git a/tool/build.dart b/angel_orm_generator/tool/build.dart
similarity index 100%
rename from tool/build.dart
rename to angel_orm_generator/tool/build.dart
diff --git a/tool/phases.dart b/angel_orm_generator/tool/phases.dart
similarity index 69%
rename from tool/phases.dart
rename to angel_orm_generator/tool/phases.dart
index e1300396..78c2dd59 100644
--- a/tool/phases.dart
+++ b/angel_orm_generator/tool/phases.dart
@@ -1,9 +1,10 @@
import 'package:build_runner/build_runner.dart';
import 'package:source_gen/source_gen.dart';
-import 'package:angel_orm/builder.dart';
-import 'package:angel_serialize/builder.dart';
+import 'package:angel_orm_generator/angel_orm_generator.dart';
+import 'package:angel_serialize_generator/angel_serialize_generator.dart';
-final InputSet MODELS = new InputSet('angel_orm', const ['test/models/*.dart']);
+final InputSet MODELS =
+ new InputSet('angel_orm_generator', const ['test/models/*.dart']);
final PhaseGroup PHASES = new PhaseGroup()
..addPhase(new Phase()
diff --git a/tool/watch.dart b/angel_orm_generator/tool/watch.dart
similarity index 100%
rename from tool/watch.dart
rename to angel_orm_generator/tool/watch.dart
diff --git a/lib/src/builder/repository.dart b/lib/src/builder/repository.dart
deleted file mode 100644
index 73a12445..00000000
--- a/lib/src/builder/repository.dart
+++ /dev/null
@@ -1,296 +0,0 @@
-import 'dart:async';
-import 'dart:mirrors';
-import 'package:analyzer/dart/element/element.dart';
-import 'package:angel_serialize/angel_serialize.dart';
-import 'package:build/build.dart';
-import 'package:code_builder/dart/async.dart';
-import 'package:code_builder/dart/core.dart';
-import 'package:code_builder/code_builder.dart';
-import 'package:inflection/inflection.dart';
-import 'package:path/path.dart' as p;
-import 'package:recase/recase.dart';
-import 'package:source_gen/src/annotation.dart';
-import 'package:source_gen/source_gen.dart';
-import 'package:query_builder_sql/query_builder_sql.dart';
-import '../annotations.dart';
-
-// TODO: whereXLessThan, greaterThan, etc.
-
-final RegExp _leadingDot = new RegExp(r'^\.+');
-
-const List QUERY_DO_NOT_OVERRIDE = const ['when'];
-
-typedef Iterable SuperArgumentProvider(
- ORM model, ClassElement clazz);
-
-class AngelQueryBuilderGenerator extends GeneratorForAnnotation {
- ClassMirror _baseRepositoryClassMirror;
- final List _imports = [
- 'dart:async',
- 'package:query_builder/query_builder.dart'
- ];
-
- final Map _constructorParams = {};
- SuperArgumentProvider _superArgProvider;
-
- AngelQueryBuilderGenerator(Type baseRepositoryQueryClass,
- {Iterable additonalImports: const [],
- Map constructorParams: const {},
- SuperArgumentProvider superArgProvider}) {
- _baseRepositoryClassMirror = reflectClass(baseRepositoryQueryClass);
- _imports.addAll(additonalImports ?? []);
- _constructorParams.addAll(constructorParams ?? {});
- _superArgProvider = superArgProvider ??
- (annotation, clazz) => [
- literal(annotation.tableName?.isNotEmpty == true
- ? annotation.tableName
- : pluralize(new ReCase(clazz.name.substring(1)).snakeCase))
- ];
- }
-
- factory AngelQueryBuilderGenerator.postgresql() =>
- new AngelQueryBuilderGenerator(SqlRepositoryQuery, constructorParams: {
- 'connection': new TypeBuilder('PostgreSQLConnection')
- }, additonalImports: [
- 'package:postgres/postgres.dart',
- 'package:query_builder_sql/query_builder_sql.dart'
- ]);
-
- @override
- Future generateForAnnotatedElement(
- Element element, ORM annotation, BuildStep buildStep) async {
- if (element.kind != ElementKind.CLASS)
- throw 'Only classes may be annotated with @model.';
- var lib = generatePostgresLibrary(element, annotation, buildStep.inputId);
- return prettyToSource(lib.buildAst());
- }
-
- LibraryBuilder generatePostgresLibrary(
- ClassElement clazz, ORM annotation, AssetId inputId) {
- if (!clazz.name.startsWith('_'))
- throw 'Classes annotated with @model must have names starting with an underscore.';
- var lib = new LibraryBuilder();
- lib.addDirectives(_imports.map((p) => new ImportBuilder(p)));
- lib.addDirective(new ImportBuilder(p.basename(inputId.path)));
-
- // Find all aliases...
- Map aliases = {};
- clazz.fields.forEach((field) {
- var aliasAnnotation = field.metadata
- .firstWhere((ann) => matchAnnotation(Alias, ann), orElse: () => null);
- if (aliasAnnotation != null) {
- var alias = instantiateAnnotation(aliasAnnotation) as Alias;
- aliases[field.name] = alias.name;
- }
- });
-
- lib.addMember(generateRepositoryClass(clazz, aliases));
- lib.addMember(generateRepositoryQueryClass(clazz, annotation, aliases));
- return lib;
- }
-
- ClassBuilder generateRepositoryClass(
- ClassElement clazz, Map aliases) {
- var genClassName = clazz.name.substring(1) + 'Repository';
- var genQueryClassName = genClassName + 'Query';
- var genClass = new ClassBuilder(genClassName);
- var genQueryType = new TypeBuilder(genQueryClassName);
-
- // Add `connection` field + constructor
-
- var genConstructor = new ConstructorBuilder();
- _constructorParams.forEach((name, type) {
- genClass.addField(varFinal(name, type: type));
- genConstructor.addPositional(parameter(name), asField: true);
- });
- genClass.addConstructor(genConstructor);
-
- // Add an all method
- genClass.addMethod(new MethodBuilder('all',
- returnType: new TypeBuilder(genQueryClassName),
- returns: new TypeBuilder(genQueryClassName)
- .newInstance([reference('connection')])));
-
- // For each field, add a whereX() method...
- clazz.fields
- .map((field) => generateWhereFieldMethod(
- field, reference('all').call([]), genQueryType, aliases))
- .forEach(genClass.addMethod);
- return genClass;
- }
-
- ClassBuilder generateRepositoryQueryClass(
- ClassElement clazz, ORM annotation, Map aliases) {
- var modelClassName = clazz.name.substring(1);
- var genClassName = clazz.name.substring(1) + 'RepositoryQuery';
- var genClass = new ClassBuilder(genClassName,
- asExtends: new TypeBuilder(
- MirrorSystem.getName(_baseRepositoryClassMirror.simpleName),
- genericTypes: [new TypeBuilder(modelClassName)]));
- var genQueryType = new TypeBuilder(genClassName);
-
- // Add `connection` field + constructor
-
- var genConstructor = new ConstructorBuilder(
- invokeSuper: _superArgProvider(annotation, clazz));
- _constructorParams.forEach((name, type) {
- genClass.addField(varFinal(name, type: type));
- genConstructor.addPositional(parameter(name), asField: true);
- });
- genClass.addConstructor(genConstructor);
-
- // For each field, add a whereX() method...
- clazz.fields
- .map((field) => generateWhereFieldMethod(
- field, explicitThis, genQueryType, aliases))
- .forEach(genClass.addMethod);
-
- // Add orWhereX()
- clazz.fields
- .map((f) => generateOrWhereFieldMethod(genQueryType, f))
- .forEach(genClass.addMethod);
-
- // Override any query methods
- _baseRepositoryClassMirror.instanceMembers.forEach((sym, method) {
- // Skip setters, etc.
- if (!method.isRegularMethod) return;
-
- // Only if return type contains 'RepositoryQuery'
- var methodName = MirrorSystem.getName(sym);
-
- if (QUERY_DO_NOT_OVERRIDE.contains(methodName)) return;
-
- var returnTypeName = MirrorSystem.getName(method.returnType.simpleName);
-
- if (returnTypeName.contains('RepositoryQuery')) {
- var overriddenMethod =
- new MethodBuilder(methodName, returnType: genQueryType);
- // Add @override
- overriddenMethod.addAnnotation(lib$core.override);
-
- // Find all positional and named args
- List args = [];
- List named = [];
-
- method.parameters.forEach((param) {
- var paramName = MirrorSystem.getName(param.simpleName);
- var typeName = MirrorSystem.getName(param.type.simpleName);
- var paramType = new TypeBuilder(typeName);
- var genParam = parameter(paramName, [paramType]);
-
- if (!param.isNamed) {
- args.add(paramName);
- overriddenMethod.addPositional(
- param.isOptional ? genParam.asOptional() : genParam);
- } else {
- overriddenMethod.addNamed(genParam);
- named.add(paramName);
- }
- });
-
- // Invoke super
- overriddenMethod.addStatement(reference('super')
- .invoke(methodName, args.map(reference),
- namedArguments: named.fold