Skip to content
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

Support YAML::Serializable #255

Merged
73 changes: 71 additions & 2 deletions spec/granite_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ require "./spec_helper"
end

it "works with after_initialize" do
model = AfterJSONInit.from_json(%({"name": "after_initialize"}))
model = AfterInit.from_json(%({"name": "after_initialize"}))

model.name.should eq "after_initialize"
model.priority.should eq 1000
Expand Down Expand Up @@ -67,7 +67,76 @@ require "./spec_helper"
]

collection = todos.to_json
collection.should eq(%([{"name":"todo 1","priority":1},{"name":"todo 2","priority":2},{"name":"todo 3","priority":3}]))
collection.should eq %([{"name":"todo 1","priority":1},{"name":"todo 2","priority":2},{"name":"todo 3","priority":3}])
end
end
end

describe "YAML" do
context ".from_yaml" do
it "can create an object from YAML" do
yaml_str = %(---\nname: yaml::anyReview\nupvotes: 2\nsentiment: 1.23\ninterest: 4.56\npublished: true)

review = Review.from_yaml(yaml_str)
review.name.should eq "yaml::anyReview"
review.upvotes.should eq 2
review.sentiment.should eq 1.23.to_f32
review.interest.should eq 4.56
review.published.should eq true
review.created_at.should be_nil
end

it "can create an array of objects from YAML" do
yaml_str = "---\n- name: yaml1\n upvotes: 2\n sentiment: 1.23\n interest: 4.56\n published: true\n- name: yaml2\n upvotes: 0\n sentiment: !!float 5\n interest: 6.99\n published: false"

review = Array(Review).from_yaml(yaml_str)
review[0].name.should eq "yaml1"
review[0].upvotes.should eq 2
review[0].sentiment.should eq 1.23.to_f32
review[0].interest.should eq 4.56
review[0].published.should be_true
review[0].created_at.should be_nil

review[1].name.should eq "yaml2"
review[1].upvotes.should eq 0
review[1].sentiment.should eq 5.00.to_f32
review[1].interest.should eq 6.99
review[1].published.should be_false
review[1].created_at.should be_nil
end

it "works with after_initialize" do
model = AfterInit.from_yaml(%(---\nname: after_initialize))

model.name.should eq "after_initialize"
model.priority.should eq 1000
end
end

context ".to_yaml" do
it "emits nil values when told" do
t = TodoEmitNull.new(name: "test todo", priority: 20)
result = %(---\nid: \nname: test todo\npriority: 20\ncreated_at: \nupdated_at: \n)

t.to_yaml.should eq result
end

it "does not emit nil values by default" do
t = Todo.new(name: "test todo", priority: 20)
result = %(---\nname: test todo\npriority: 20\n)

t.to_yaml.should eq result
end

it "works with array of models" do
todos = [
Todo.new(name: "todo 1", priority: 1),
Todo.new(name: "todo 2", priority: 2),
Todo.new(name: "todo 3", priority: 3),
]

collection = todos.to_yaml
collection.should eq %(---\n- name: todo 1\n priority: 1\n- name: todo 2\n priority: 2\n- name: todo 3\n priority: 3\n)
end
end
end
Expand Down
5 changes: 3 additions & 2 deletions spec/spec_models.cr
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@ require "uuid"
end

@[JSON::Serializable::Options(emit_nulls: true)]
@[YAML::Serializable::Options(emit_nulls: true)]
class TodoEmitNull < Granite::Base
adapter {{ adapter.id }}
table_name todos
Expand All @@ -248,7 +249,7 @@ require "uuid"
timestamps
end

class AfterJSONInit < Granite::Base
class AfterInit < Granite::Base
adapter {{ adapter.id }}
table_name after_json_init

Expand Down Expand Up @@ -295,6 +296,6 @@ require "uuid"
Comment.migrator.drop_and_create
Todo.migrator.drop_and_create
TodoEmitNull.migrator.drop_and_create
AfterJSONInit.migrator.drop_and_create
AfterInit.migrator.drop_and_create
end
{% end %}
1 change: 1 addition & 0 deletions src/granite/base.cr
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class Granite::Base
include Select

include JSON::Serializable
include YAML::Serializable

extend Querying
extend Transactions::ClassMethods
Expand Down
1 change: 1 addition & 0 deletions src/granite/callbacks.cr
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ module Granite::Callbacks
CALLBACK_NAMES = %w(before_save after_save before_create after_create before_update after_update before_destroy after_destroy)

@[JSON::Field(ignore: true)]
@[YAML::Field(ignore: true)]
@_current_callback : String?

macro included
Expand Down
3 changes: 3 additions & 0 deletions src/granite/fields.cr
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ module Granite::Fields
{% if options[:json_options] %}
@[JSON::Field({{**options[:json_options]}})]
{% end %}
{% if options[:yaml_options] %}
@[YAML::Field({{**options[:yaml_options]}})]
{% end %}
property{{suffixes[0].id}} {{name.id}} : Union({{type.id}} | Nil)
def {{name.id}}{{suffixes[1].id}}
raise {{@type.name.stringify}} + "#" + {{name.stringify}} + " cannot be nil" if @{{name.id}}.nil?
Expand Down
2 changes: 2 additions & 0 deletions src/granite/transactions.cr
Original file line number Diff line number Diff line change
Expand Up @@ -205,10 +205,12 @@ module Granite::Transactions

# Returns true if this object hasn't been saved yet.
@[JSON::Field(ignore: true)]
@[YAML::Field(ignore: true)]
getter? new_record : Bool = true

# Returns true if this object has been destroyed.
@[JSON::Field(ignore: true)]
@[YAML::Field(ignore: true)]
getter? destroyed : Bool = false

# Returns true if the record is persisted.
Expand Down
1 change: 1 addition & 0 deletions src/granite/validators.cr
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ require "./error"
# ```
module Granite::Validators
@[JSON::Field(ignore: true)]
@[YAML::Field(ignore: true)]
getter errors = [] of Error

macro included
Expand Down