ardm 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (93) hide show
  1. checksums.yaml +5 -13
  2. data/Gemfile +1 -2
  3. data/LICENSE +2 -2
  4. data/README.md +72 -16
  5. data/ardm.gemspec +1 -0
  6. data/lib/ardm.rb +2 -1
  7. data/lib/ardm/active_record.rb +8 -1
  8. data/lib/ardm/active_record/associations.rb +33 -4
  9. data/lib/ardm/active_record/base.rb +2 -0
  10. data/lib/ardm/active_record/collection.rb +5 -0
  11. data/lib/ardm/active_record/data_mapper_constant.rb +1 -0
  12. data/lib/ardm/active_record/data_mapper_constant_proxy.rb +24 -0
  13. data/lib/ardm/active_record/finalize.rb +18 -0
  14. data/lib/ardm/active_record/predicate_builder/array_handler.rb +10 -16
  15. data/lib/ardm/active_record/predicate_builder/rails3.rb +42 -15
  16. data/lib/ardm/active_record/predicate_builder/rails4.rb +39 -13
  17. data/lib/ardm/active_record/property.rb +24 -12
  18. data/lib/ardm/active_record/query.rb +9 -18
  19. data/lib/ardm/active_record/record.rb +54 -11
  20. data/lib/ardm/active_record/relation.rb +36 -6
  21. data/lib/ardm/active_record/repository.rb +6 -2
  22. data/lib/ardm/data_mapper.rb +2 -0
  23. data/lib/ardm/data_mapper/record.rb +3 -9
  24. data/lib/ardm/version.rb +1 -1
  25. data/spec/ardm/datamapper_constants_spec.rb +31 -0
  26. data/spec/fixtures/article.rb +2 -0
  27. data/spec/integration/api_key_spec.rb +3 -3
  28. data/spec/integration/bcrypt_hash_spec.rb +7 -7
  29. data/spec/integration/comma_separated_list_spec.rb +11 -11
  30. data/spec/integration/dirty_minder_spec.rb +23 -39
  31. data/spec/integration/enum_spec.rb +11 -11
  32. data/spec/integration/epoch_time_spec.rb +6 -6
  33. data/spec/integration/file_path_spec.rb +23 -23
  34. data/spec/integration/flag_spec.rb +11 -13
  35. data/spec/integration/ip_address_spec.rb +15 -15
  36. data/spec/integration/json_spec.rb +7 -7
  37. data/spec/integration/slug_spec.rb +6 -6
  38. data/spec/integration/uri_spec.rb +11 -11
  39. data/spec/integration/uuid_spec.rb +16 -16
  40. data/spec/integration/yaml_spec.rb +8 -8
  41. data/spec/public/model_spec.rb +193 -0
  42. data/spec/public/property/binary_spec.rb +4 -4
  43. data/spec/public/property/boolean_spec.rb +3 -3
  44. data/spec/public/property/class_spec.rb +2 -2
  45. data/spec/public/property/date_spec.rb +2 -2
  46. data/spec/public/property/date_time_spec.rb +2 -2
  47. data/spec/public/property/decimal_spec.rb +2 -2
  48. data/spec/public/property/discriminator_spec.rb +21 -20
  49. data/spec/public/property/float_spec.rb +2 -2
  50. data/spec/public/property/integer_spec.rb +2 -2
  51. data/spec/public/property/object_spec.rb +14 -13
  52. data/spec/public/property/serial_spec.rb +2 -2
  53. data/spec/public/property/string_spec.rb +2 -2
  54. data/spec/public/property/text_spec.rb +2 -2
  55. data/spec/public/property/time_spec.rb +2 -2
  56. data/spec/public/property_spec.rb +44 -48
  57. data/spec/public/resource_spec.rb +278 -0
  58. data/spec/schema.rb +33 -4
  59. data/spec/semipublic/property/boolean_spec.rb +5 -5
  60. data/spec/semipublic/property/class_spec.rb +3 -3
  61. data/spec/semipublic/property/date_spec.rb +8 -8
  62. data/spec/semipublic/property/date_time_spec.rb +9 -9
  63. data/spec/semipublic/property/decimal_spec.rb +16 -16
  64. data/spec/semipublic/property/float_spec.rb +16 -16
  65. data/spec/semipublic/property/integer_spec.rb +16 -16
  66. data/spec/semipublic/property/lookup_spec.rb +4 -4
  67. data/spec/semipublic/property/text_spec.rb +2 -2
  68. data/spec/semipublic/property/time_spec.rb +10 -10
  69. data/spec/semipublic/property_spec.rb +4 -4
  70. data/spec/shared/finder_shared_spec.rb +1151 -0
  71. data/spec/shared/flags_shared_spec.rb +6 -6
  72. data/spec/shared/identity_function_group.rb +1 -1
  73. data/spec/shared/public_property_spec.rb +26 -25
  74. data/spec/shared/resource_spec.rb +1218 -0
  75. data/spec/shared/semipublic_property_spec.rb +23 -22
  76. data/spec/spec_helper.rb +17 -0
  77. data/spec/unit/bcrypt_hash_spec.rb +15 -15
  78. data/spec/unit/csv_spec.rb +11 -11
  79. data/spec/unit/dirty_minder_spec.rb +3 -5
  80. data/spec/unit/enum_spec.rb +17 -17
  81. data/spec/unit/epoch_time_spec.rb +8 -8
  82. data/spec/unit/file_path_spec.rb +9 -9
  83. data/spec/unit/flag_spec.rb +9 -9
  84. data/spec/unit/ip_address_spec.rb +9 -9
  85. data/spec/unit/json_spec.rb +11 -11
  86. data/spec/unit/paranoid_boolean_spec.rb +19 -17
  87. data/spec/unit/paranoid_datetime_spec.rb +21 -19
  88. data/spec/unit/regexp_spec.rb +4 -4
  89. data/spec/unit/uri_spec.rb +8 -8
  90. data/spec/unit/yaml_spec.rb +9 -9
  91. metadata +35 -27
  92. data/lib/ardm/active_record/not_found.rb +0 -7
  93. data/lib/ardm/data_mapper/not_found.rb +0 -5
@@ -78,25 +78,51 @@ module Ardm
78
78
  end
79
79
 
80
80
  def expand(klass, table, column, value)
81
- queries = []
81
+ if klass && association = klass.reflect_on_association(column.to_sym)
82
+ expand_association(association, table, column, value)
83
+ else
84
+ [build(table[column], value)]
85
+ end
86
+ end
82
87
 
83
- # Find the foreign key when using queries such as:
84
- # Post.where(author: author)
85
- #
86
- # For polymorphic relationships, find the foreign key and type:
87
- # PriceEstimate.where(estimate_of: treasure)
88
- if klass && value.is_a?(Base) && reflection = klass.reflect_on_association(column.to_sym)
89
- if reflection.polymorphic?
90
- queries << build(table[reflection.foreign_type], value.class.base_class)
88
+ # Find the foreign key when using queries such as:
89
+ # Post.where(author: author)
90
+ #
91
+ # For polymorphic relationships, find the foreign key and type:
92
+ # PriceEstimate.where(estimate_of: treasure)
93
+ #
94
+ # Attempt to build a query that makes sense for an association name
95
+ # in the query, but if we can't generate a propery query, fallback
96
+ # to using the original key we received.
97
+ def expand_association(association, table, column, value)
98
+ queries = []
99
+ case association.macro
100
+ when :belongs_to
101
+ if association.polymorphic? && base_class = polymorphic_base_class_from_value(value)
102
+ queries << build(table[association.foreign_type], base_class)
91
103
  end
92
-
93
- column = reflection.foreign_key
104
+ queries << build(table[association.foreign_key], value)
105
+ when :has_many, :has_one
106
+ table = Arel::Table.new(association.klass.table_name, table.engine)
107
+ queries << build(table[association.klass.primary_key], value)
108
+ else
109
+ queries << build(table[column], value)
94
110
  end
95
-
96
- queries << build(table[column], value)
97
111
  queries
98
112
  end
99
113
 
114
+ def polymorphic_base_class_from_value(value)
115
+ case value
116
+ when Relation
117
+ value.klass.base_class
118
+ when Array
119
+ val = value.compact.first
120
+ val.class.base_class if val.is_a?(Base)
121
+ when Base
122
+ value.class.base_class
123
+ end
124
+ end
125
+
100
126
  def references(attributes)
101
127
  attributes.map do |key, value|
102
128
  if value.is_a?(Hash)
@@ -51,7 +51,7 @@ module Ardm
51
51
  # use that class rather than the primitive
52
52
  klass = Ardm::Property.determine_class(type)
53
53
 
54
- unless klass
54
+ if !klass || klass == NilClass
55
55
  raise ArgumentError, "+type+ was #{type.inspect}, which is not a supported type"
56
56
  end
57
57
 
@@ -100,7 +100,11 @@ module Ardm
100
100
  end
101
101
 
102
102
  def columns
103
- @columns ||= properties.map do |property|
103
+ @columns ||= _ardm_load_columns
104
+ end
105
+
106
+ def _ardm_load_columns
107
+ properties.map do |property|
104
108
  sql_type = connection.type_to_sql(
105
109
  property.dump_as.name.to_sym,
106
110
  property.options[:limit],
@@ -109,8 +113,7 @@ module Ardm
109
113
  )
110
114
 
111
115
  column = ::ActiveRecord::ConnectionAdapters::Column.new(
112
- #property.name.to_s,
113
- property.field.to_s,
116
+ property.field.to_s, #property.name.to_s,
114
117
  nil,#property.dump(property.default),
115
118
  sql_type,
116
119
  property.allow_nil?
@@ -141,6 +144,13 @@ module Ardm
141
144
  end
142
145
  end
143
146
 
147
+ def assert_valid_attributes(options)
148
+ options.each do |key, value|
149
+ property = properties[key]
150
+ property.assert_valid_value(value)
151
+ end
152
+ end
153
+
144
154
  # Gets the list of key fields for this Model
145
155
  #
146
156
  # @return [Array]
@@ -280,19 +290,21 @@ module Ardm
280
290
 
281
291
  # This not the same as read_attribute in AR
282
292
  def attribute_get(name)
283
- property = self.class.properties[name]
284
- val = read_attribute property.field
285
- if new_record? && val.nil? && property.default?
286
- write_attribute property.field, property.typecast(property.default_for(self))
293
+ if property = self.class.properties[name]
294
+ val = read_attribute property.field
295
+ if new_record? && val.nil? && property.default?
296
+ write_attribute property.field, property.typecast(property.default_for(self))
297
+ end
298
+ read_attribute property.field
287
299
  end
288
- read_attribute property.field
289
300
  end
290
301
 
291
302
  # This not the same as write_attribute in AR
292
303
  def attribute_set(name, value)
293
- property = self.class.properties[name]
294
- write_attribute property.field, property.typecast(value)
295
- read_attribute property.field
304
+ if property = self.class.properties[name]
305
+ write_attribute property.field, property.typecast(value)
306
+ read_attribute property.field
307
+ end
296
308
  end
297
309
 
298
310
  # Retrieve the key(s) for this resource.
@@ -52,10 +52,18 @@ module Ardm
52
52
  end
53
53
 
54
54
  def get(id)
55
- all(id: id).first
55
+ if Array === id && id.size == 1
56
+ # Model#key returns an array
57
+ id = id.first
58
+ end
59
+ where(primary_key => id).first
56
60
  end
57
61
 
58
62
  def get!(id)
63
+ if Array === id && id.size == 1
64
+ # Model#key returns an array
65
+ id = id.first
66
+ end
59
67
  find(id)
60
68
  end
61
69
 
@@ -71,23 +79,6 @@ module Ardm
71
79
  all(find_params).first_or_initialize
72
80
  end
73
81
 
74
- #def first(args=nil)
75
- # if Hash === args
76
- # all(args).first
77
- # else
78
- # puts "#{self}.first(#{args.inspect})"
79
- # puts caller[0..1]
80
- # super(args)
81
- # end
82
- #end
83
-
84
- #def all(options={})
85
- # puts "#{self}.all(#{options.inspect})"
86
- # puts caller[0..1]
87
- # binding.pry if options[:account]
88
- # Ardm::Query.all(self, options)
89
- #end
90
-
91
82
  #def exist?(options={})
92
83
  # puts "#{self}.exist?(#{options.inspect})"
93
84
  # puts caller[0..10]
@@ -9,42 +9,85 @@ module Ardm
9
9
 
10
10
  self.abstract_class = true
11
11
 
12
- JSON = Json
12
+ class_attribute :raise_on_save_failure
13
+ self.raise_on_save_failure = false
13
14
 
14
- def self.finalize
15
- end
15
+ JSON = Json
16
16
 
17
17
  def self.execute_sql(sql)
18
18
  connection.execute(sql)
19
19
  end
20
20
 
21
21
  def self.property(property_name, property_type, options={})
22
- property = super
22
+ prop = super
23
23
  begin
24
- attr_accessible property.name
25
- attr_accessible property.field
24
+ attr_accessible prop.name
25
+ attr_accessible prop.field
26
26
  rescue => e
27
- puts "WARNING: Error silenced. FIXME before release.\n#{e}"
27
+ puts "WARNING: Error silenced. FIXME before release.\n#{e}" unless $attr_accessible_warning
28
+ $attr_accessible_warning = true
28
29
  end
29
- property
30
+ prop
30
31
  end
31
32
 
32
33
  # no-op in active record
33
- def self.timestamps(*a)
34
+ def self.timestamps(at=:at)
35
+ case at
36
+ when :at
37
+ property :created_at, DateTime
38
+ property :updated_at, DateTime
39
+ when :on
40
+ property :created_on, Date
41
+ property :updated_on, Date
42
+ else
43
+ raise ArgumentError, "Unknown argument: timestamps(#{at.inspect})"
44
+ end
45
+ end
46
+
47
+ # The reflections returned here don't look like datamapper relationships.
48
+ # @todo improve this if needed with a wrapper
49
+ def self.relationships
50
+ reflections
51
+ end
52
+
53
+ def self.update(*a)
54
+ options = dump_properties_hash(a.first)
55
+ options = dump_associations_hash(options)
56
+ assert_valid_attributes(options)
57
+ update_all(options) != 0
34
58
  end
35
59
 
36
- def key
37
- id
60
+ def self.update!(*a)
61
+ options = dump_properties_hash(a.first)
62
+ options = dump_associations_hash(options)
63
+ assert_valid_attributes(options)
64
+ update_all(options) != 0
65
+ end
66
+
67
+ def self.destroy(*a)
68
+ destroy_all
69
+ end
70
+
71
+ def self.destroy!(*a)
72
+ delete_all
38
73
  end
39
74
 
40
75
  def new?
41
76
  new_record?
42
77
  end
43
78
 
79
+ def saved?
80
+ !new_record?
81
+ end
82
+
44
83
  def save_self(*)
45
84
  save
46
85
  end
47
86
 
87
+ def save
88
+ super || (raise_on_save_failure && raise(Ardm::SaveFailureError, "Save Failed"))
89
+ end
90
+
48
91
  def update(*a)
49
92
  if a.size == 1
50
93
  update_attributes(*a)
@@ -1,5 +1,5 @@
1
1
  require 'active_support/concern'
2
- require 'active_record'
2
+ require 'ardm/active_record/collection'
3
3
 
4
4
  module Ardm
5
5
  module ActiveRecord
@@ -15,7 +15,8 @@ module Ardm
15
15
  def update(*a)
16
16
  if a.size == 1
17
17
  # need to translate attributes
18
- options = @klass.send(:dump_properties_hash, a.first)
18
+ options = @klass.dump_properties_hash(a.first)
19
+ options = @klass.dump_associations_hash(options)
19
20
  update_all(options)
20
21
  else
21
22
  update_without_ardm(*a)
@@ -48,13 +49,42 @@ module Ardm
48
49
  apply_finder_options(options)
49
50
  end
50
51
 
52
+ #def apply_finder_options(options)
53
+ # return super if options.nil? || options.empty?
54
+ # options = options.dup
55
+ # conditions = options.slice!(*::ActiveRecord::SpawnMethods::VALID_FIND_OPTIONS)
56
+ # super(options).where(conditions)
57
+ #end
58
+
59
+ VALID_FIND_OPTIONS = [ :conditions, :include, :joins, :limit, :offset, :extend,
60
+ :order, :select, :readonly, :group, :having, :from, :lock ]
61
+
62
+ # We used to just patch this, like above, but we need to copy it over
63
+ # completely for rails4 since it no longer supports the old style finder
64
+ # methods that act more like the datamapper finders.
51
65
  def apply_finder_options(options)
52
- return super if options.nil? || options.empty?
53
- options = options.dup
54
- conditions = options.slice!(*::ActiveRecord::SpawnMethods::VALID_FIND_OPTIONS)
55
- super(options).where(conditions)
66
+ relation = clone
67
+ return relation if options.nil?
68
+
69
+ finders = options.dup
70
+ finders[:select] = finders.delete(:fields)
71
+ conditions = finders.slice!(*VALID_FIND_OPTIONS)
72
+
73
+ finders.delete_if { |key, value| value.nil? && key != :limit }
74
+
75
+ ([:joins, :select, :group, :order, :having, :limit, :offset, :from, :lock, :readonly] & finders.keys).each do |finder|
76
+ relation = relation.send(finder, finders[finder])
77
+ end
78
+
79
+ relation = relation.where(conditions) if conditions.any?
80
+ relation = relation.where(finders[:conditions]) if options.has_key?(:conditions)
81
+ relation = relation.includes(finders[:include]) if options.has_key?(:include)
82
+ relation = relation.extending(finders[:extend]) if options.has_key?(:extend)
83
+
84
+ relation
56
85
  end
57
86
 
87
+
58
88
  def calculate(operation, column_name, options={})
59
89
  if property = properties[column_name]
60
90
  column_name = property.field
@@ -5,12 +5,16 @@ module Ardm
5
5
  module Repository
6
6
  extend ActiveSupport::Concern
7
7
 
8
- def repository
8
+ def repository(name=nil)
9
9
  self.class.repository
10
10
  end
11
11
 
12
12
  module ClassMethods
13
- def repository
13
+ def repository(name=nil)
14
+ if name && name != :default
15
+ raise Ardm::NotImplemented, "Alternate repository names not supported"
16
+ end
17
+
14
18
  if block_given?
15
19
  yield
16
20
  else
@@ -2,4 +2,6 @@ require 'ardm/data_mapper/record'
2
2
 
3
3
  module Ardm
4
4
  Record = Ardm::DataMapper::Record
5
+ SaveFailureError = ::DataMapper::SaveFailureError
6
+ RecordNotFound = ::DataMapper::ObjectNotFoundError
5
7
  end
@@ -5,12 +5,11 @@ module Ardm
5
5
  module Record
6
6
  extend ActiveSupport::Concern
7
7
 
8
- NotFound = DataMapper::ObjectNotFoundError
9
-
10
8
  module ClassMethods
9
+ extend Forwardable
10
+
11
11
  def inherited(base)
12
12
  base.send(:include, DataMapper::Resource)
13
- base.send(:include, Awsm::Resource)
14
13
  #base.send(:extend, DataMapper::CollectionRaise)
15
14
 
16
15
  unless %w[Alert Association Nonce Account::Cancellation::Handler].include?(base.name)
@@ -18,13 +17,8 @@ module Ardm
18
17
  end
19
18
  end
20
19
 
21
- extend Forwardable
22
- def datamapper() DataMapper end
23
20
  def_delegators :datamapper, :repository, :finalize, :logger, :logger=
24
-
25
- def execute_sql(sql)
26
- DataMapper.repository.adapter.execute(sql)
27
- end
21
+ def datamapper() DataMapper end
28
22
 
29
23
  def alias_attribute(new, old)
30
24
  alias_method new, old
data/lib/ardm/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Ardm
2
- VERSION = '0.0.1'
2
+ VERSION = '0.1.0'
3
3
  end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ardm::ActiveRecord::DataMapperConstantProxy do
4
+ it 'defines Resource' do
5
+ expect(described_class::Resource).to be_kind_of(Module)
6
+ end
7
+
8
+ it 'defines ObjectNotFoundError to ActiveRecord::RecordNotFound' do
9
+ expect(described_class::ObjectNotFoundError).to be(ActiveRecord::RecordNotFound)
10
+ end
11
+
12
+ it 'defines SaveFailureError to ActiveRecord::RecordNotSaved' do
13
+ expect(described_class::SaveFailureError).to be(ActiveRecord::RecordNotSaved)
14
+ end
15
+
16
+ it 'responds to finalize' do
17
+ expect(described_class.respond_to?(:finalize)).to be_truthy
18
+ end
19
+
20
+ it 'responds to repository' do
21
+ expect(described_class.respond_to?(:repository)).to be_truthy
22
+ end
23
+
24
+ it 'responds to logger' do
25
+ expect(described_class.respond_to?(:logger)).to be_truthy
26
+ end
27
+
28
+ it 'responds to logger=' do
29
+ expect(described_class.respond_to?(:logger=)).to be_truthy
30
+ end
31
+ end
@@ -14,6 +14,8 @@ module Ardm
14
14
 
15
15
  property :slug, Slug
16
16
 
17
+ timestamps :at
18
+
17
19
  before_validation do
18
20
  self.slug = self.title
19
21
  end