ardm 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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