dvStudioModelDartSource function
The @DVModel spec compiles back from, as a file in lib/models.
Every rule the definition carries is written as the annotation that
declares it, so the generator reads the same spec back: the key first,
choices as an enum, validation as @DVModel.validate, uniqueness as
@DVModel.uniqueField, indexes and access on the model.
Implementation
String dvStudioModelDartSource(DVStudioModelSpec spec) {
String quote(String value) =>
"'${value.replaceAll(r'\', r'\\').replaceAll("'", r"\'").replaceAll(r'$', r'\$')}'";
final StringBuffer out = StringBuffer()
..writeln(dvStudioModelSourceMarker)
..writeln('// Studio rewrites this file while that line is first. Delete the')
..writeln('// line to take the model over by hand; Studio then leaves it be.')
..writeln("import 'package:dartvel_core/dartvel.dart';")
..writeln();
final Set<String> enums = <String>{};
for (final DVStudioFieldSpec field in spec.fields) {
final List<String>? options = field.options;
if (options == null) continue;
final String type = dvStudioBaseType(field.type);
if (!enums.add(type)) continue;
out
..writeln('enum $type { ${options.join(', ')} }')
..writeln();
}
final List<String> arguments = <String>[
// A designed model has no page of its own until one is designed for it.
'generatePages: false',
if (!spec.versioned) 'version: false',
if (spec.softDelete) 'softDelete: true',
if (spec.access case final DVModelAccess access)
'access: DVModelAccess('
'view: DVAccess.${access.view.name}, '
'create: DVAccess.${access.create.name}, '
'update: DVAccess.${access.update.name}, '
'delete: DVAccess.${access.delete.name})',
if (spec.indexes.isNotEmpty)
'indexes: <DVIndex>[${<String>[
for (final DVStudioIndexSpec index in spec.indexes)
'DVIndex(<String>[${index.fields.map(quote).join(', ')}]'
'${index.unique ? ', unique: true' : ''})',
].join(', ')}]',
];
out
..writeln('@DVModel(')
..writeln(<String>[for (final String a in arguments) ' $a,'].join('\n'))
..writeln(')')
..writeln("@pragma('vm:entry-point')")
..writeln('class const _${spec.model}({');
final List<DVStudioFieldSpec> ordered = <DVStudioFieldSpec>[
...spec.fields.where((DVStudioFieldSpec f) => f.name == spec.key),
...spec.fields.where((DVStudioFieldSpec f) => f.name != spec.key),
];
for (final DVStudioFieldSpec field in ordered) {
final List<String> rules = <String>[
if (field.min != null) 'min: ${_number(field.min!)}',
if (field.max != null) 'max: ${_number(field.max!)}',
if (field.minLength != null) 'minLength: ${field.minLength}',
if (field.maxLength != null) 'maxLength: ${field.maxLength}',
if (field.pattern != null) 'pattern: ${quote(field.pattern!)}',
];
if (field.unique) out.writeln(' @DVModel.uniqueField()');
if (rules.isNotEmpty) {
out.writeln(' @DVModel.validate(${rules.join(', ')})');
}
final String type = field.type;
out.writeln(
field.nullable
? ' final $type ${field.name},'
: ' required final $type ${field.name},',
);
}
out.writeln('});');
return out.toString();
}