generateModel<T extends Object?> method
Generate models for the data classes file.
Implementation
void generateModel<T extends Object?>(
final StringBuffer buffer,
final ClassModel model,
) {
final String comparable = model.fields.any((final _) => _.compare)
? ' implements Comparable<${model.name}>'
: '';
final String doc =
model.doc == null ? 'The model of a `${model.key}`.' : model.doc!;
final bool isConst = model.fields.every(
(final _) =>
(_.type != FieldType.$datetime && _.type != FieldType.$$datetime) ||
_.$default == null,
);
buffer
..writeDoc(doc, indent: 2)
..writeln('@sealed')
..writeln('@immutable')
..writeln('class ${model.name}$comparable {')
/// `constructor`
..writeDoc(doc, indent: 4)
..writeFunction(
'${isConst ? 'const ' : ''}${model.name}',
bracketFields: <String>[
for (final FieldModel field in model.fields)
(final FieldModel field) {
final String $default = _renderDefault(model, field);
final String $field = field.required ? 'required ' : '';
return $field +
($default.isNotEmpty
? 'final '
'${_renderType(model, field, nullable: true)} '
'${field.name}'
: 'this.${field.name}');
}(field)
]..sort(
(final String a, final String b) =>
(b.startsWith('required') ? 1 : -1)
.compareTo(a.startsWith('required') ? 1 : -1),
),
outerFields: <String?>[
for (final FieldModel field in model.fields)
(final String $default) {
if ($default.isNotEmpty) {
return '${field.name} = ${field.name} ?? ${$default}';
} else {
return null;
}
}(_renderDefault(model, field))
].whereType(),
)
..writeln();
/// `keys`
if (model.staticKeys) {
buffer
..writeDoc('The key of this [${model.name}].', indent: 2)
..writeln("static const String \$ = '${model.key}';");
for (final FieldModel field in model.fields) {
buffer
..writeDoc(
'The key of `[${field.name}]` property of this [${model.name}].',
indent: 2,
)
..writeln("static const String \$${field.name} = '${field.key}';");
}
}
/// `fields`
for (final FieldModel field in model.fields) {
buffer
..writeDoc(
field.doc == null
? 'The `${field.key}` property of this [${model.name}].'
: field.doc!,
indent: 2,
)
..writeln('final ${_renderType(model, field)} ${field.name};');
}
/// `copyWith`
if (model.fields.any((final _) => _.copy)) {
buffer
..writeDoc('Return the copy of this model.', indent: 2)
..writeFunction(
'${model.name} copyWith',
bracketFields: <String>[
for (final FieldModel field in model.fields)
if (field.copy)
'''final ${_renderType(model, field, nullable: true)} ${field.name}'''
],
bodyConstructor: model.name,
bodyFields: <String>[
for (final FieldModel field in model.fields)
if (field.copy)
'${field.name}: ${field.name} ?? this.${field.name}'
else if (field.required)
'${field.name}: ${field.name}'
],
);
}
/// `copyWithNull`
if (model.fields.any((final _) => _.nullable && _.copy)) {
buffer
..writeDoc(
'Return the copy of this model with nullable fields.',
indent: 2,
)
..writeFunction(
'${model.name} copyWithNull',
bracketFields: <String>[
for (final FieldModel field in model.fields)
if (field.nullable && field.copy)
'final bool ${field.name} = false'
],
bodyConstructor: model.name,
bodyFields: <String>[
for (final FieldModel field in model.fields)
if (field.nullable && field.copy)
'${field.name}: ${field.name} ? null : this.${field.name}'
else
'${field.name}: ${field.name}'
],
);
}
buffer
/// `toMap`
..writeDoc(
'Convert this model to map with string keys.',
indent: 2,
)
..writeFunction(
'Map<String, Object?> toMap',
bodyConstructor: '<String, Object?>{',
bodyFields: <String>[
for (final FieldModel field in model.fields)
if (field.serialize != FieldSerialization.none)
(final FieldModel field) {
final String key =
model.staticKeys ? field.staticKey : "'${field.key}'";
final String $field =
'$key: ${renderSerialization(model, field)}';
return field.serialize == FieldSerialization.nonNull &&
field.nullable
? 'if (${field.name} != null) ${$field}'
: $field;
}(field)
],
)
/// `fromMap`
..writeDoc('Convert the map with string keys to this model.', indent: 2)
..writeFunction(
'factory ${model.name}.fromMap',
fields: <String>['final Map<String, Object?> map'],
bodyConstructor: (model.fields.isEmpty ? 'const ' : '') + model.name,
bodyFields: <String>[
for (final FieldModel field in model.fields)
if (field.deserialize || field.required)
'${field.name}: ${renderDeserialization(model, field)}'
],
);
if (model.toJson) {
buffer
/// `toJson`
..writeDoc('Convert this model to a json string.', indent: 2)
..writeFunction(
'String toJson',
bodyConstructor: 'json.encode',
bodyFields: <String>['toMap()'],
)
/// `fromJson`
..writeDoc('Convert the json string to this model.', indent: 2)
..writeFunction(
'factory ${model.name}.fromJson',
fields: <String>['final String source'],
bodyConstructor: '${model.name}.fromMap',
bodyFields: <String>['json.decode(source)! as Map<String, Object?>'],
);
}
/// `compareTo`
final List<String> compareFields = <String>[
for (final FieldModel field in model.fields)
if (field.compare)
if (field.nullable)
'${field.name} != null && other.${field.name} != null ? '
'${field.name}!.compareTo(other.${field.name}!) : 0'
else
'${field.name}.compareTo(other.${field.name})'
];
if (compareFields.isEmpty) {
} else if (compareFields.length == 1) {
buffer
..writeln()
..writeln('@override')
..writeFunction(
'int compareTo',
fields: <String>['final ${model.name} other'],
bodyFields: compareFields,
separator: '',
);
} else {
buffer
..writeln()
..writeln('@override')
..writeln('int compareTo(final ${model.name} other) {')
..writeln('int value;');
for (int index = 0; index < compareFields.length; index++) {
if (index > 0) {
buffer.write(' else ');
}
buffer.writeln(
'if ((value = ${compareFields.elementAt(index)}) != 0) {}',
);
}
buffer
..writeln('return value;')
..writeln('}');
}
/// `equality`
if (model.fields.any((final _) => _.equality != FieldEquality.none)) {
buffer
..writeln()
/// `==` operator
..writeln('@override')
..writeFunction(
'bool operator ==',
fields: <String>['final Object? other'],
bodyFields: <String>[
'identical(this, other) ||other is ${model.name}',
for (final FieldModel field in model.fields)
if (field.equality != FieldEquality.none)
if (field.type.name.startsWith(r'$$'))
(final FieldModel field) {
final String equality =
field.equality == FieldEquality.ordered
? 'IterableEquality'
: 'UnorderedIterableEquality';
return 'const $equality'
'<${_renderType(model, field, iterable: false)}>()'
'.equals(other.${field.name}, ${field.name},)';
}(field)
else
'other.${field.name} == ${field.name}'
],
separator: ' && ',
)
..writeln()
/// `hashCode`
..writeln('@override')
..writeFunction(
'int get hashCode',
bodyFields: <String>[
for (final FieldModel field in model.fields)
if (field.equality != FieldEquality.none)
(final FieldModel field) {
if (!field.type.isIterable) {
return '${field.name}.hashCode';
}
final bool needsParanthesis = field.nullable &&
model.fields
.where(
(final FieldModel field) =>
field.equality != FieldEquality.none,
)
.length >
1;
String hash = field.equality == FieldEquality.unordered
? 'Object.hashAllUnordered'
: 'Object.hashAll';
hash = field.nullable
? '${field.name} == null ? ${field.name}.hashCode : '
'$hash(${field.name}!)'
: '$hash(${field.name})';
return needsParanthesis ? '($hash)' : hash;
}(field)
],
separator: ' ^ ',
);
}
/// `toString`
buffer
..writeln()
..writeln('@override')
..writeFunction(
'String toString',
bodyConstructor:
"'${model.name.startsWith(r'$') ? r'\' : ''}${model.name}(",
bodyFields: <String>[
for (final FieldModel field in model.fields)
if (field.$toString) '${field.name}: \$${field.name}'
],
)
..writeln('}');
}