141 lines
4.1 KiB
Dart
141 lines
4.1 KiB
Dart
import 'dart:math';
|
|
import 'package:angel_framework/angel_framework.dart';
|
|
import 'package:faker/faker.dart';
|
|
export 'package:faker/faker.dart';
|
|
|
|
/// Generates data using a [Faker].
|
|
typedef FakerCallback = Function(Faker faker);
|
|
|
|
/// Used to seed nested objects.
|
|
typedef SeederCallback<T> = Function(T created,
|
|
Function(Pattern path, SeederConfiguration configuration, {bool? verbose}));
|
|
|
|
/// Seeds the given service in development.
|
|
AngelConfigurer seed<T>(
|
|
Pattern servicePath,
|
|
SeederConfiguration<T> configuration, {
|
|
bool verbose = false,
|
|
}) {
|
|
return (Angel app) async {
|
|
if (configuration.runInProduction != true) return;
|
|
|
|
if (!app.services.containsKey(servicePath)) {
|
|
throw ArgumentError(
|
|
"App does not contain a service at path '$servicePath'.");
|
|
}
|
|
|
|
if (configuration.disabled == true) {
|
|
print("Service '$servicePath' will not be seeded.");
|
|
return;
|
|
}
|
|
|
|
var service = app.findService(servicePath);
|
|
var faker = Faker();
|
|
|
|
Map _buildTemplate(Map data) {
|
|
return data.keys.fold({}, (map, key) {
|
|
var value = data[key];
|
|
|
|
if (value is FakerCallback) {
|
|
return map..[key] = value(faker);
|
|
} else if (value is Function) {
|
|
return map..[key] = value();
|
|
} else if (value is Map) {
|
|
return map..[key] = _buildTemplate(value);
|
|
} else {
|
|
return map..[key] = value;
|
|
}
|
|
});
|
|
}
|
|
|
|
Future<Null> Function(SeederConfiguration configuration) _buildSeeder(
|
|
Service? service,
|
|
{bool? verbose}) {
|
|
return (SeederConfiguration configuration) async {
|
|
if (configuration.delete == true) await service!.remove(null);
|
|
|
|
var count = configuration.count;
|
|
var rnd = Random();
|
|
if (count < 1) count = 1;
|
|
|
|
for (var i = 0; i < count; i++) {
|
|
Future _gen(template) async {
|
|
var data = template;
|
|
|
|
if (data is Map) {
|
|
data = _buildTemplate(data);
|
|
} else if (data is Faker) {
|
|
data = template(faker);
|
|
}
|
|
|
|
var params = <String, dynamic>{}..addAll(configuration.params);
|
|
var result = await service!.create(data, params);
|
|
|
|
if (configuration.callback != null) {
|
|
await configuration.callback!(result,
|
|
(Pattern path, SeederConfiguration configuration,
|
|
{bool? verbose}) {
|
|
return _buildSeeder(app.findService(path),
|
|
verbose: verbose == true)(configuration);
|
|
});
|
|
}
|
|
}
|
|
|
|
if (configuration.template != null) {
|
|
await _gen(configuration.template);
|
|
} else if (configuration.templates.isNotEmpty == true) {
|
|
var template = configuration.templates
|
|
.elementAt(rnd.nextInt(configuration.templates.length));
|
|
await _gen(template);
|
|
} else {
|
|
throw ArgumentError(
|
|
'Configuration for service \'$servicePath\' must define at least one template.');
|
|
}
|
|
}
|
|
|
|
if (verbose == true) {
|
|
print('Created $count object(s) in service \'$servicePath\'.');
|
|
}
|
|
};
|
|
}
|
|
|
|
await _buildSeeder(service, verbose: verbose == true)(configuration);
|
|
};
|
|
}
|
|
|
|
/// Configures the seeder.
|
|
class SeederConfiguration<T> {
|
|
/// Optional callback on creation.
|
|
final SeederCallback<T>? callback;
|
|
|
|
/// Number of objects to seed.
|
|
final int count;
|
|
|
|
/// If `true`, all records in the service are deleted before seeding.
|
|
final bool delete;
|
|
|
|
/// If `true`, seeding will not occur.
|
|
final bool disabled;
|
|
|
|
/// Optional service parameters to be passed.
|
|
final Map<String, dynamic> params;
|
|
|
|
/// Unless this is `true`, the seeder will not run in production.
|
|
final bool runInProduction;
|
|
|
|
/// A data template to build from.
|
|
final template;
|
|
|
|
/// A set of templates to choose from.
|
|
final Iterable templates;
|
|
|
|
SeederConfiguration(
|
|
{this.callback,
|
|
this.count = 1,
|
|
this.delete = true,
|
|
this.disabled = false,
|
|
this.params = const {},
|
|
this.runInProduction = false,
|
|
this.template,
|
|
this.templates = const []});
|
|
}
|