1.0.1
This commit is contained in:
parent
f07211328f
commit
80a31575aa
9 changed files with 662 additions and 295 deletions
|
@ -1,19 +1,20 @@
|
|||
import 'dart:io';
|
||||
import 'package:args/command_runner.dart';
|
||||
import 'package:code_builder/code_builder.dart';
|
||||
import 'package:console/console.dart';
|
||||
import 'package:id/id.dart';
|
||||
import 'package:inflection/inflection.dart';
|
||||
import 'package:recase/recase.dart';
|
||||
import 'service_generators/service_generators.dart';
|
||||
import 'init.dart' show preBuild;
|
||||
|
||||
const List<ServiceGenerator> GENERATORS = const [
|
||||
const MapServiceGenerator(),
|
||||
const MongoServiceGenerator(),
|
||||
const RethinkServiceGenerator(),
|
||||
const CustomServiceGenerator()
|
||||
];
|
||||
|
||||
class ServiceCommand extends Command {
|
||||
final String CUSTOM = 'Custom';
|
||||
final String MEMORY = 'In-Memory';
|
||||
final String MEMORY_JSON = 'In-Memory (serialized via `source_gen`)';
|
||||
final String MONGO = 'MongoDB';
|
||||
final String MONGO_TYPED = 'MongoDB (typed)';
|
||||
final String MONGO_TYPED_JSON =
|
||||
'MongoDB (typed, serialized via `source_gen`)';
|
||||
final String TRESTLE = 'Trestle';
|
||||
final TextPen _pen = new TextPen();
|
||||
|
||||
@override
|
||||
|
@ -22,130 +23,146 @@ class ServiceCommand extends Command {
|
|||
@override
|
||||
String get description => 'Creates a new service within the given project.';
|
||||
|
||||
String _snake(name) => idFromString(name).snake;
|
||||
|
||||
@override
|
||||
run() async {
|
||||
var name = await readInput('Name of Service (not plural): ');
|
||||
var chooser = new Chooser([MONGO, MONGO_TYPED, MEMORY, CUSTOM],
|
||||
var chooser = new Chooser<String>(
|
||||
GENERATORS.map<String>((g) => g.name).toList(),
|
||||
message: 'What type of service would you like to create? ');
|
||||
var type = await chooser.choose();
|
||||
|
||||
fail() {
|
||||
_pen.red();
|
||||
_pen('Could not successfully create service $name.');
|
||||
_pen();
|
||||
}
|
||||
print('Wrap this service in a TypedService? (slight performance cost)');
|
||||
chooser = new Chooser<String>(['Yes', 'No']);
|
||||
var typed = (await chooser.choose()) == 'Yes';
|
||||
|
||||
String serviceSource = '';
|
||||
var generator =
|
||||
GENERATORS.firstWhere((g) => g.name == type, orElse: () => null);
|
||||
|
||||
if (type == MONGO) {
|
||||
serviceSource = _generateMongoService(name);
|
||||
} else if (type == MONGO_TYPED) {
|
||||
serviceSource = _generateMongoTypedService(name);
|
||||
await _generateMongoModel(name);
|
||||
await _generateValidator(name);
|
||||
} else if (type == MONGO_TYPED_JSON) {
|
||||
serviceSource = _generateMongoTypedService(name);
|
||||
await _generateMongoModelJson(name);
|
||||
await _generateValidator(name);
|
||||
} else if (type == MEMORY) {
|
||||
serviceSource = _generateMemoryService(name);
|
||||
await _generateMemoryModel(name);
|
||||
await _generateValidator(name);
|
||||
} else if (type == MEMORY_JSON) {
|
||||
serviceSource = _generateMemoryService(name);
|
||||
await _generateMemoryModelJson(name);
|
||||
await _generateValidator(name);
|
||||
} else if (type == CUSTOM) {
|
||||
serviceSource = _generateCustomService(name);
|
||||
} else if (type == TRESTLE) {
|
||||
if (generator == null) {
|
||||
_pen.blue();
|
||||
_pen('${Icon.STAR} Trestle services are not yet implemented. :(');
|
||||
_pen('${Icon.STAR} \'$type\' services are not yet implemented. :(');
|
||||
_pen();
|
||||
} else {
|
||||
print('Code to generate a $type service is not yet written.');
|
||||
}
|
||||
|
||||
if (serviceSource.isEmpty) {
|
||||
fail();
|
||||
throw new Exception('Empty generated service code.');
|
||||
}
|
||||
|
||||
var lower = _snake(name);
|
||||
var rc = new ReCase(name);
|
||||
name = rc.pascalCase;
|
||||
var lower = rc.snakeCase;
|
||||
var servicesDir = new Directory('lib/src/services');
|
||||
var serviceFile = new File.fromUri(servicesDir.uri.resolve('$lower.dart'));
|
||||
var serviceFile =
|
||||
new File.fromUri(servicesDir.uri.resolve('$lower.dart'));
|
||||
var testDir = new Directory('test/services');
|
||||
var testFile = new File.fromUri(testDir.uri.resolve('${lower}_test.dart'));
|
||||
|
||||
if (!await servicesDir.exists()) await servicesDir.create(recursive: true);
|
||||
var testFile =
|
||||
new File.fromUri(testDir.uri.resolve('${lower}_test.dart'));
|
||||
|
||||
if (!await servicesDir.exists())
|
||||
await servicesDir.create(recursive: true);
|
||||
if (!await testDir.exists()) await testDir.create(recursive: true);
|
||||
|
||||
await serviceFile.writeAsString(serviceSource);
|
||||
|
||||
if (type == MONGO_TYPED || type == MEMORY) {
|
||||
var serviceLibrary = new File('lib/src/models/models.dart');
|
||||
await serviceLibrary.writeAsString("\nexport '$lower.dart';",
|
||||
mode: FileMode.APPEND);
|
||||
await preBuild(Directory.current);
|
||||
}
|
||||
|
||||
await testFile.writeAsString(_generateTests(name, type));
|
||||
await serviceFile
|
||||
.writeAsString(_generateService(generator, name, lower, typed));
|
||||
await testFile.writeAsString(_generateTests(lower, type));
|
||||
|
||||
var runConfig = new File('./.idea/runConfigurations/${name}_Tests.xml');
|
||||
|
||||
if (!await runConfig.exists()) {
|
||||
await runConfig.create(recursive: true);
|
||||
await runConfig.writeAsString(_generateRunConfiguration(name));
|
||||
await runConfig.writeAsString(_generateRunConfiguration(name, lower));
|
||||
}
|
||||
|
||||
if (generator.createsModel == true) {
|
||||
await _generateModel(name, lower);
|
||||
}
|
||||
|
||||
if (generator.createsValidator == true) {
|
||||
await _generateValidator(lower, rc.constantCase);
|
||||
}
|
||||
|
||||
if (generator.exportedInServiceLibrary == true) {
|
||||
var serviceLibrary = new File('lib/src/models/models.dart');
|
||||
await serviceLibrary.writeAsString("\nexport '$lower.dart';",
|
||||
mode: FileMode.APPEND);
|
||||
}
|
||||
|
||||
if (generator.shouldRunBuild == true) {
|
||||
await preBuild(Directory.current);
|
||||
}
|
||||
|
||||
_pen.green();
|
||||
_pen('${Icon.CHECKMARK} Successfully generated service $name.');
|
||||
_pen();
|
||||
}
|
||||
|
||||
_generateValidator(String name) async {
|
||||
var rc = new ReCase(name);
|
||||
var file = new File('lib/src/validators/${rc.snakeCase}.dart');
|
||||
|
||||
if (!await file.exists()) await file.createSync(recursive: true);
|
||||
|
||||
await file.writeAsString('''
|
||||
import 'package:angel_validate/angel_validate.dart';
|
||||
|
||||
final Validator CREATE_${rc.constantCase} =
|
||||
new Validator({'name*': isString, 'desc*': isString});
|
||||
'''
|
||||
.trim());
|
||||
}
|
||||
|
||||
_generateCustomService(String name) {
|
||||
return '''
|
||||
String _generateService(
|
||||
ServiceGenerator generator, String name, String lower, bool typed) {
|
||||
var lib = new LibraryBuilder();
|
||||
|
||||
/*
|
||||
import 'package:angel_framework/angel_framework.dart';
|
||||
import '../models/$lower.dart';
|
||||
export '../models/$lower.dart';
|
||||
*/
|
||||
lib.addMember(
|
||||
new ImportBuilder('package:angel_framework/angel_framework.dart'));
|
||||
generator.applyToLibrary(lib, name, lower);
|
||||
|
||||
class ${name}Service extends Service {
|
||||
${name}Service():super() {
|
||||
// Your logic here!
|
||||
}
|
||||
}
|
||||
'''
|
||||
.trim();
|
||||
if (generator.createsModel == true) {
|
||||
lib
|
||||
..addMember(new ImportBuilder('../models/$lower.dart'))
|
||||
..addMember(new ExportBuilder('../models/$lower.dart'));
|
||||
}
|
||||
|
||||
_generateMemoryModel(String name) async {
|
||||
var lower = _snake(name);
|
||||
// configureServer() {}
|
||||
var configureServer = new MethodBuilder('configureServer',
|
||||
returnType: new TypeBuilder('AngelConfigurer'));
|
||||
generator.applyToConfigureServer(configureServer, name, lower);
|
||||
|
||||
// return (Angel app) async {}
|
||||
var closure = new MethodBuilder.closure(modifier: MethodModifier.asAsync)
|
||||
..addPositional(parameter('app', [new TypeBuilder('Angel')]));
|
||||
generator.beforeService(closure, name, lower);
|
||||
|
||||
// app.use('/api/todos', new MapService());
|
||||
var service = generator.createInstance(closure, name, lower);
|
||||
|
||||
if (typed == true) {
|
||||
service =
|
||||
new TypeBuilder('TypedService', genericTypes: [new TypeBuilder(name)])
|
||||
.newInstance([service]);
|
||||
}
|
||||
|
||||
closure.addStatement(reference('app')
|
||||
.invoke('use', [literal('/api/${pluralize(lower)}'), service]));
|
||||
|
||||
if (generator.injectsSingleton == true) {
|
||||
closure.addStatement(varField('service',
|
||||
value: reference('app')
|
||||
.invoke('service', [literal('/api/${pluralize(lower)}')]).castAs(
|
||||
new TypeBuilder('HookedService'))));
|
||||
closure.addStatement(reference('app')
|
||||
.property('container')
|
||||
.invoke('singleton', [reference('service').property('inner')]));
|
||||
}
|
||||
|
||||
configureServer.addStatement(closure.asReturn());
|
||||
|
||||
lib.addMember(configureServer);
|
||||
|
||||
return prettyToSource(lib.buildAst());
|
||||
}
|
||||
|
||||
_generateModel(String name, String lower) async {
|
||||
var file = new File('lib/src/models/$lower.dart');
|
||||
|
||||
if (!await file.exists()) await file.createSync(recursive: true);
|
||||
|
||||
await file.writeAsString('''
|
||||
library angel.models.$lower;
|
||||
|
||||
import 'package:angel_framework/common.dart';
|
||||
|
||||
class $name extends Model {
|
||||
String name, desc;
|
||||
String name;
|
||||
|
||||
String desc;
|
||||
|
||||
$name({String id, this.name, this.desc}) {
|
||||
this.id = id;
|
||||
|
@ -155,197 +172,21 @@ class $name extends Model {
|
|||
.trim());
|
||||
}
|
||||
|
||||
_generateMemoryModelJson(String name) async {
|
||||
var lower = _snake(name);
|
||||
var file = new File('lib/src/models/$lower.dart');
|
||||
_generateValidator(String lower, String constantCase) async {
|
||||
var file = new File('lib/src/validators/$lower.dart');
|
||||
|
||||
if (!await file.exists()) await file.createSync(recursive: true);
|
||||
|
||||
await file.writeAsString('''
|
||||
library angel.models.$lower;
|
||||
|
||||
import 'package:angel_framework/common.dart';
|
||||
import 'package:source_gen/generators/json_serializable.dart';
|
||||
|
||||
part '$lower.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
class $name extends Model with _\$${name}SerializerMixin {
|
||||
@JsonKey('id')
|
||||
@override
|
||||
String id;
|
||||
|
||||
@JsonKey('name')
|
||||
String name;
|
||||
|
||||
@JsonKey('desc')
|
||||
String desc;
|
||||
|
||||
factory $name.fromJson(Map json) => _\$${name}FromJson(json);
|
||||
|
||||
$name({this.id, this.name, this.desc});
|
||||
}
|
||||
'''
|
||||
.trim());
|
||||
}
|
||||
|
||||
_generateMemoryService(String name) {
|
||||
var rc = new ReCase(name);
|
||||
var lower = rc.snakeCase;
|
||||
|
||||
return '''
|
||||
import 'package:angel_framework/angel_framework.dart';
|
||||
import '../models/$lower.dart';
|
||||
export '../models/$lower.dart';
|
||||
|
||||
/// Manages [$name] in-memory.
|
||||
class ${name}Service extends MemoryService<$name> {
|
||||
${name}Service():super() {
|
||||
// Your logic here!
|
||||
}
|
||||
}
|
||||
'''
|
||||
.trim();
|
||||
}
|
||||
|
||||
_generateMongoModel(String name) async {
|
||||
var lower = _snake(name);
|
||||
var file = new File('lib/src/models/$lower.dart');
|
||||
|
||||
if (!await file.exists()) await file.createSync(recursive: true);
|
||||
|
||||
await file.writeAsString('''
|
||||
library angel.models.$lower;
|
||||
|
||||
import 'package:angel_mongo/model.dart';
|
||||
import 'package:source_gen/generators/json_serializable.dart';
|
||||
|
||||
part '$lower.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
class $name extends Model with _\$${name}SerializerMixin {
|
||||
@JsonKey('id')
|
||||
@override
|
||||
String id;
|
||||
|
||||
@JsonKey('name')
|
||||
String name;
|
||||
|
||||
@JsonKey('desc')
|
||||
String desc;
|
||||
|
||||
factory $name.fromJson(Map json) => _\$${name}FromJson(json);
|
||||
|
||||
$name({this.id, this.name, this.desc});
|
||||
}
|
||||
'''
|
||||
.trim());
|
||||
}
|
||||
|
||||
_generateMongoModelJson(String name) async {
|
||||
var lower = _snake(name);
|
||||
var file = new File('lib/src/models/$lower.dart');
|
||||
|
||||
if (!await file.exists()) await file.createSync(recursive: true);
|
||||
|
||||
await file.writeAsString('''
|
||||
library angel.models.$lower;
|
||||
|
||||
import 'package:angel_framework/common.dart';
|
||||
import 'package:source_gen/generators/json_serializable.dart';
|
||||
|
||||
part '$lower.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
class $name extends Model with _\$${name}SerializerMixin {
|
||||
@JsonKey('id')
|
||||
@override
|
||||
String id;
|
||||
|
||||
@JsonKey('name')
|
||||
String name;
|
||||
|
||||
@JsonKey('desc')
|
||||
String desc;
|
||||
|
||||
factory $name.fromJson(Map json) => _\$${name}FromJson(json);
|
||||
|
||||
$name({this.id, this.name, this.desc});
|
||||
}
|
||||
'''
|
||||
.trim());
|
||||
}
|
||||
|
||||
_generateMongoService(String name) {
|
||||
var lower = _snake(name);
|
||||
|
||||
return '''
|
||||
import 'package:angel_framework/angel_framework.dart';
|
||||
import 'package:angel_mongo/angel_mongo.dart';
|
||||
import 'package:angel_validate/angel_validate.dart';
|
||||
import 'package:angel_validate/server.dart';
|
||||
import 'package:mongo_dart/mongo_dart.dart';
|
||||
|
||||
final Validator ${lower}Schema = new Validator({
|
||||
'name*': [isString, isNotEmpty],
|
||||
'desc*': [isString, isNotEmpty]
|
||||
});
|
||||
|
||||
configureServer(Db db) {
|
||||
return (Angel app) async {
|
||||
app.use('/api/${lower}s', new ${name}Service(db.collection('${lower}s')));
|
||||
|
||||
HookedService service = app.service('api/${lower}s');
|
||||
app.container.singleton(service.inner);
|
||||
|
||||
service
|
||||
..beforeCreate.listen(validateEvent(${lower}Schema))
|
||||
..beforeUpdate.listen(validateEvent(${lower}Schema));
|
||||
};
|
||||
}
|
||||
|
||||
/// Manages [$name] in the database.
|
||||
class ${name}Service extends MongoService {
|
||||
${name}Service(collection):super(collection) {
|
||||
// Your logic here!
|
||||
}
|
||||
}
|
||||
final Validator CREATE_$constantCase =
|
||||
new Validator({'name*': isString, 'desc*': isString});
|
||||
'''
|
||||
.trim();
|
||||
.trim());
|
||||
}
|
||||
|
||||
_generateMongoTypedService(String name) {
|
||||
var lower = _snake(name);
|
||||
|
||||
return '''
|
||||
import 'package:angel_framework/angel_framework.dart';
|
||||
import 'package:angel_mongo/angel_mongo.dart';
|
||||
import 'package:mongo_dart/mongo_dart.dart';
|
||||
import '../models/$lower.dart';
|
||||
export '../models/$lower.dart';
|
||||
|
||||
configureServer(Db db) {
|
||||
return (Angel app) async {
|
||||
app.use('/api/${lower}s', new ${name}Service(db.collection('${lower}s')));
|
||||
|
||||
HookedService service = app.service('api/${lower}s');
|
||||
app.container.singleton(service.inner);
|
||||
};
|
||||
}
|
||||
|
||||
/// Manages [$name] in the database.
|
||||
class ${name}Service extends MongoTypedService<$name> {
|
||||
${name}Service(collection):super(collection) {
|
||||
// Your logic here!
|
||||
}
|
||||
}
|
||||
'''
|
||||
.trim();
|
||||
}
|
||||
|
||||
_generateRunConfiguration(String name) {
|
||||
var lower = _snake(name);
|
||||
|
||||
_generateRunConfiguration(String name, String lower) {
|
||||
return '''
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="$name Tests" type="DartTestRunConfigurationType" factoryName="Dart Test" singleton="true">
|
||||
|
@ -357,9 +198,7 @@ class ${name}Service extends MongoTypedService<$name> {
|
|||
.trim();
|
||||
}
|
||||
|
||||
_generateTests(String name, String type) {
|
||||
var lower = _snake(name);
|
||||
|
||||
_generateTests(String lower, String type) {
|
||||
return '''
|
||||
import 'dart:io';
|
||||
import 'package:angel/angel.dart';
|
||||
|
@ -382,13 +221,13 @@ main() async {
|
|||
});
|
||||
|
||||
test('index via REST', () async {
|
||||
var response = await client.get('/api/${lower}s');
|
||||
var response = await client.get('/api/${pluralize(lower)}');
|
||||
expect(response, hasStatus(HttpStatus.OK));
|
||||
});
|
||||
|
||||
test('Index ${lower}s', () async {
|
||||
var ${lower}s = await client.service('api/${lower}s').index();
|
||||
print(${lower}s);
|
||||
test('Index ${pluralize(lower)}', () async {
|
||||
var ${pluralize(lower)} = await client.service('api/${pluralize(lower)}').index();
|
||||
print(${pluralize(lower)});
|
||||
});
|
||||
}
|
||||
|
||||
|
|
24
lib/src/commands/service_generators/custom.dart
Normal file
24
lib/src/commands/service_generators/custom.dart
Normal file
|
@ -0,0 +1,24 @@
|
|||
import 'package:code_builder/code_builder.dart';
|
||||
import 'generator.dart';
|
||||
|
||||
class CustomServiceGenerator extends ServiceGenerator {
|
||||
@override
|
||||
bool get createsModel => false;
|
||||
|
||||
@override
|
||||
bool get createsValidator => false;
|
||||
|
||||
const CustomServiceGenerator() : super('Custom');
|
||||
|
||||
@override
|
||||
void applyToLibrary(LibraryBuilder library, String name, String lower) {
|
||||
var clazz = new ClassBuilder('${name}Service', asExtends: new TypeBuilder('Service'));
|
||||
library.addMember(clazz);
|
||||
}
|
||||
|
||||
@override
|
||||
ExpressionBuilder createInstance(
|
||||
MethodBuilder methodBuilder, String name, String lower) {
|
||||
return new TypeBuilder('${name}Service').newInstance([]);
|
||||
}
|
||||
}
|
24
lib/src/commands/service_generators/generator.dart
Normal file
24
lib/src/commands/service_generators/generator.dart
Normal file
|
@ -0,0 +1,24 @@
|
|||
import 'package:code_builder/code_builder.dart';
|
||||
|
||||
class ServiceGenerator {
|
||||
final String name;
|
||||
|
||||
const ServiceGenerator(this.name);
|
||||
|
||||
bool get createsModel => true;
|
||||
bool get createsValidator => true;
|
||||
bool get exportedInServiceLibrary => true;
|
||||
bool get injectsSingleton => true;
|
||||
bool get shouldRunBuild => false;
|
||||
|
||||
void applyToLibrary(LibraryBuilder library, String name, String lower) {}
|
||||
|
||||
void beforeService(MethodBuilder methodBuilder, String name, String lower) {}
|
||||
|
||||
void applyToConfigureServer(
|
||||
MethodBuilder configureServer, String name, String lower) {}
|
||||
|
||||
ExpressionBuilder createInstance(
|
||||
MethodBuilder methodBuilder, String name, String lower) =>
|
||||
literal(null);
|
||||
}
|
15
lib/src/commands/service_generators/map.dart
Normal file
15
lib/src/commands/service_generators/map.dart
Normal file
|
@ -0,0 +1,15 @@
|
|||
import 'generator.dart';
|
||||
import 'package:code_builder/code_builder.dart';
|
||||
|
||||
class MapServiceGenerator extends ServiceGenerator {
|
||||
@override
|
||||
bool get createsModel => false;
|
||||
|
||||
const MapServiceGenerator() : super('In-Memory');
|
||||
|
||||
@override
|
||||
ExpressionBuilder createInstance(
|
||||
MethodBuilder methodBuilder, String name, String lower) {
|
||||
return new TypeBuilder('MapService').newInstance([]);
|
||||
}
|
||||
}
|
29
lib/src/commands/service_generators/mongo.dart
Normal file
29
lib/src/commands/service_generators/mongo.dart
Normal file
|
@ -0,0 +1,29 @@
|
|||
import 'generator.dart';
|
||||
import 'package:code_builder/code_builder.dart';
|
||||
import 'package:inflection/inflection.dart';
|
||||
|
||||
class MongoServiceGenerator extends ServiceGenerator {
|
||||
const MongoServiceGenerator() : super('MongoDB');
|
||||
|
||||
@override
|
||||
void applyToConfigureServer(
|
||||
MethodBuilder configureServer, String name, String lower) {
|
||||
configureServer.addPositional(parameter('db', [new TypeBuilder('Db')]));
|
||||
}
|
||||
|
||||
@override
|
||||
void applyToLibrary(LibraryBuilder library, String name, String lower) {
|
||||
library.addMembers([
|
||||
'package:angel_mongo/angel_mongo.dart',
|
||||
'package:mongo_dart/mongo_dart.dart'
|
||||
].map((str) => new ImportBuilder(str)));
|
||||
}
|
||||
|
||||
@override
|
||||
ExpressionBuilder createInstance(
|
||||
MethodBuilder methodBuilder, String name, String lower) {
|
||||
return new TypeBuilder('MongoService').newInstance([
|
||||
reference('db').invoke('collection', [literal(pluralize(lower))])
|
||||
]);
|
||||
}
|
||||
}
|
31
lib/src/commands/service_generators/rethink.dart
Normal file
31
lib/src/commands/service_generators/rethink.dart
Normal file
|
@ -0,0 +1,31 @@
|
|||
import 'generator.dart';
|
||||
import 'package:code_builder/code_builder.dart';
|
||||
import 'package:inflection/inflection.dart';
|
||||
|
||||
class RethinkServiceGenerator extends ServiceGenerator {
|
||||
const RethinkServiceGenerator() : super('RethinkDB');
|
||||
|
||||
@override
|
||||
void applyToConfigureServer(
|
||||
MethodBuilder configureServer, String name, String lower) {
|
||||
configureServer
|
||||
..addPositional(parameter('connection', [new TypeBuilder('Connection')]))
|
||||
..addPositional(parameter('r', [new TypeBuilder('Rethinkdb')]));
|
||||
}
|
||||
|
||||
@override
|
||||
void applyToLibrary(LibraryBuilder library, String name, String lower) {
|
||||
library.addMembers([
|
||||
'package:angel_rethink/angel_rethink.dart',
|
||||
'package:rethinkdb_driver/rethinkdb_driver.dart'
|
||||
].map((str) => new ImportBuilder(str)));
|
||||
}
|
||||
|
||||
@override
|
||||
ExpressionBuilder createInstance(
|
||||
MethodBuilder methodBuilder, String name, String lower) {
|
||||
return new TypeBuilder('RethinkService').newInstance([
|
||||
reference('r').invoke('table', [literal(pluralize(lower))])
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
export 'custom.dart';
|
||||
export 'generator.dart';
|
||||
export 'map.dart';
|
||||
export 'mongo.dart';
|
||||
export 'rethink.dart';
|
398
lib/src/commands/service_old.dart
Normal file
398
lib/src/commands/service_old.dart
Normal file
|
@ -0,0 +1,398 @@
|
|||
import 'dart:io';
|
||||
import 'package:args/command_runner.dart';
|
||||
import 'package:console/console.dart';
|
||||
import 'package:id/id.dart';
|
||||
import 'package:recase/recase.dart';
|
||||
import 'init.dart' show preBuild;
|
||||
|
||||
class ServiceCommand extends Command {
|
||||
final String CUSTOM = 'Custom';
|
||||
final String MEMORY = 'In-Memory';
|
||||
final String MEMORY_JSON = 'In-Memory (serialized via `source_gen`)';
|
||||
final String MONGO = 'MongoDB';
|
||||
final String MONGO_TYPED = 'MongoDB (typed)';
|
||||
final String MONGO_TYPED_JSON =
|
||||
'MongoDB (typed, serialized via `source_gen`)';
|
||||
final String TRESTLE = 'Trestle';
|
||||
final TextPen _pen = new TextPen();
|
||||
|
||||
@override
|
||||
String get name => 'service';
|
||||
|
||||
@override
|
||||
String get description => 'Creates a new service within the given project.';
|
||||
|
||||
String _snake(name) => idFromString(name).snake;
|
||||
|
||||
@override
|
||||
run() async {
|
||||
var name = await readInput('Name of Service (not plural): ');
|
||||
var chooser = new Chooser([MONGO, MONGO_TYPED, MEMORY, CUSTOM],
|
||||
message: 'What type of service would you like to create? ');
|
||||
var type = await chooser.choose();
|
||||
|
||||
fail() {
|
||||
_pen.red();
|
||||
_pen('Could not successfully create service $name.');
|
||||
_pen();
|
||||
}
|
||||
|
||||
String serviceSource = '';
|
||||
|
||||
if (type == MONGO) {
|
||||
serviceSource = _generateMongoService(name);
|
||||
} else if (type == MONGO_TYPED) {
|
||||
serviceSource = _generateMongoTypedService(name);
|
||||
await _generateMongoModel(name);
|
||||
await _generateValidator(name);
|
||||
} else if (type == MONGO_TYPED_JSON) {
|
||||
serviceSource = _generateMongoTypedService(name);
|
||||
await _generateMongoModelJson(name);
|
||||
await _generateValidator(name);
|
||||
} else if (type == MEMORY) {
|
||||
serviceSource = _generateMemoryService(name);
|
||||
await _generateMemoryModel(name);
|
||||
await _generateValidator(name);
|
||||
} else if (type == MEMORY_JSON) {
|
||||
serviceSource = _generateMemoryService(name);
|
||||
await _generateMemoryModelJson(name);
|
||||
await _generateValidator(name);
|
||||
} else if (type == CUSTOM) {
|
||||
serviceSource = _generateCustomService(name);
|
||||
} else if (type == TRESTLE) {
|
||||
_pen.blue();
|
||||
_pen('${Icon.STAR} Trestle services are not yet implemented. :(');
|
||||
_pen();
|
||||
} else {
|
||||
print('Code to generate a $type service is not yet written.');
|
||||
}
|
||||
|
||||
if (serviceSource.isEmpty) {
|
||||
fail();
|
||||
throw new Exception('Empty generated service code.');
|
||||
}
|
||||
|
||||
var lower = _snake(name);
|
||||
var servicesDir = new Directory('lib/src/services');
|
||||
var serviceFile = new File.fromUri(servicesDir.uri.resolve('$lower.dart'));
|
||||
var testDir = new Directory('test/services');
|
||||
var testFile = new File.fromUri(testDir.uri.resolve('${lower}_test.dart'));
|
||||
|
||||
if (!await servicesDir.exists()) await servicesDir.create(recursive: true);
|
||||
|
||||
if (!await testDir.exists()) await testDir.create(recursive: true);
|
||||
|
||||
await serviceFile.writeAsString(serviceSource);
|
||||
|
||||
if (type == MONGO_TYPED || type == MEMORY) {
|
||||
var serviceLibrary = new File('lib/src/models/models.dart');
|
||||
await serviceLibrary.writeAsString("\nexport '$lower.dart';",
|
||||
mode: FileMode.APPEND);
|
||||
await preBuild(Directory.current);
|
||||
}
|
||||
|
||||
await testFile.writeAsString(_generateTests(name, type));
|
||||
|
||||
var runConfig = new File('./.idea/runConfigurations/${name}_Tests.xml');
|
||||
|
||||
if (!await runConfig.exists()) {
|
||||
await runConfig.create(recursive: true);
|
||||
await runConfig.writeAsString(_generateRunConfiguration(name));
|
||||
}
|
||||
|
||||
_pen.green();
|
||||
_pen('${Icon.CHECKMARK} Successfully generated service $name.');
|
||||
_pen();
|
||||
}
|
||||
|
||||
_generateValidator(String name) async {
|
||||
var rc = new ReCase(name);
|
||||
var file = new File('lib/src/validators/${rc.snakeCase}.dart');
|
||||
|
||||
if (!await file.exists()) await file.createSync(recursive: true);
|
||||
|
||||
await file.writeAsString('''
|
||||
import 'package:angel_validate/angel_validate.dart';
|
||||
|
||||
final Validator CREATE_${rc.constantCase} =
|
||||
new Validator({'name*': isString, 'desc*': isString});
|
||||
'''
|
||||
.trim());
|
||||
}
|
||||
|
||||
_generateCustomService(String name) {
|
||||
return '''
|
||||
import 'package:angel_framework/angel_framework.dart';
|
||||
|
||||
class ${name}Service extends Service {
|
||||
${name}Service():super() {
|
||||
// Your logic here!
|
||||
}
|
||||
}
|
||||
'''
|
||||
.trim();
|
||||
}
|
||||
|
||||
_generateMemoryModel(String name) async {
|
||||
var lower = _snake(name);
|
||||
var file = new File('lib/src/models/$lower.dart');
|
||||
|
||||
if (!await file.exists()) await file.createSync(recursive: true);
|
||||
|
||||
await file.writeAsString('''
|
||||
library angel.models.$lower;
|
||||
|
||||
import 'package:angel_framework/common.dart';
|
||||
|
||||
class $name extends Model {
|
||||
String name, desc;
|
||||
|
||||
$name({String id, this.name, this.desc}) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
'''
|
||||
.trim());
|
||||
}
|
||||
|
||||
_generateMemoryModelJson(String name) async {
|
||||
var lower = _snake(name);
|
||||
var file = new File('lib/src/models/$lower.dart');
|
||||
|
||||
if (!await file.exists()) await file.createSync(recursive: true);
|
||||
|
||||
await file.writeAsString('''
|
||||
library angel.models.$lower;
|
||||
|
||||
import 'package:angel_framework/common.dart';
|
||||
import 'package:source_gen/generators/json_serializable.dart';
|
||||
|
||||
part '$lower.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
class $name extends Model with _\$${name}SerializerMixin {
|
||||
@JsonKey('id')
|
||||
@override
|
||||
String id;
|
||||
|
||||
@JsonKey('name')
|
||||
String name;
|
||||
|
||||
@JsonKey('desc')
|
||||
String desc;
|
||||
|
||||
factory $name.fromJson(Map json) => _\$${name}FromJson(json);
|
||||
|
||||
$name({this.id, this.name, this.desc});
|
||||
}
|
||||
'''
|
||||
.trim());
|
||||
}
|
||||
|
||||
_generateMemoryService(String name) {
|
||||
var rc = new ReCase(name);
|
||||
var lower = rc.snakeCase;
|
||||
|
||||
return '''
|
||||
import 'package:angel_framework/angel_framework.dart';
|
||||
import '../models/$lower.dart';
|
||||
export '../models/$lower.dart';
|
||||
|
||||
/// Manages [$name] in-memory.
|
||||
class ${name}Service extends MemoryService<$name> {
|
||||
${name}Service():super() {
|
||||
// Your logic here!
|
||||
}
|
||||
}
|
||||
'''
|
||||
.trim();
|
||||
}
|
||||
|
||||
_generateMongoModel(String name) async {
|
||||
var lower = _snake(name);
|
||||
var file = new File('lib/src/models/$lower.dart');
|
||||
|
||||
if (!await file.exists()) await file.createSync(recursive: true);
|
||||
|
||||
await file.writeAsString('''
|
||||
library angel.models.$lower;
|
||||
|
||||
import 'package:angel_mongo/model.dart';
|
||||
import 'package:source_gen/generators/json_serializable.dart';
|
||||
|
||||
part '$lower.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
class $name extends Model with _\$${name}SerializerMixin {
|
||||
@JsonKey('id')
|
||||
@override
|
||||
String id;
|
||||
|
||||
@JsonKey('name')
|
||||
String name;
|
||||
|
||||
@JsonKey('desc')
|
||||
String desc;
|
||||
|
||||
factory $name.fromJson(Map json) => _\$${name}FromJson(json);
|
||||
|
||||
$name({this.id, this.name, this.desc});
|
||||
}
|
||||
'''
|
||||
.trim());
|
||||
}
|
||||
|
||||
_generateMongoModelJson(String name) async {
|
||||
var lower = _snake(name);
|
||||
var file = new File('lib/src/models/$lower.dart');
|
||||
|
||||
if (!await file.exists()) await file.createSync(recursive: true);
|
||||
|
||||
await file.writeAsString('''
|
||||
library angel.models.$lower;
|
||||
|
||||
import 'package:angel_framework/common.dart';
|
||||
import 'package:source_gen/generators/json_serializable.dart';
|
||||
|
||||
part '$lower.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
class $name extends Model with _\$${name}SerializerMixin {
|
||||
@JsonKey('id')
|
||||
@override
|
||||
String id;
|
||||
|
||||
@JsonKey('name')
|
||||
String name;
|
||||
|
||||
@JsonKey('desc')
|
||||
String desc;
|
||||
|
||||
factory $name.fromJson(Map json) => _\$${name}FromJson(json);
|
||||
|
||||
$name({this.id, this.name, this.desc});
|
||||
}
|
||||
'''
|
||||
.trim());
|
||||
}
|
||||
|
||||
_generateMongoService(String name) {
|
||||
var lower = _snake(name);
|
||||
|
||||
return '''
|
||||
import 'package:angel_framework/angel_framework.dart';
|
||||
import 'package:angel_mongo/angel_mongo.dart';
|
||||
import 'package:angel_validate/angel_validate.dart';
|
||||
import 'package:angel_validate/server.dart';
|
||||
import 'package:mongo_dart/mongo_dart.dart';
|
||||
|
||||
final Validator ${lower}Schema = new Validator({
|
||||
'name*': [isString, isNotEmpty],
|
||||
'desc*': [isString, isNotEmpty]
|
||||
});
|
||||
|
||||
configureServer(Db db) {
|
||||
return (Angel app) async {
|
||||
app.use('/api/${lower}s', new ${name}Service(db.collection('${lower}s')));
|
||||
|
||||
HookedService service = app.service('api/${lower}s');
|
||||
app.container.singleton(service.inner);
|
||||
|
||||
service
|
||||
..beforeCreate.listen(validateEvent(${lower}Schema))
|
||||
..beforeUpdate.listen(validateEvent(${lower}Schema));
|
||||
};
|
||||
}
|
||||
|
||||
/// Manages [$name] in the database.
|
||||
class ${name}Service extends MongoService {
|
||||
${name}Service(collection):super(collection) {
|
||||
// Your logic here!
|
||||
}
|
||||
}
|
||||
'''
|
||||
.trim();
|
||||
}
|
||||
|
||||
_generateMongoTypedService(String name) {
|
||||
var lower = _snake(name);
|
||||
|
||||
return '''
|
||||
import 'package:angel_framework/angel_framework.dart';
|
||||
import 'package:angel_mongo/angel_mongo.dart';
|
||||
import 'package:mongo_dart/mongo_dart.dart';
|
||||
import '../models/$lower.dart';
|
||||
export '../models/$lower.dart';
|
||||
|
||||
configureServer(Db db) {
|
||||
return (Angel app) async {
|
||||
app.use('/api/${lower}s', new ${name}Service(db.collection('${lower}s')));
|
||||
|
||||
HookedService service = app.service('api/${lower}s');
|
||||
app.container.singleton(service.inner);
|
||||
};
|
||||
}
|
||||
|
||||
/// Manages [$name] in the database.
|
||||
class ${name}Service extends MongoTypedService<$name> {
|
||||
${name}Service(collection):super(collection) {
|
||||
// Your logic here!
|
||||
}
|
||||
}
|
||||
'''
|
||||
.trim();
|
||||
}
|
||||
|
||||
_generateRunConfiguration(String name) {
|
||||
var lower = _snake(name);
|
||||
|
||||
return '''
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="$name Tests" type="DartTestRunConfigurationType" factoryName="Dart Test" singleton="true">
|
||||
<option name="filePath" value="\$PROJECT_DIR\$/test/services/${lower}_test.dart" />
|
||||
<method />
|
||||
</configuration>
|
||||
</component>
|
||||
'''
|
||||
.trim();
|
||||
}
|
||||
|
||||
_generateTests(String name, String type) {
|
||||
var lower = _snake(name);
|
||||
|
||||
return '''
|
||||
import 'dart:io';
|
||||
import 'package:angel/angel.dart';
|
||||
import 'package:angel_framework/angel_framework.dart';
|
||||
import 'package:angel_test/angel_test.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
main() async {
|
||||
Angel app;
|
||||
TestClient client;
|
||||
|
||||
setUp(() async {
|
||||
app = await createServer();
|
||||
client = await connectTo(app);
|
||||
});
|
||||
|
||||
tearDown(() async {
|
||||
await client.close();
|
||||
app = null;
|
||||
});
|
||||
|
||||
test('index via REST', () async {
|
||||
var response = await client.get('/api/${lower}s');
|
||||
expect(response, hasStatus(HttpStatus.OK));
|
||||
});
|
||||
|
||||
test('Index ${lower}s', () async {
|
||||
var ${lower}s = await client.service('api/${lower}s').index();
|
||||
print(${lower}s);
|
||||
});
|
||||
}
|
||||
|
||||
'''
|
||||
.trim();
|
||||
}
|
||||
}
|
|
@ -2,13 +2,15 @@ author: "Tobe O <thosakwe@gmail.com>"
|
|||
description: "Command-line tools for the Angel framework."
|
||||
homepage: "https://github.com/angel-dart/angel_cli"
|
||||
name: "angel_cli"
|
||||
version: "1.0.0"
|
||||
version: "1.0.1"
|
||||
dependencies:
|
||||
analyzer: "^0.29.0"
|
||||
args: "^0.13.7"
|
||||
code_builder: "^1.0.0-alpha"
|
||||
console: "^2.2.3"
|
||||
glob: "^1.1.0"
|
||||
id: "^1.0.0"
|
||||
inflection: "^0.4.1"
|
||||
pubspec: "^0.0.14"
|
||||
random_string: "^0.0.1"
|
||||
recase: "^1.0.0"
|
||||
|
|
Loading…
Reference in a new issue