ardm 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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