generateClient method
Returns the generated client source for schema.
If schemaSource is provided, a // schema-hash: comment is embedded in
the file header. The CLI uses this to skip re-writing the output file when
the schema hasn't changed (incremental generation, see 5.3).
Implementation
String generateClient(SchemaDocument schema, {String? schemaSource}) {
final effectiveSchema = schema.withoutIgnored();
final imports = <String>[
"import 'package:comon_orm/comon_orm.dart';",
...options.additionalImports,
];
final buffer = StringBuffer()
..writeln('// Generated code. Do not edit by hand.')
..writeln(
'// ignore_for_file: unused_element, non_constant_identifier_names',
);
if (schemaSource != null) {
final hash = sha256.convert(utf8.encode(schemaSource)).toString();
buffer.writeln('// schema-hash: $hash');
}
buffer
..writeln(imports.join('\n'))
..writeln();
if (schemaSource != null) {
buffer
..writeln(
'const String _comonOrmGeneratedSchemaSource = ${jsonEncode(schemaSource)};',
)
..writeln();
}
buffer
..writeln()
..writeln('class ComonOrm {')
..writeln(' ComonOrm({')
..writeln(' required DatabaseAdapter adapter,')
..writeln(
' List<DatabaseMiddleware> middlewares = const <DatabaseMiddleware>[],',
)
..writeln(' QueryLogWriter? logger,')
..writeln(' })')
..writeln(
' : _client = ComonOrmClient(adapter: adapter, schemaView: runtimeSchemaView, middlewares: middlewares, logger: logger);',
)
..writeln()
..writeln(' ComonOrm._fromClient(this._client);')
..writeln()
..writeln(
' static const GeneratedRuntimeSchema runtimeSchema = _ComonOrmRuntimeMetadata.schema;',
)
..writeln()
..writeln(' static final RuntimeSchemaView runtimeSchemaView =')
..writeln(' runtimeSchemaViewFromGeneratedSchema(runtimeSchema);')
..writeln()
..writeln(' static InMemoryDatabaseAdapter createInMemoryAdapter() {')
..writeln(' return InMemoryDatabaseAdapter.fromGeneratedSchema(')
..writeln(' schema: runtimeSchema,')
..writeln(' );')
..writeln(' }')
..writeln()
..writeln(' factory ComonOrm.inMemory({')
..writeln(
' List<DatabaseMiddleware> middlewares = const <DatabaseMiddleware>[],',
)
..writeln(' QueryLogWriter? logger,')
..writeln(' }) {')
..writeln(
' return ComonOrm(adapter: createInMemoryAdapter(), middlewares: middlewares, logger: logger);',
)
..writeln(' }')
..writeln()
..writeln(' static Future<void> _migrateWithAdapter({')
..writeln(' required DatabaseAdapter adapter,')
..writeln(' required MigrationReader migrations,')
..writeln(' }) async {')
..writeln(' if (adapter is! MigrationCapableDatabaseAdapter) {')
..writeln(
' throw StateError(\'Adapter \${adapter.runtimeType} does not support runtime migrations.\');',
)
..writeln(' }')
..writeln(' final executor = adapter.createMigrationExecutor();')
..writeln(' final artifacts = await migrations.loadAll();')
..writeln(' await executor.applyPending(artifacts);')
..writeln(' }')
..writeln();
for (final member in options.additionalClassMembers) {
buffer
..writeln(member)
..writeln();
}
if (options.emitDefaultMigrateMethod) {
buffer
..writeln(' static Future<void> migrate({')
..writeln(' required DatabaseAdapter adapter,')
..writeln(' required MigrationReader migrations,')
..writeln(' }) {')
..writeln(
' return _migrateWithAdapter(adapter: adapter, migrations: migrations);',
)
..writeln(' }')
..writeln();
}
buffer.writeln(' final ComonOrmClient _client;');
buffer
..writeln()
..writeln(' void reset() {')
..writeln(' _client.reset();')
..writeln(' }')
..writeln()
..writeln(' void seed(')
..writeln(' Map<String, List<Map<String, Object?>>> data, {')
..writeln(' bool replace = false,')
..writeln(' }) {')
..writeln(' _client.seed(data, replace: replace);')
..writeln(' }')
..writeln();
for (final model in effectiveSchema.models) {
final delegateName = '${model.name}Delegate';
final propertyName = _lowercaseFirst(model.name);
buffer.writeln(
' late final $delegateName $propertyName = $delegateName._(_client);',
);
}
buffer
..writeln()
..writeln(' Future<T> transaction<T>(')
..writeln(' Future<T> Function(ComonOrm tx) action,')
..writeln(' ) {')
..writeln(
' return _client.transaction((tx) => action(ComonOrm._fromClient(tx)));',
)
..writeln(' }')
..writeln()
..writeln(' Future<List<T>> batch<T>(')
..writeln(' List<Future<T> Function(ComonOrm tx)> operations,')
..writeln(' ) {')
..writeln(' if (operations.isEmpty) {')
..writeln(' return Future<List<T>>.value(<T>[]);')
..writeln(' }')
..writeln(' return _client.batch<T>(')
..writeln(' operations')
..writeln(' .map(')
..writeln(
' (operation) => (ComonOrmClient tx) => operation(ComonOrm._fromClient(tx)),',
)
..writeln(' )')
..writeln(' .toList(growable: false),')
..writeln(' );')
..writeln(' }')
..writeln()
..writeln(' Future<void> close() async {')
..writeln(' await _client.close();')
..writeln(' }')
..writeln('}')
..writeln();
for (final declaration in options.additionalDeclarations) {
buffer
..writeln(declaration)
..writeln();
}
_writeGeneratedRuntimeMetadata(buffer, effectiveSchema);
for (final definition in effectiveSchema.enums) {
_writeEnumClass(buffer, definition);
}
_writeScalarUpdateOperationHelpers(buffer);
for (final model in effectiveSchema.models) {
_writeModelClass(buffer, effectiveSchema, model);
}
for (final model in effectiveSchema.models) {
_writeDelegate(buffer, effectiveSchema, model);
_writeWhereInput(buffer, effectiveSchema, model);
_writeWhereUniqueInput(buffer, effectiveSchema, model);
_writeOrderByInput(buffer, effectiveSchema, model);
_writeScalarFieldEnum(buffer, effectiveSchema, model);
_writeAggregateInputClasses(buffer, effectiveSchema, model);
_writeAggregateResultClasses(buffer, effectiveSchema, model);
_writeGroupBySupportClasses(buffer, effectiveSchema, model);
_writeInclude(buffer, effectiveSchema, model);
_writeSelect(buffer, effectiveSchema, model);
_writeCreateInput(buffer, effectiveSchema, model);
_writeUpdateInput(buffer, effectiveSchema, model);
_writeUpsertManyInput(buffer, model);
_writeCreateWithoutInputs(buffer, effectiveSchema, model);
_writeConnectOrCreateInputs(buffer, effectiveSchema, model);
_writeNestedCreateInputs(buffer, effectiveSchema, model);
_writeNestedUpdateInputs(buffer, effectiveSchema, model);
}
buffer
..writeln('DateTime? _asDateTime(Object? value) {')
..writeln(' if (value is DateTime) {')
..writeln(' return value;')
..writeln(' }')
..writeln(' if (value is String) {')
..writeln(' return DateTime.tryParse(value);')
..writeln(' }')
..writeln(' return null;')
..writeln('}')
..writeln()
..writeln('double? _asDouble(Object? value) {')
..writeln(' if (value is num) {')
..writeln(' return value.toDouble();')
..writeln(' }')
..writeln(' return null;')
..writeln('}')
..writeln()
..writeln('List<int>? _asBytes(Object? value) {')
..writeln(' if (value is List<int>) {')
..writeln(' return value;')
..writeln(' }')
..writeln(' if (value is List<Object?>) {')
..writeln(' return value.whereType<int>().toList(growable: false);')
..writeln(' }')
..writeln(' return null;')
..writeln('}')
..writeln()
..writeln('BigInt? _asBigInt(Object? value) {')
..writeln(' if (value is BigInt) {')
..writeln(' return value;')
..writeln(' }')
..writeln(' if (value is int) {')
..writeln(' return BigInt.from(value);')
..writeln(' }')
..writeln(' if (value is String) {')
..writeln(' return BigInt.tryParse(value);')
..writeln(' }')
..writeln(' return null;')
..writeln('}')
..writeln()
..writeln('String? _enumName(Object? value) {')
..writeln(' if (value is Enum) {')
..writeln(' return value.name;')
..writeln(' }')
..writeln(' return null;')
..writeln('}')
..writeln()
..writeln('class _Undefined {')
..writeln(' const _Undefined();')
..writeln('}')
..writeln()
..writeln('const Object _undefined = _Undefined();')
..writeln()
..writeln('bool _deepEquals(Object? left, Object? right) {')
..writeln(' if (identical(left, right)) {')
..writeln(' return true;')
..writeln(' }')
..writeln(' if (left is List<Object?> && right is List<Object?>) {')
..writeln(' if (left.length != right.length) {')
..writeln(' return false;')
..writeln(' }')
..writeln(' for (var index = 0; index < left.length; index++) {')
..writeln(' if (!_deepEquals(left[index], right[index])) {')
..writeln(' return false;')
..writeln(' }')
..writeln(' }')
..writeln(' return true;')
..writeln(' }')
..writeln(
' if (left is Map<Object?, Object?> && right is Map<Object?, Object?>) {',
)
..writeln(' if (left.length != right.length) {')
..writeln(' return false;')
..writeln(' }')
..writeln(' for (final entry in left.entries) {')
..writeln(' if (!right.containsKey(entry.key)) {')
..writeln(' return false;')
..writeln(' }')
..writeln(' if (!_deepEquals(entry.value, right[entry.key])) {')
..writeln(' return false;')
..writeln(' }')
..writeln(' }')
..writeln(' return true;')
..writeln(' }')
..writeln(' return left == right;')
..writeln('}')
..writeln()
..writeln('int _deepHash(Object? value) {')
..writeln(' if (value is List<Object?>) {')
..writeln(' return Object.hashAll(value.map(_deepHash));')
..writeln(' }')
..writeln(' if (value is Map<Object?, Object?>) {')
..writeln(' final entries = value.entries')
..writeln(
' .map((entry) => Object.hash(_deepHash(entry.key), _deepHash(entry.value)))',
)
..writeln(' .toList(growable: false)')
..writeln(' ..sort();')
..writeln(' return Object.hashAll(entries);')
..writeln(' }')
..writeln(' return value.hashCode;')
..writeln('}')
..writeln()
..writeln('Object? _jsonEncodable(Object? value) {')
..writeln(
' if (value == null || value is String || value is num || value is bool) {',
)
..writeln(' return value;')
..writeln(' }')
..writeln(' if (value is DateTime) {')
..writeln(' return value.toIso8601String();')
..writeln(' }')
..writeln(' if (value is BigInt) {')
..writeln(' return value.toString();')
..writeln(' }')
..writeln(' if (value is Enum) {')
..writeln(' return value.name;')
..writeln(' }')
..writeln(' if (value is List<Object?>) {')
..writeln(' return value.map(_jsonEncodable).toList(growable: false);')
..writeln(' }')
..writeln(' if (value is Map<Object?, Object?>) {')
..writeln(' final json = <String, Object?>{};')
..writeln(' for (final entry in value.entries) {')
..writeln(
' json[entry.key.toString()] = _jsonEncodable(entry.value);',
)
..writeln(' }')
..writeln(' return Map<String, Object?>.unmodifiable(json);')
..writeln(' }')
..writeln(' return value;')
..writeln('}')
..writeln()
..writeln('Object? _requireRecordValue(')
..writeln(' Map<String, Object?> record,')
..writeln(' String field,')
..writeln(' String context,')
..writeln(') {')
..writeln(' final value = record[field];')
..writeln(' if (value == null) {')
..writeln(' throw StateError(')
..writeln(" 'Missing required key \"\$field\" for \$context.',")
..writeln(' );')
..writeln(' }')
..writeln(' return value;')
..writeln('}')
..writeln()
..writeln('bool _isSkippableDuplicateError(Object error) {')
..writeln(' final code = _errorCode(error);')
..writeln(" if (code == '23505') {")
..writeln(' return true;')
..writeln(' }')
..writeln(' final normalized = error.toString().toLowerCase();')
..writeln(
" return normalized.contains('duplicate key value violates unique constraint') ||",
)
..writeln(" normalized.contains('unique constraint failed') ||")
..writeln(" normalized.contains('unique violation');")
..writeln('}')
..writeln()
..writeln('String? _errorCode(Object error) {')
..writeln(' try {')
..writeln(' final dynamicError = error as dynamic;')
..writeln(' final code = dynamicError.code;')
..writeln(' return code is String ? code : null;')
..writeln(' } catch (_) {')
..writeln(' return null;')
..writeln(' }')
..writeln('}')
..writeln();
return buffer.toString();
}