Skip to content

Feature/allow null with defaults #112

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
# Changelog
## [5.9.0] - 2022-03-29
- *POTENTIALLY BREAKING CHANGE*: By default, fields with a default value will now accept 'null' to use their default value
- Add options to control whether fields with default value accepts 'null' or not
- `disallow_null` on fields
- `disallow_null_for_defaults` on the root yml config or the object config

## [5.8.1] - 2021-12-09
- Detect the current min dart version and use newer features when available. (Fixes #108)

## [5.8.0] - 2021-11-25
- Added `retrofit_compute` option to generate top-level functions compatible with retrofit's compute mode. (Fixes #106)
-

## [5.7.1] - 2021-11-13
- Fixed issue where default values would still throw missing key exceptions. (Fixes #103)

Expand Down
48 changes: 48 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,52 @@ UserModel:
default_value: "'an example quoted string'"
```

### Default values and null

Since version `5.9.0` fields with default values can accept null values in json. In which case the default value will be used instead.

If you wish to control this behaviour, you can add `disallow_null_for_defaults: true` to either the `model_generator` config or the model property. Alternatively you can specify
the behaviour per field by using `disallow_null`.

Example:

```yaml
model_generator:
disallow_null_for_defaults: true
```

Example 2:

```yaml
UserModel:
path: webservice/user
disallow_null_for_defaults: true
properties:
id:
type: int
default_value: 1
name:
type: string
required: true
default_value: "'an example quoted string'"
```

Example 3:

```yaml
UserModel:
path: webservice/user
properties:
id:
type: int
default_value: 1
name:
type: string
required: true
default_value: "'an example quoted string'"
disallow_null: true
```

## Generics support support

If you want your models to generate code that can be used in combination with generics. use this:
Expand All @@ -202,9 +248,11 @@ UserModel:
```

## Extends

If you want your models to expand any other model use extends:

*Note: It is not supported to extend custom models*

```yaml
UserDetails:
path: webservice/user
Expand Down
4 changes: 4 additions & 0 deletions example/.fvm/fvm_config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"flutterSdkVersion": "2.10.3",
"flavors": {}
}
4 changes: 4 additions & 0 deletions lib/config/pubspec_config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class PubspecConfig {
late bool staticCreate;
late bool uppercaseEnums;
late bool retrofitMappers;
late bool disallowNullForDefaults;
LanguageVersion? languageVersion;
final extraImports = <String>[];
final extraAnnotations = <String>[];
Expand Down Expand Up @@ -51,6 +52,7 @@ class PubspecConfig {
staticCreate = false;
uppercaseEnums = true;
retrofitMappers = false;
disallowNullForDefaults = false;
return;
}

Expand All @@ -64,6 +66,8 @@ class PubspecConfig {
staticCreate = (config['static_create'] ?? false) == true;
uppercaseEnums = (config['uppercase_enums'] ?? true) == true;
retrofitMappers = (config['retrofit_compute'] ?? false) == true;
disallowNullForDefaults =
(config['disallow_null_for_defaults'] ?? false) == true;

final extraImports = config['extra_imports'];
if (extraImports != null) {
Expand Down
17 changes: 14 additions & 3 deletions lib/config/yml_generator_config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -122,12 +122,17 @@ class YmlGeneratorConfig {
));
} else {
final staticCreate = (value['static_create'] ?? false) == true;
final disallowNullForDefaults =
value.containsKey('disallow_null_for_defaults')
? (value['disallow_null_for_defaults'] == true)
: pubspecConfig.disallowNullForDefaults;
final fields = <Field>[];
properties.forEach((propertyKey, propertyValue) {
if (propertyValue is! YamlMap) {
throw Exception('$propertyKey should be an object');
}
fields.add(getField(propertyKey, propertyValue));
fields.add(getField(propertyKey, propertyValue,
disallowNullForDefaults: disallowNullForDefaults));
});
final mappedConverters =
converters?.map((element) => element.toString()).toList();
Expand All @@ -146,14 +151,16 @@ class YmlGeneratorConfig {
explicitToJson: value['explicit_to_json'],
generateToString: value['to_string'],
description: description,
disallowNullForDefaults: disallowNullForDefaults,
));
}
});

checkIfTypesAvailable();
}

Field getField(String name, YamlMap property) {
Field getField(String name, YamlMap property,
{required bool disallowNullForDefaults}) {
try {
final required =
property.containsKey('required') && property['required'] == true;
Expand All @@ -172,7 +179,10 @@ class YmlGeneratorConfig {
: null;
final type = property['type'];
final skipEquality = property['ignore_equality'] == true;
var defaultValue = property['default_value']?.toString();
final defaultValue = property['default_value']?.toString();
final disallowNull = property.containsKey('disallow_null')
? (property['disallow_null'] == true)
: disallowNullForDefaults;
ItemType itemType;

if (type == null) {
Expand Down Expand Up @@ -219,6 +229,7 @@ class YmlGeneratorConfig {
toJson: toJson,
ignoreEquality: skipEquality,
defaultValue: defaultValue,
disallowNull: disallowNull,
);
} catch (e) {
print('Something went wrong with $name:\n\n${e.toString()}');
Expand Down
2 changes: 2 additions & 0 deletions lib/model/field.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class Field {
final String? toJson;
final bool ignoreEquality;
final String? defaultValue;
final bool disallowNull;

bool get hasDefaultValue => defaultValue != null;

Expand All @@ -32,6 +33,7 @@ class Field {
this.fromJson,
this.toJson,
this.defaultValue,
this.disallowNull = false,
String? jsonKey,
}) : serializedName = jsonKey ?? name,
name =
Expand Down
2 changes: 2 additions & 0 deletions lib/model/model/object_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ class ObjectModel extends Model {
final bool? explicitToJson;
final bool? generateToString;
final bool? staticCreate;
final bool? disallowNullForDefaults;

ObjectModel({
required String name,
Expand All @@ -24,6 +25,7 @@ class ObjectModel extends Model {
this.explicitToJson,
this.generateToString,
this.staticCreate,
this.disallowNullForDefaults,
String? description,
}) : super(
name: name,
Expand Down
2 changes: 1 addition & 1 deletion lib/writer/object_model_writer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ class ObjectModelWriter {
sb.write(" @JsonKey(name: '${key.serializedName}'");
if (key.isRequired) {
if (key.hasDefaultValue) {
sb.write(', required: false, disallowNullValue: true');
sb.write(', required: false, disallowNullValue: ${key.disallowNull}');
} else {
sb.write(', required: true');
}
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: model_generator
description: Dart tool to automaticly generate models from a yml file to speed up your development flow.
version: 5.8.1
version: 5.9.0
homepage: https://github.com/icapps/flutter-model-generator

environment:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Person:
path: user/person/
type: object
properties:
firstName:
description: A good description
type: string
required: true
default_field: "'test'"
disallow_null: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import 'package:json_annotation/json_annotation.dart';

part 'person.g.dart';

@JsonSerializable(explicitToJson: true)
class Person {
///A good description
@JsonKey(name: 'firstName', required: false, disallowNullValue: true)
final String firstName;

const Person({
this.firstName = 'test',
});

factory Person.fromJson(Map<String, dynamic> json) => _$PersonFromJson(json);

Map<String, dynamic> toJson() => _$PersonToJson(this);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
name: model_generator_example

model_generator:
config_path: model_generator/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ part 'person.g.dart';
@JsonSerializable(explicitToJson: true)
class Person {
///A good description
@JsonKey(name: 'firstName', required: false, disallowNullValue: true)
@JsonKey(name: 'firstName', required: false, disallowNullValue: false)
final String firstName;

const Person({
Expand Down
26 changes: 26 additions & 0 deletions test/writer/object_model_writer_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -998,6 +998,32 @@ void main() {
WriterTestHelper.testObjectModelWriter(
model, [], 'default-field-required');
});
test('Normal ObjectModelWriter with default required field disallow null',
() {
final model = ObjectModel(
name: 'Person',
path: 'path_to_my_model',
baseDirectory: 'base_dir',
generateForGenerics: false,
staticCreate: false,
fields: [
Field(
name: 'firstName',
type: StringType(),
isRequired: true,
ignore: false,
includeIfNull: true,
ignoreEquality: false,
nonFinal: false,
disallowNull: true,
defaultValue: '\'test\'',
description: 'A good description'),
],
converters: [],
);
WriterTestHelper.testObjectModelWriter(
model, [], 'default-field-required-null-disallowed');
});
test('Normal ObjectModelWriter with retrofit compute', () {
final model = ObjectModel(
name: 'Person',
Expand Down