Skip to content

Commit

Permalink
Merge pull request maxdemarzi#76 from blizkreeg/models
Browse files Browse the repository at this point in the history
move typecasting closer to read/save to graph
  • Loading branch information
blizkreeg committed Dec 16, 2013
2 parents 4569d6a + a9bdf25 commit 652ab07
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 63 deletions.
3 changes: 2 additions & 1 deletion lib/deja/neo_parse.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module Deja
module NeoParse
extend ActiveSupport::Concern
include TypeCaster

module ClassMethods
def normalize(hash, type = :eager)
Expand All @@ -26,7 +27,7 @@ def sane_hash(hash)
attr_hash[:start_node] = record['start'].split('/').last.to_i if record['start']
attr_hash[:end_node] = record['end'].split('/').last.to_i if record['end']
record['data'].each do |key, value|
attr_hash[key.to_sym] = value
attr_hash[key.to_sym] = record['data']['type'].nil? ? value : TypeCaster.reversecast(key.to_sym, value, record['data']['type'])
end
attr_hash
end
Expand Down
2 changes: 1 addition & 1 deletion lib/deja/node.rb
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ def persisted_attributes
inst_vars = instance_variables.map { |i| i.to_s[1..-1].to_sym }
attrs = (self.class.attributes + self.class.composed_attributes) & inst_vars
attrs.inject({}) do |memo, (k, v)|
memo[k] = send(k)
memo[k] = TypeCaster.typecast(k, send(k), self.class.name)
memo
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/deja/relationship.rb
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ def persisted_attributes
inst_vars = instance_variables.map { |i| i.to_s[1..-1].to_sym }
attrs = self.class.attributes & inst_vars
attrs.inject({}) do |memo, (k, v)|
memo[k] = send(k)
memo[k] = TypeCaster.typecast(k, send(k), self.class.name)
memo
end
end
Expand Down
8 changes: 1 addition & 7 deletions lib/deja/schema_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,8 @@ def attribute(name, type, opts = {})
def attr_accessorize(name, opts)
send(:attr_accessor, name)
define_attribute_methods name
define_method("#{name}") do
#reversecast(name, instance_variable_get("@#{name}"))
instance_variable_get("@#{name}")
end
define_method("#{name}=") do |new_value|
casted_value = typecast(name, new_value)
send("#{name}_will_change!") if (casted_value != instance_variable_get("@#{name}") && !instance_variable_get("@#{name}").nil?)
#instance_variable_set("@#{name}", casted_value)
send("#{name}_will_change!") if (new_value != instance_variable_get("@#{name}") && !instance_variable_get("@#{name}").nil?)
instance_variable_set("@#{name}", new_value)
end
end
Expand Down
74 changes: 40 additions & 34 deletions lib/deja/type_caster.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,46 +2,52 @@ module Deja
module TypeCaster
extend ActiveSupport::Concern

included do
# cast back to Ruby objects where representation in the graph is different
def reversecast(attr_name, value)
return nil if value.nil?
# cast back to Ruby objects where representation in the graph is different
def self.reversecast(attr_name, value, klass)
return nil if value.nil?

data_type = self.class.schema[:attributes][attr_name][:type].to_s
data_type = klass.constantize.schema[:attributes][attr_name][:type].to_s

case data_type
when 'Date'
Date.parse(value.to_s)
when 'Time'
Time.at(value)
else
value
end
case data_type
when 'Integer'
value.to_i
when 'Float'
value.to_f
when 'String'
value.to_s
when 'Deja::Boolean'
Boolean.true?(value)
when 'Date'
Date.parse(value.to_s)
when 'Time'
Time.at(value)
else
value
end
end

# cast to neo4j basic types and raise errors when invalid/unrecognized data type
def typecast(attr_name, value)
return nil if value.nil?
# cast to neo4j basic types and raise errors when invalid/unrecognized data type
def self.typecast(attr_name, value, klass)
return nil if value.nil?

data_type = self.class.schema[:attributes][attr_name][:type].to_s
data_type = klass.constantize.schema[:attributes][attr_name][:type].to_s

case data_type
when 'Integer'
Integer(value)
when 'Float'
Float(value)
when 'Deja::Boolean'
raise TypeError, "invalid boolean value passed in: '#{value}'" unless Boolean.boolean?(value)
Boolean.true?(value)
when 'String'
String(value)
when 'Date'
Date.parse(value.to_s).strftime("%Y%m%d").to_i
when 'Time'
value.to_i
else
raise TypeError, "undefined data type #{data_type} for attribute #{name}"
end
case data_type
when 'Integer'
Integer(value)
when 'Float'
Float(value)
when 'Deja::Boolean'
raise TypeError, "invalid boolean value passed in: '#{value}'" unless Boolean.boolean?(value)
Boolean.true?(value)
when 'String'
String(value)
when 'Date'
Date.parse(value.to_s).strftime("%Y%m%d").to_i
when 'Time'
value.to_i
else
raise TypeError, "undefined data type #{data_type} for attribute #{name}"
end
end
end
Expand Down
38 changes: 19 additions & 19 deletions spec/type_caster_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,79 +8,79 @@
context 'typecast' do
it 'should typecast a valid string' do
person.name = 'james bond'
expect(person.name).to eq('james bond')
expect(TypeCaster.typecast(:name, person.name, 'Person')).to eq('james bond')
end

it 'should typecast a valid integer' do
person.age = '-5'
expect(person.age).to eq(-5)
expect(TypeCaster.typecast(:age, person.age, 'Person')).to eq(-5)

person.age = 10
expect(person.age).to eq(10)
expect(TypeCaster.typecast(:age, person.age, 'Person')).to eq(10)
end

it 'should fail to cast an invalid integer' do
expect { person.age = '5a' }.to raise_error
expect(TypeCaster.typecast(:age, person.age, 'Person')).to raise_error
end

it 'should cast a valid float' do
person.bank_balance = 50000.51
expect(person.bank_balance).to eq(50000.51)
expect(TypeCaster.typecast(:bank_balance, person.bank_balance, 'Person')).to eq(50000.51)

person.bank_balance = '10.25'
expect(person.bank_balance).to eq(10.25)
expect(TypeCaster.typecast(:bank_balance, person.bank_balance, 'Person')).to eq(10.25)
end

it 'should fail to cast an invalid floating point value' do
expect { person.bank_balance = '5a' }.to raise_error
expect{TypeCaster.typecast(:bank_balance, '5a', 'Person')}.to raise_error
end

it 'should cast a valid boolean value' do
person.vip = 'true'
expect(person.vip).to eq(true)
expect(TypeCaster.typecast(:vip, person.vip, 'Person')).to eq(true)

person.vip = 't'
expect(person.vip).to eq(true)
expect(TypeCaster.typecast(:vip, person.vip, 'Person')).to eq(true)

person.vip = true
expect(person.vip).to eq(true)
expect(TypeCaster.typecast(:vip, person.vip, 'Person')).to eq(true)

person.vip = 1
expect(person.vip).to eq(true)
expect(TypeCaster.typecast(:vip, person.vip, 'Person')).to eq(true)

person.vip = 'false'
expect(person.vip).to eq(false)
expect(TypeCaster.typecast(:vip, person.vip, 'Person')).to eq(false)

person.vip = 'f'
expect(person.vip).to eq(false)
expect(TypeCaster.typecast(:vip, person.vip, 'Person')).to eq(false)

person.vip = false
expect(person.vip).to eq(false)
expect(TypeCaster.typecast(:vip, person.vip, 'Person')).to eq(false)

person.vip = 0
expect(person.vip).to eq(false)
expect(TypeCaster.typecast(:vip, person.vip, 'Person')).to eq(false)
end

it 'should fail to cast an invalid boolean value' do
expect { person.vip = 'tru1' }.to raise_error TypeError
expect { TypeCaster.typecast(:vip, 'tru1', 'Person') }.to raise_error TypeError
end

it 'should fail on unrecognized data type' do
expect { person.tags = ['engineer', 'designer', 'entrepreneur'] }.to raise_error TypeError
expect { TypeCaster.typecast(:tags, ['engineer', 'designer', 'entrepreneur'], 'Person') }.to raise_error TypeError
end

it 'should validate date values' do
Timecop.freeze do
person.born_on = Date.today
expect(person.instance_variable_get("@born_on")).to eq(Date.today.strftime("%Y%m%d").to_i)
expect(person.instance_variable_get("@born_on")).to eq(Date.today)
expect(person.born_on).to eq(Date.today)
end
end

it 'should validate time values' do
Timecop.freeze do
person.knighted_at = Time.now
expect(person.instance_variable_get("@knighted_at")).to eq(Time.now.to_i)
expect(person.instance_variable_get("@knighted_at")).to eq(Time.now)
expect(person.knighted_at.to_i).to eq(Time.now.to_i)
end
end
Expand Down

0 comments on commit 652ab07

Please sign in to comment.