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

Add field! for property! #181

Merged
merged 2 commits into from
Apr 22, 2018
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
34 changes: 34 additions & 0 deletions spec/granite_orm/fields/field_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
require "../../spec_helper"

class Field < Granite::ORM::Base
adapter pg

field normal : Int32
field! raise_on_nil : Int32
end

describe Granite::ORM::Fields do
describe "field" do
it "generates a nilable field getter and a raise-on-nil field getter suffixed with '!'" do
field = Field.new(normal: 1)
nil_field = Field.new

field.normal.should eq(1)
field.normal!.should eq(1)
nil_field.normal.should be_nil
expect_raises(Exception, "Field#normal cannot be nil") { nil_field.normal! }
end
end

describe "field!" do
it "generates a raise-on-nil field getter and a nilable field getter suffixed with '?'" do
field = Field.new(raise_on_nil: 1)
nil_field = Field.new

field.raise_on_nil.should eq(1)
field.raise_on_nil?.should eq(1)
expect_raises(Exception, "Field#raise_on_nil cannot be nil") { nil_field.raise_on_nil }
nil_field.raise_on_nil?.should be_nil
end
end
end
37 changes: 24 additions & 13 deletions src/granite_orm/fields.cr
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,14 @@ module Granite::ORM::Fields
end

# specify the fields you want to define and types
macro field(decl)
{% CONTENT_FIELDS[decl.var] = decl.type %}
macro field(decl, **options)
{% CONTENT_FIELDS[decl.var] = options || {} of Nil => Nil %}
{% CONTENT_FIELDS[decl.var][:type] = decl.type %}
end

# specify the raise-on-nil fields you want to define and types
macro field!(decl, **options)
field {{decl}}, {{options.double_splat(", ")}}raise_on_nil: true
end

# include created_at and updated_at that will automatically be updated
Expand All @@ -24,15 +30,17 @@ module Granite::ORM::Fields

macro __process_fields
# merge PK and CONTENT_FIELDS into FIELDS
{% FIELDS[PRIMARY[:name]] = PRIMARY[:type] %}
{% for name, type in CONTENT_FIELDS %}
{% FIELDS[name] = type %}
{% FIELDS[PRIMARY[:name]] = PRIMARY %}
{% for name, options in CONTENT_FIELDS %}
{% FIELDS[name] = options %}
{% end %}

# Create the properties
{% for name, type in FIELDS %}
property {{name.id}} : Union({{type.id}} | Nil)
def {{name.id}}!
{% for name, options in FIELDS %}
{% type = options[:type] %}
{% suffixes = options[:raise_on_nil] ? ["?", ""] : ["", "!"] %}
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?
@{{name.id}}.not_nil!
end
Expand All @@ -50,8 +58,8 @@ module Granite::ORM::Fields
# keep a hash of the params that will be passed to the adapter.
def content_values
parsed_params = [] of DB::Any
{% for name, type in CONTENT_FIELDS %}
{% if type.id == Time.id %}
{% for name, options in CONTENT_FIELDS %}
{% if options[:type].id == Time.id %}
parsed_params << {{name.id}}.try(&.to_s("%F %X"))
{% else %}
parsed_params << {{name.id}}
Expand All @@ -63,7 +71,8 @@ module Granite::ORM::Fields
def to_h
fields = {} of String => DB::Any

{% for name, type in FIELDS %}
{% for name, options in FIELDS %}
{% type = options[:type] %}
{% if type.id == Time.id %}
fields["{{name}}"] = {{name.id}}.try(&.to_s("%F %X"))
{% elsif type.id == Slice.id %}
Expand All @@ -78,7 +87,8 @@ module Granite::ORM::Fields

def to_json(json : JSON::Builder)
json.object do
{% for name, type in FIELDS %}
{% for name, options in FIELDS %}
{% type = options[:type] %}
%field, %value = "{{name.id}}", {{name.id}}
{% if type.id == Time.id %}
json.field %field, %value.try(&.to_s("%F %X"))
Expand All @@ -105,7 +115,8 @@ module Granite::ORM::Fields
private def cast_to_field(name, value : Type)
{% unless FIELDS.empty? %}
case name.to_s
{% for _name, type in FIELDS %}
{% for _name, options in FIELDS %}
{% type = options[:type] %}
when "{{_name.id}}"
if "{{_name.id}}" == "{{PRIMARY[:name]}}"
{% if !PRIMARY[:auto] %}
Expand Down
3 changes: 2 additions & 1 deletion src/granite_orm/querying.cr
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ module Granite::ORM::Querying
def set_attributes(result : DB::ResultSet)
# Loading from DB means existing records.
@new_record = false
\{% for name, type in FIELDS %}
\{% for name, options in FIELDS %}
\{% type = options[:type] %}
\{% if type.id.stringify == "Time" %}
if @@adapter.class.name == "Granite::Adapter::Sqlite"
# sqlite3 does not have timestamp type - timestamps are stored as str
Expand Down
7 changes: 0 additions & 7 deletions src/granite_orm/table.cr
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,6 @@ module Granite::ORM::Table
@@primary_name = "{{primary_name}}"
@@primary_auto = "{{primary_auto}}"

property {{primary_name}} : Union({{primary_type.id}} | Nil)

def {{primary_name}}!
raise {{@type.name.stringify}} + "#" + {{primary_name.stringify}} + " cannot be nil" if @{{primary_name}}.nil?
@{{primary_name}}.not_nil!
end

def self.table_name
@@table_name
end
Expand Down