diff --git a/CHANGELOG.md b/CHANGELOG.md index 1cc5aef..0887a5f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,12 @@ ## Master -* _No changes yet. Don't hesitate to contribute with Pull Requests!_ +* `Decodable` - Add `JSONIgnored` userinfo's attribute (decodable usage only). + [Arnaud Bretagne](https://github.com/abretagne) + [#38](https://github.com/NijiDigital/gyro/pull/38) +* `Decodable` - Handle optional attributes/relationship parsing. + [Arnaud Bretagne](https://github.com/abretagne) + [#38](https://github.com/NijiDigital/gyro/pull/38) ## 1.0.1 diff --git a/lib/gyro/parser/xcdatamodel/attribute.rb b/lib/gyro/parser/xcdatamodel/attribute.rb index 8c9a654..32e69a0 100644 --- a/lib/gyro/parser/xcdatamodel/attribute.rb +++ b/lib/gyro/parser/xcdatamodel/attribute.rb @@ -20,11 +20,12 @@ module XCDataModel class Attribute attr_accessor :entity_name, :name, :type, :optional, :indexed, :default attr_accessor :realm_ignored, :realm_read_only, :enum_type, :enum_values - attr_accessor :json_key_path, :json_values, :transformer, :comment, :support_annotation + attr_accessor :json_key_path, :json_values, :transformer, :comment, :support_annotation, :json_ignored alias optional? optional alias indexed? indexed alias realm_ignored? realm_ignored + alias json_ignored? json_ignored # rubocop:disable Metrics/AbcSize, Metrics/MethodLength def initialize(attribute_xml, entity_name) @@ -40,6 +41,7 @@ def initialize(attribute_xml, entity_name) @enum_values = Gyro::Parser::XCDataModel.user_info(attribute_xml, 'enumValues').split(',') @json_key_path = Gyro::Parser::XCDataModel.user_info(attribute_xml, 'JSONKeyPath') @json_values = Gyro::Parser::XCDataModel.user_info(attribute_xml, 'JSONValues').split(',') + @json_ignored = !Gyro::Parser::XCDataModel.user_info(attribute_xml, 'JSONIgnored').empty? @transformer = Gyro::Parser::XCDataModel.user_info(attribute_xml, 'transformer').strip @comment = Gyro::Parser::XCDataModel.user_info(attribute_xml, 'comment') @support_annotation = Gyro::Parser::XCDataModel.user_info(attribute_xml, 'supportAnnotation') @@ -56,6 +58,7 @@ def to_h 'realm_ignored' => realm_ignored, 'realm_read_only' => realm_read_only, 'enum_type' => enum_type, 'enum_values' => enum_values, 'json_key_path' => json_key_path, 'json_values' => json_values, + 'json_ignored' => json_ignored, 'transformer' => transformer, 'need_transformer' => need_transformer?, 'comment' => comment, 'support_annotation' => support_annotation, diff --git a/lib/gyro/parser/xcdatamodel/relationship.rb b/lib/gyro/parser/xcdatamodel/relationship.rb index 9a7f803..1b8f54d 100644 --- a/lib/gyro/parser/xcdatamodel/relationship.rb +++ b/lib/gyro/parser/xcdatamodel/relationship.rb @@ -19,11 +19,12 @@ module XCDataModel # class Relationship attr_accessor :entity_name, :name, :type, :optional, :deletion_rule - attr_accessor :inverse_name, :inverse_type, :json_key_path, :support_annotation + attr_accessor :inverse_name, :inverse_type, :json_key_path, :support_annotation, :json_ignored attr_accessor :realm_ignored attr_accessor :destination alias realm_ignored? realm_ignored + alias json_ignored? json_ignored # rubocop:disable Metrics/AbcSize, Metrics/MethodLength def initialize(relationship_xml, entity_name) @@ -35,6 +36,7 @@ def initialize(relationship_xml, entity_name) @inverse_type = relationship_xml.attributes['destinationEntity'].to_s @json_key_path = Gyro::Parser::XCDataModel.user_info(relationship_xml, 'JSONKeyPath') @realm_ignored = Gyro::Parser::XCDataModel.user_info(relationship_xml, 'realmIgnored').empty? ? false : true + @json_ignored = Gyro::Parser::XCDataModel.user_info(relationship_xml, 'JSONIgnored').empty? ? false : true @support_annotation = Gyro::Parser::XCDataModel.user_info(relationship_xml, 'supportAnnotation') load_type(relationship_xml) @destination = Gyro::Parser::XCDataModel.user_info(relationship_xml, 'destination') @@ -45,7 +47,8 @@ def to_h { 'entity_name' => entity_name, 'name' => name, 'type' => type.to_s, 'optional' => optional, 'deletion_rule' => deletion_rule, 'inverse_name' => inverse_name, 'inverse_type' => inverse_type, - 'json_key_path' => json_key_path, 'support_annotation' => support_annotation, + 'json_key_path' => json_key_path, 'json_ignored' => json_ignored, + 'support_annotation' => support_annotation, 'realm_ignored' => realm_ignored, 'destination' => destination, 'inverse' => inverse? } end # rubocop:enable Metrics/AbcSize, Metrics/MethodLength diff --git a/lib/templates/decodable/README.md b/lib/templates/decodable/README.md index 0638c20..4c36cbf 100644 --- a/lib/templates/decodable/README.md +++ b/lib/templates/decodable/README.md @@ -34,3 +34,9 @@ extension Shop: Decodable { } } ``` + +# Specific JSON tasks + +## Ignoring specific properties + +If you don't want to generate a decodable call for a specific property, just add the `JSONIgnored` attribute in the xcdatamodel property's userInfos. diff --git a/lib/templates/decodable/entity.liquid b/lib/templates/decodable/entity.liquid index 32a514c..146efc2 100644 --- a/lib/templates/decodable/entity.liquid +++ b/lib/templates/decodable/entity.liquid @@ -8,49 +8,77 @@ extension {{ entity.name }}: Decodable { static func decode(_ json: Any) throws -> {{ entity.name }} { {%- assign entityVariable = entity.name | uncapitalize %} let {{ entityVariable }} = {{ entity.name }}() + {%- for attribute in entity.attributes %} - {% assign attributeKey = attribute.name -%} + {%- if attribute.json_ignored == false %} + {%- assign trySyntax = "try" -%} + {%- if attribute.optional == true -%} + {%- assign trySyntax = "try?" -%} + {%- endif -%} + {%- assign attributeKey = attribute.name -%} {%- if attribute.json_key_path.size > 0 -%} {%- assign attributeKey = attribute.json_key_path -%} {%- endif -%} {%- case attribute.type -%} - {%- when "date" -%} - {{ entityVariable }}.{{ attribute.name }} = try Date.decode(json => "{{ attributeKey }}") + {%- when "date" %} + {{ entityVariable }}.{{ attribute.name }} = {{ trySyntax }} Date.decode(json => "{{ attributeKey }}") {%- when "integer_16" or "integer_32" or "integer_64" or "float" or "double" or "boolean" -%} {%- if attribute.optional == true -%} - {%- if attribute.transformer.size > 0 -%} - {{ entityVariable }}.{{ attribute.name }}.value = try {{ attribute.transformer }}.decode(json => "{{ attributeKey }}") + {%- if attribute.enum_values.size > 0 -%} + {%- if attribute.transformer.size > 0 %} + {{ entityVariable }}.{{ attribute.name }} = {{ trySyntax }} {{ attribute.transformer }}.decode(json => "{{ attributeKey }}") + {%- else %} + {{ entityVariable }}.{{ attribute.name }} = {{ trySyntax }} json => "{{ attributeKey }}" + {%- endif -%} {%- else -%} - {{ entityVariable }}.{{ attribute.name }}.value = try json => "{{ attributeKey }}" + {%- if attribute.transformer.size > 0 %} + {{ entityVariable }}.{{ attribute.name }}.value = {{ trySyntax }} {{ attribute.transformer }}.decode(json => "{{ attributeKey }}") + {%- else %} + {{ entityVariable }}.{{ attribute.name }}.value = {{ trySyntax }} json => "{{ attributeKey }}" + {%- endif -%} {%- endif -%} {%- else -%} - {%- if attribute.transformer.size > 0 -%} - {{ entityVariable }}.{{ attribute.name }} = try {{ attribute.transformer }}.decode(json => "{{ attributeKey }}") - {%- else -%} - {{ entityVariable }}.{{ attribute.name }} = try json => "{{ attributeKey }}" + {%- if attribute.transformer.size > 0 %} + {{ entityVariable }}.{{ attribute.name }} = {{ trySyntax }} {{ attribute.transformer }}.decode(json => "{{ attributeKey }}") + {%- else %} + {{ entityVariable }}.{{ attribute.name }} = {{ trySyntax }} json => "{{ attributeKey }}" {%- endif -%} {%- endif -%} {%- else -%} - {%- if attribute.transformer.size > 0 -%} - {{ entityVariable }}.{{ attribute.name }} = try {{ attribute.transformer }}.decode(json => "{{ attributeKey }}") - {%- else -%} - {{ entityVariable }}.{{ attribute.name }} = try json => "{{ attributeKey }}" + {%- if attribute.transformer.size > 0 %} + {{ entityVariable }}.{{ attribute.name }} = {{ trySyntax }} {{ attribute.transformer }}.decode(json => "{{ attributeKey }}") + {%- else %} + {{ entityVariable }}.{{ attribute.name }} = {{ trySyntax }} json => "{{ attributeKey }}" {%- endif -%} {%- endcase -%} + {%- endif -%} {%- endfor -%} - {%- for relationship in entity.relationships %} - {% assign relationKey = relationship.name -%} + {% for relationship in entity.relationships -%} + {%- if relationship.json_ignored == false %} + {%- assign relationKey = relationship.name -%} + {%- assign trySyntax = "try" -%} + {%- if relationship.optional == true -%} + {%- assign trySyntax = "try?" -%} + {%- endif -%} {%- if relationship.json_key_path.size > 0 -%} {%- assign relationKey = relationship.json_key_path -%} {%- endif -%} {%- if relationship.type == "to_many" -%} - let {{ relationship.name }}Sandbox: [{{ relationship.inverse_type }}] = try json => "{{ relationKey }}" + {%- if relationship.optional == true %} + if let {{ relationship.name }}Sandbox: [{{ relationship.inverse_type }}] = {{ trySyntax }} json => "{{ relationKey }}" { + {{ entityVariable }}.{{ relationship.name }}.append(objectsIn: {{ relationship.name }}Sandbox) + } + {%- else %} + let {{ relationship.name }}Sandbox: [{{ relationship.inverse_type }}] = {{ trySyntax }} json => "{{ relationKey }}" {{ entityVariable }}.{{ relationship.name }}.append(objectsIn: {{ relationship.name }}Sandbox) - {%- else -%} - {{ entityVariable }}.{{ relationship.name }} = try json => "{{ relationKey }}" {%- endif -%} + {%- else %} + {{ entityVariable }}.{{ relationship.name }} = {{ trySyntax }} json => "{{ relationKey }}" + {%- endif -%} + {%- endif -%} {%- endfor %} + return {{ entityVariable }} } diff --git a/spec/fixtures/swift/transformers/decodable/Shop+Decodable.swift b/spec/fixtures/swift/transformers/decodable/Shop+Decodable.swift index 0784c59..353a6f9 100644 --- a/spec/fixtures/swift/transformers/decodable/Shop+Decodable.swift +++ b/spec/fixtures/swift/transformers/decodable/Shop+Decodable.swift @@ -7,12 +7,13 @@ extension Shop: Decodable { static func decode(_ json: Any) throws -> Shop { let shop = Shop() - shop.attrDate = try Date.decode(json => "attrDate") - shop.attrDateCustom = try Date.decode(json => "attrDateCustom") - shop.attrDouble = try json => "attrDouble" - shop.attrInteger16 = try Int.decode(json => "attrInteger16") - shop.attrInteger32 = try json => "attrInteger32" - shop.attrInteger64 = try Int.decode(json => "attrInteger64") + shop.attrDate = try? Date.decode(json => "attrDate") + shop.attrDateCustom = try? Date.decode(json => "attrDateCustom") + shop.attrDouble = try json => "attrDouble" + shop.attrInteger16 = try Int.decode(json => "attrInteger16") + shop.attrInteger32 = try json => "attrInteger32" + shop.attrInteger64 = try Int.decode(json => "attrInteger64") + return shop }