ardm 0.1.0 → 0.2.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 (40) hide show
  1. data/.ruby-version +1 -0
  2. data/Gemfile +14 -2
  3. data/ardm.gemspec +1 -1
  4. data/lib/ardm.rb +8 -0
  5. data/lib/ardm/active_record.rb +0 -5
  6. data/lib/ardm/active_record/associations.rb +27 -10
  7. data/lib/ardm/active_record/predicate_builder/rails4.rb +12 -5
  8. data/lib/ardm/active_record/property.rb +4 -3
  9. data/lib/ardm/active_record/record.rb +10 -6
  10. data/lib/ardm/active_record/relation.rb +67 -2
  11. data/lib/ardm/data_mapper.rb +2 -0
  12. data/lib/ardm/data_mapper/record.rb +19 -22
  13. data/lib/ardm/property/support/paranoid_base.rb +1 -1
  14. data/lib/ardm/query/expression.rb +5 -15
  15. data/lib/ardm/query/operator.rb +3 -3
  16. data/lib/ardm/version.rb +1 -1
  17. data/spec/fixtures/article.rb +1 -1
  18. data/spec/fixtures/resource_blog.rb +53 -0
  19. data/spec/integration/comma_separated_list_spec.rb +4 -4
  20. data/spec/integration/dirty_minder_spec.rb +1 -1
  21. data/spec/integration/enum_spec.rb +2 -2
  22. data/spec/integration/epoch_time_spec.rb +2 -2
  23. data/spec/integration/file_path_spec.rb +4 -4
  24. data/spec/integration/flag_spec.rb +5 -3
  25. data/spec/integration/json_spec.rb +3 -3
  26. data/spec/public/model_spec.rb +78 -8
  27. data/spec/public/property_spec.rb +10 -6
  28. data/spec/public/resource_spec.rb +9 -64
  29. data/spec/shared/{finder_shared_spec.rb → finder_shared.rb} +134 -128
  30. data/spec/shared/{flags_shared_spec.rb → flags_shared.rb} +0 -0
  31. data/spec/shared/{public_property_spec.rb → public_property.rb} +0 -0
  32. data/spec/shared/{resource_spec.rb → resource.rb} +46 -31
  33. data/spec/shared/{semipublic_property_spec.rb → semipublic_property.rb} +0 -0
  34. data/spec/spec_helper.rb +11 -5
  35. data/spec/support/logger.rb +38 -0
  36. data/spec/unit/dirty_minder_spec.rb +4 -2
  37. data/spec/unit/paranoid_boolean_spec.rb +3 -3
  38. data/spec/unit/paranoid_datetime_spec.rb +3 -3
  39. metadata +59 -30
  40. checksums.yaml +0 -7
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 1.9.3
data/Gemfile CHANGED
@@ -3,10 +3,22 @@ source 'https://rubygems.org'
3
3
  gemspec
4
4
 
5
5
  gem 'pry'
6
+ gem 'pry-nav'
7
+ gem 'awesome_print'
6
8
 
7
9
  group :test do
8
10
  gem 'sqlite3'
9
- gem 'activerecord', '~> 3.2'
11
+ gem 'activerecord', '~> 4.0.0'
10
12
  gem 'addressable'
11
- gem 'database_cleaner'
13
+ gem 'database_cleaner', git: "git://github.com/lanej/database_cleaner.git", branch: "datamapper-fix"
14
+ gem 'rspec-its'
15
+ end
16
+
17
+ group :datamapper do
18
+ gem 'dm-core', '~> 1.2'
19
+ gem 'dm-sqlite-adapter', '~> 1.2'
20
+ gem 'dm-types', '~> 1.2', git: "git://github.com/engineyard/dm-types.git", branch: "1.2-multijson"
21
+ gem 'dm-validations', '~> 1.2'
22
+ gem 'dm-transactions', '~> 1.2'
23
+ gem 'dm-migrations', '~> 1.2'
12
24
  end
data/ardm.gemspec CHANGED
@@ -17,7 +17,7 @@ Gem::Specification.new do |gem|
17
17
  gem.require_paths = [ "lib" ]
18
18
  gem.version = Ardm::VERSION
19
19
 
20
- gem.add_runtime_dependency('activesupport', '>= 3.2')
20
+ gem.add_runtime_dependency('activesupport', '>= 3.2', '< 4.1')
21
21
  gem.add_runtime_dependency('bcrypt-ruby', '~> 3.0.0')
22
22
  gem.add_runtime_dependency('fastercsv', '~> 1.5.4')
23
23
  gem.add_runtime_dependency('multi_json', '> 1.3.2')
data/lib/ardm.rb CHANGED
@@ -44,6 +44,14 @@ module Ardm
44
44
  yield if block_given? && active_record?
45
45
  end
46
46
 
47
+ def self.rails3?
48
+ self.active_record? && ::ActiveRecord::VERSION::STRING >= "3.0" && ::ActiveRecord::VERSION::STRING <= "4.0"
49
+ end
50
+
51
+ def self.rails4?
52
+ self.active_record? && !self.rails3?
53
+ end
54
+
47
55
  # Yield if Ardm has loaded DataMapper ORM.
48
56
  #
49
57
  # @api public
@@ -40,11 +40,6 @@ module Ardm
40
40
  end
41
41
  end
42
42
 
43
-
44
- #::ActiveRecord::Base.class_eval do
45
- # include Ardm::ActiveRecord::Base
46
- #end
47
-
48
43
  ::ActiveRecord::Relation.class_eval do
49
44
  include Ardm::ActiveRecord::Relation
50
45
  end
@@ -1,4 +1,4 @@
1
- require 'active_support/concern'
1
+
2
2
 
3
3
  module Ardm
4
4
  module ActiveRecord
@@ -33,14 +33,20 @@ module Ardm
33
33
  ar[:foreign_key] = property.field
34
34
  end
35
35
 
36
- if (conditions = ar.slice!(*keep)).any?
37
- ar[:conditions] = conditions
36
+ if Ardm.rails3?
37
+ if (conditions = ar.slice!(*keep)).any?
38
+ ar[:conditions] = conditions
39
+ end
40
+ [ar]
41
+ else
42
+ block = if (conditions = ar.slice!(*keep)).any?
43
+ lambda { where(conditions) }
44
+ end
45
+ [block, ar].compact
38
46
  end
39
- ar
40
47
  end
41
48
 
42
49
  module ClassMethods
43
-
44
50
  def dump_associations_hash(options)
45
51
  options.inject({}) do |new_attrs, (key, value)|
46
52
  if reflection = reflect_on_association(key.to_sym)
@@ -73,9 +79,13 @@ module Ardm
73
79
  options.delete(:default)
74
80
  options.delete(:required)
75
81
  opts = Ardm::ActiveRecord::Associations.convert_options(self, options)
76
- super field, opts
82
+ super field, *opts
77
83
  assoc = reflect_on_association(field)
78
- property assoc.foreign_key, assoc.klass.key.first.class
84
+ Ardm::ActiveRecord::Record.on_finalize << lambda do
85
+ self.class_eval do
86
+ property assoc.foreign_key, assoc.klass.key.first.class, key: false
87
+ end
88
+ end
79
89
  nil
80
90
  end
81
91
 
@@ -97,9 +107,16 @@ module Ardm
97
107
  options[:order] = Ardm::ActiveRecord::Query.order(self, options[:order]) if options[:order]
98
108
  opts = Ardm::ActiveRecord::Associations.convert_options(self, options, :through, :order)
99
109
 
100
- case count
101
- when 1 then has_one name, opts
102
- when "many" then has_many name, opts
110
+ if Ardm.rails3?
111
+ case count
112
+ when 1 then has_one name, *opts
113
+ when "many" then has_many name, *opts
114
+ end
115
+ else
116
+ case count
117
+ when 1 then has_one name, *opts
118
+ when "many" then has_many name, *opts
119
+ end
103
120
  end
104
121
  end
105
122
 
@@ -58,19 +58,26 @@ module Ardm
58
58
  end
59
59
  else
60
60
  if Ardm::Query::Operator === column
61
- column = column.target.to_s
62
61
  operator = column.operator
62
+ target_column = column.target.to_s
63
63
  else
64
- column = column.to_s
64
+ target_column = column.to_s
65
65
  operator = nil
66
66
  end
67
67
 
68
- if column.include?('.')
69
- table_name, column = column.split('.', 2)
68
+ if target_column.include?('.')
69
+ table_name, target_column = target_column.split('.', 2)
70
70
  table = Arel::Table.new(table_name, default_table.engine)
71
71
  end
72
72
 
73
- queries.concat expand(klass, table, column, value)
73
+ query = expand(klass, table, target_column, value)
74
+ # TODO make nicer
75
+ if [:not_eq, :not_in].include?(operator)
76
+ # Logical not factorization !(a && b) == (!a || !b)
77
+ query.map! &:not
78
+ query = [query.inject { |composite, predicate| composite.or(predicate) }]
79
+ end
80
+ queries.concat query
74
81
  end
75
82
  end
76
83
 
@@ -212,7 +212,7 @@ module Ardm
212
212
 
213
213
  def set_primary_key_for(property)
214
214
  if property.key? || property.serial?
215
- self.primary_key = property.name
215
+ self.primary_key ||= property.name
216
216
  end
217
217
  end
218
218
 
@@ -223,7 +223,6 @@ module Ardm
223
223
  return if property.key? || property.serial? # let AR do it
224
224
  name = property.name.to_s
225
225
  reader_visibility = property.reader_visibility
226
- instance_variable_name = property.instance_variable_name
227
226
  property_module.module_eval <<-RUBY, __FILE__, __LINE__ + 1
228
227
  #{reader_visibility}
229
228
  def #{name}
@@ -254,7 +253,7 @@ module Ardm
254
253
  property_module.module_eval <<-RUBY, __FILE__, __LINE__ + 1
255
254
  #{writer_visibility}
256
255
  def #{writer_name}(value)
257
- attribute_set(#{name.inspect}, value)
256
+ attribute_set(:#{name}, value)
258
257
  end
259
258
  RUBY
260
259
  end
@@ -328,6 +327,8 @@ module Ardm
328
327
 
329
328
  # only memoize a valid key
330
329
  @_key = key if model_key.valid?(key)
330
+
331
+ key
331
332
  end
332
333
 
333
334
  # Gets this instance's Model's properties
@@ -21,8 +21,8 @@ module Ardm
21
21
  def self.property(property_name, property_type, options={})
22
22
  prop = super
23
23
  begin
24
- attr_accessible prop.name
25
- attr_accessible prop.field
24
+ attr_accessible prop.name
25
+ attr_accessible prop.field
26
26
  rescue => e
27
27
  puts "WARNING: Error silenced. FIXME before release.\n#{e}" unless $attr_accessible_warning
28
28
  $attr_accessible_warning = true
@@ -72,6 +72,10 @@ module Ardm
72
72
  delete_all
73
73
  end
74
74
 
75
+ def destroy
76
+ self.class.delete(self.send(self.class.primary_key))
77
+ end
78
+
75
79
  def new?
76
80
  new_record?
77
81
  end
@@ -80,12 +84,12 @@ module Ardm
80
84
  !new_record?
81
85
  end
82
86
 
83
- def save_self(*)
84
- save
87
+ def save_self(*args)
88
+ save(*args)
85
89
  end
86
90
 
87
- def save
88
- super || (raise_on_save_failure && raise(Ardm::SaveFailureError, "Save Failed"))
91
+ def save!(*args)
92
+ save(*args) || (raise_on_save_failure && raise(Ardm::SaveFailureError, "Save Failed"))
89
93
  end
90
94
 
91
95
  def update(*a)
@@ -57,7 +57,7 @@ module Ardm
57
57
  #end
58
58
 
59
59
  VALID_FIND_OPTIONS = [ :conditions, :include, :joins, :limit, :offset, :extend,
60
- :order, :select, :readonly, :group, :having, :from, :lock ]
60
+ :order, :select, :readonly, :group, :having, :from, :lock ]
61
61
 
62
62
  # We used to just patch this, like above, but we need to copy it over
63
63
  # completely for rails4 since it no longer supports the old style finder
@@ -76,7 +76,72 @@ module Ardm
76
76
  relation = relation.send(finder, finders[finder])
77
77
  end
78
78
 
79
- relation = relation.where(conditions) if conditions.any?
79
+ conditions.each do |key, value|
80
+ if assoc = relation.reflect_on_association(key)
81
+ conditions.delete(key)
82
+ # strip out assocations
83
+ case assoc.macro
84
+ when :belongs_to
85
+ id = value.is_a?(Hash) ? value.with_indifferent_access[:id] : value
86
+ relation = if value.is_a?(::ActiveRecord::Relation)
87
+ if value.values.empty?
88
+ relation.where.not(assoc.foreign_key => nil)
89
+ else
90
+ relation.where(assoc.foreign_key => value)
91
+ end
92
+ else
93
+ relation.where(assoc.foreign_key => id)
94
+ end
95
+ when :has_one
96
+ foreign_class = assoc.options[:class_name].constantize
97
+ foreign_key = assoc.foreign_key
98
+ parent_key = assoc.options[:child_key] || klass.primary_key
99
+
100
+ if value.is_a?(::Array) && value.empty?
101
+ # @fixme: dm basically no-ops cause it knows you are stupid
102
+ return klass.where(klass.primary_key => nil)
103
+ end
104
+
105
+ relation = if value.is_a?(::ActiveRecord::Base)
106
+ relation.where(parent_key => value.send(assoc.foreign_key))
107
+ elsif value.is_a?(::ActiveRecord::Relation)
108
+ relation.where(parent_key => value.select(foreign_key))
109
+ elsif value.nil?
110
+ relation.where.not(parent_key => foreign_class.select(foreign_key).where.not(foreign_key => value))
111
+ else
112
+ relation.where(parent_key => foreign_class.select(foreign_key).where(value))
113
+ end
114
+ when :has_many
115
+ foreign_class = assoc.options[:class_name].constantize
116
+ foreign_key = assoc.foreign_key
117
+ parent_key = assoc.options[:child_key] || klass.primary_key
118
+
119
+ relation = if value.is_a?(::ActiveRecord::Relation)
120
+ relation.where(foreign_key => value)
121
+ else
122
+ relation.where(parent_key => foreign_class.select(foreign_class.primary_key).where.not(foreign_key => value))
123
+ end
124
+ else
125
+ raise("unknown: #{assoc.inspect}")
126
+ end
127
+ end
128
+ end
129
+
130
+ processed_conditions = {}
131
+
132
+ conditions.each do |key, value|
133
+ key = key.is_a?(Ardm::Property) ? key.name : key
134
+
135
+ case key
136
+ when String, Symbol then
137
+ processed_conditions[key] = value
138
+ when Ardm::Query::Operator then
139
+ relation = key.to_arel(self, value).scope
140
+ else raise "unknown key: #{key.inspect} #{value.inspect}"
141
+ end
142
+ end
143
+
144
+ relation = relation.where(processed_conditions) if processed_conditions.any?
80
145
  relation = relation.where(finders[:conditions]) if options.has_key?(:conditions)
81
146
  relation = relation.includes(finders[:include]) if options.has_key?(:include)
82
147
  relation = relation.extending(finders[:extend]) if options.has_key?(:extend)
@@ -4,4 +4,6 @@ module Ardm
4
4
  Record = Ardm::DataMapper::Record
5
5
  SaveFailureError = ::DataMapper::SaveFailureError
6
6
  RecordNotFound = ::DataMapper::ObjectNotFoundError
7
+ Property = ::DataMapper::Property
8
+ Collection = ::DataMapper::Collection
7
9
  end
@@ -1,34 +1,31 @@
1
- require 'awsm/resource'
1
+ require 'active_support/concern'
2
+ require 'dm-core'
2
3
 
3
4
  module Ardm
4
5
  module DataMapper
5
- module Record
6
- extend ActiveSupport::Concern
6
+ class Record
7
+ extend Forwardable
7
8
 
8
- module ClassMethods
9
- extend Forwardable
10
-
11
- def inherited(base)
12
- base.send(:include, DataMapper::Resource)
13
- #base.send(:extend, DataMapper::CollectionRaise)
9
+ def self.inherited(base)
10
+ base.send(:include, ::DataMapper::Resource)
11
+ end
14
12
 
15
- unless %w[Alert Association Nonce Account::Cancellation::Handler].include?(base.name)
16
- base.timestamps :at
17
- end
18
- end
13
+ def self.finalize
14
+ ::DataMapper.finalize
15
+ end
19
16
 
20
- def_delegators :datamapper, :repository, :finalize, :logger, :logger=
21
- def datamapper() DataMapper end
17
+ def self.alias_attribute(new, old)
18
+ alias_method new, old
19
+ end
22
20
 
23
- def alias_attribute(new, old)
24
- alias_method new, old
25
- end
21
+ def self.attr_accessible(*attrs)
22
+ end
26
23
 
27
- def attr_accessible(*attrs)
28
- end
24
+ def self.abstract_class=(val)
25
+ end
29
26
 
30
- def abstract_class=(val)
31
- end
27
+ def self.table_name=(name)
28
+ self.storage_names[:default] = name
32
29
  end
33
30
  end
34
31
  end
@@ -41,7 +41,7 @@ module Ardm
41
41
 
42
42
  # @api public
43
43
  def with_deleted(&block)
44
- with_deleted_scope = self.scoped.with_default_scope
44
+ with_deleted_scope = self.all.with_default_scope
45
45
  paranoid_scopes.each do |cond|
46
46
  with_deleted_scope.where_values.delete(cond)
47
47
  end
@@ -7,20 +7,11 @@ module Ardm
7
7
  new(relation, target, value).scope
8
8
  end
9
9
 
10
- def initialize(relation, target, value)
10
+ def initialize(relation, target, operator, value)
11
11
  @relation = relation
12
12
  @value = value
13
-
14
- case target
15
- when Ardm::Query::Operator
16
- @target = target.target
17
- @operator = target.operator
18
- when Symbol, String
19
- @target = target
20
- @operator = :eq
21
- else
22
- raise ArgumentError, "Unknown target #{target.inspect} in Expresion"
23
- end
13
+ @target = target
14
+ @operator = operator
24
15
  end
25
16
 
26
17
  def resolved_target
@@ -54,14 +45,13 @@ module Ardm
54
45
  if association.macro == :belongs_to
55
46
  association.foreign_key.to_sym
56
47
  else
57
- $stderr.puts "WARNING: #{association.macro} based queries not yet supported?"
58
- association.primary_key.to_sym
48
+ association.klass.primary_key.to_sym
59
49
  end
60
50
  end
61
51
  end
62
52
 
63
53
  def arel_operator
64
- value.respond_to?(:to_ary) ? operator.for_array : operator
54
+ value.respond_to?(:to_ary) ? operator.for_array : operator.operator
65
55
  end
66
56
 
67
57
  def arel_value(val = value)
@@ -7,7 +7,7 @@ module Ardm
7
7
  OPERATORS = {
8
8
  # DM => ARel
9
9
  :eql => :eq,
10
- :not => :not,
10
+ :not => :not_eq,
11
11
  :in => :in,
12
12
  :gt => :gt,
13
13
  :gte => :gteq,
@@ -47,8 +47,8 @@ module Ardm
47
47
  FOR_ARRAY[operator]
48
48
  end
49
49
 
50
- def to_arel(arel_table, value)
51
- Ardm::Query::Expression.new(arel_table, target, operator, value)
50
+ def to_arel(relation, value)
51
+ Ardm::Query::Expression.new(relation, target, self, value)
52
52
  end
53
53
 
54
54
  private