Skip to content
This repository has been archived by the owner on Dec 20, 2023. It is now read-only.

Feature/optional decodable #38

Merged
merged 9 commits into from
Dec 13, 2017
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
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
5 changes: 4 additions & 1 deletion lib/gyro/parser/xcdatamodel/attribute.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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')
Expand All @@ -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,
Expand Down
7 changes: 5 additions & 2 deletions lib/gyro/parser/xcdatamodel/relationship.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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')
Expand All @@ -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
Expand Down
6 changes: 6 additions & 0 deletions lib/templates/decodable/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
66 changes: 47 additions & 19 deletions lib/templates/decodable/entity.liquid
Original file line number Diff line number Diff line change
Expand Up @@ -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 }}
}

Expand Down
13 changes: 7 additions & 6 deletions spec/fixtures/swift/transformers/decodable/Shop+Decodable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down