ardm 0.0.1
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.
- checksums.yaml +15 -0
- data/.gitignore +35 -0
- data/Gemfile +13 -0
- data/LICENSE +21 -0
- data/README.md +70 -0
- data/Rakefile +4 -0
- data/ardm.gemspec +29 -0
- data/db/.gitignore +1 -0
- data/lib/ardm/active_record/associations.rb +80 -0
- data/lib/ardm/active_record/base.rb +49 -0
- data/lib/ardm/active_record/dirty.rb +25 -0
- data/lib/ardm/active_record/hooks.rb +31 -0
- data/lib/ardm/active_record/inheritance.rb +37 -0
- data/lib/ardm/active_record/is/state_machine.rb +21 -0
- data/lib/ardm/active_record/is.rb +22 -0
- data/lib/ardm/active_record/not_found.rb +7 -0
- data/lib/ardm/active_record/predicate_builder/array_handler.rb +31 -0
- data/lib/ardm/active_record/predicate_builder/rails3.rb +147 -0
- data/lib/ardm/active_record/predicate_builder/rails4.rb +139 -0
- data/lib/ardm/active_record/predicate_builder/relation_handler.rb +15 -0
- data/lib/ardm/active_record/predicate_builder.rb +19 -0
- data/lib/ardm/active_record/property.rb +357 -0
- data/lib/ardm/active_record/query.rb +108 -0
- data/lib/ardm/active_record/record.rb +70 -0
- data/lib/ardm/active_record/relation.rb +83 -0
- data/lib/ardm/active_record/repository.rb +38 -0
- data/lib/ardm/active_record/serialization.rb +164 -0
- data/lib/ardm/active_record/storage_names.rb +28 -0
- data/lib/ardm/active_record/validations.rb +111 -0
- data/lib/ardm/active_record.rb +43 -0
- data/lib/ardm/data_mapper/not_found.rb +5 -0
- data/lib/ardm/data_mapper/record.rb +41 -0
- data/lib/ardm/data_mapper.rb +5 -0
- data/lib/ardm/env.rb +5 -0
- data/lib/ardm/property/api_key.rb +30 -0
- data/lib/ardm/property/bcrypt_hash.rb +31 -0
- data/lib/ardm/property/binary.rb +23 -0
- data/lib/ardm/property/boolean.rb +29 -0
- data/lib/ardm/property/class.rb +19 -0
- data/lib/ardm/property/comma_separated_list.rb +28 -0
- data/lib/ardm/property/csv.rb +35 -0
- data/lib/ardm/property/date.rb +12 -0
- data/lib/ardm/property/datetime.rb +12 -0
- data/lib/ardm/property/decimal.rb +38 -0
- data/lib/ardm/property/discriminator.rb +65 -0
- data/lib/ardm/property/enum.rb +51 -0
- data/lib/ardm/property/epoch_time.rb +38 -0
- data/lib/ardm/property/file_path.rb +25 -0
- data/lib/ardm/property/flag.rb +65 -0
- data/lib/ardm/property/float.rb +18 -0
- data/lib/ardm/property/integer.rb +24 -0
- data/lib/ardm/property/invalid_value_error.rb +22 -0
- data/lib/ardm/property/ip_address.rb +35 -0
- data/lib/ardm/property/json.rb +49 -0
- data/lib/ardm/property/lookup.rb +29 -0
- data/lib/ardm/property/numeric.rb +40 -0
- data/lib/ardm/property/object.rb +36 -0
- data/lib/ardm/property/paranoid_boolean.rb +18 -0
- data/lib/ardm/property/paranoid_datetime.rb +17 -0
- data/lib/ardm/property/regexp.rb +22 -0
- data/lib/ardm/property/serial.rb +16 -0
- data/lib/ardm/property/slug.rb +29 -0
- data/lib/ardm/property/string.rb +40 -0
- data/lib/ardm/property/support/dirty_minder.rb +169 -0
- data/lib/ardm/property/support/flags.rb +41 -0
- data/lib/ardm/property/support/paranoid_base.rb +78 -0
- data/lib/ardm/property/text.rb +11 -0
- data/lib/ardm/property/time.rb +12 -0
- data/lib/ardm/property/uri.rb +27 -0
- data/lib/ardm/property/uuid.rb +65 -0
- data/lib/ardm/property/validation.rb +208 -0
- data/lib/ardm/property/yaml.rb +38 -0
- data/lib/ardm/property.rb +891 -0
- data/lib/ardm/property_set.rb +152 -0
- data/lib/ardm/query/expression.rb +85 -0
- data/lib/ardm/query/ext/symbol.rb +37 -0
- data/lib/ardm/query/operator.rb +64 -0
- data/lib/ardm/record.rb +1 -0
- data/lib/ardm/support/assertions.rb +8 -0
- data/lib/ardm/support/deprecate.rb +12 -0
- data/lib/ardm/support/descendant_set.rb +89 -0
- data/lib/ardm/support/equalizer.rb +48 -0
- data/lib/ardm/support/ext/array.rb +22 -0
- data/lib/ardm/support/ext/blank.rb +25 -0
- data/lib/ardm/support/ext/hash.rb +67 -0
- data/lib/ardm/support/ext/module.rb +47 -0
- data/lib/ardm/support/ext/object.rb +57 -0
- data/lib/ardm/support/ext/string.rb +24 -0
- data/lib/ardm/support/ext/try_dup.rb +12 -0
- data/lib/ardm/support/hook.rb +405 -0
- data/lib/ardm/support/lazy_array.rb +451 -0
- data/lib/ardm/support/local_object_space.rb +13 -0
- data/lib/ardm/support/logger.rb +201 -0
- data/lib/ardm/support/mash.rb +176 -0
- data/lib/ardm/support/naming_conventions.rb +90 -0
- data/lib/ardm/support/ordered_set.rb +380 -0
- data/lib/ardm/support/subject.rb +33 -0
- data/lib/ardm/support/subject_set.rb +250 -0
- data/lib/ardm/version.rb +3 -0
- data/lib/ardm.rb +56 -0
- data/spec/fixtures/api_user.rb +11 -0
- data/spec/fixtures/article.rb +22 -0
- data/spec/fixtures/bookmark.rb +14 -0
- data/spec/fixtures/invention.rb +5 -0
- data/spec/fixtures/network_node.rb +23 -0
- data/spec/fixtures/person.rb +17 -0
- data/spec/fixtures/software_package.rb +22 -0
- data/spec/fixtures/ticket.rb +12 -0
- data/spec/fixtures/tshirt.rb +15 -0
- data/spec/integration/api_key_spec.rb +25 -0
- data/spec/integration/bcrypt_hash_spec.rb +45 -0
- data/spec/integration/comma_separated_list_spec.rb +85 -0
- data/spec/integration/dirty_minder_spec.rb +197 -0
- data/spec/integration/enum_spec.rb +79 -0
- data/spec/integration/epoch_time_spec.rb +59 -0
- data/spec/integration/file_path_spec.rb +158 -0
- data/spec/integration/flag_spec.rb +72 -0
- data/spec/integration/ip_address_spec.rb +151 -0
- data/spec/integration/json_spec.rb +70 -0
- data/spec/integration/slug_spec.rb +65 -0
- data/spec/integration/uri_spec.rb +136 -0
- data/spec/integration/uuid_spec.rb +102 -0
- data/spec/integration/yaml_spec.rb +85 -0
- data/spec/public/property/binary_spec.rb +41 -0
- data/spec/public/property/boolean_spec.rb +30 -0
- data/spec/public/property/class_spec.rb +28 -0
- data/spec/public/property/date_spec.rb +22 -0
- data/spec/public/property/date_time_spec.rb +22 -0
- data/spec/public/property/decimal_spec.rb +23 -0
- data/spec/public/property/discriminator_spec.rb +133 -0
- data/spec/public/property/float_spec.rb +22 -0
- data/spec/public/property/integer_spec.rb +22 -0
- data/spec/public/property/object_spec.rb +103 -0
- data/spec/public/property/serial_spec.rb +22 -0
- data/spec/public/property/string_spec.rb +22 -0
- data/spec/public/property/text_spec.rb +23 -0
- data/spec/public/property/time_spec.rb +22 -0
- data/spec/public/property_spec.rb +316 -0
- data/spec/rcov.opts +6 -0
- data/spec/schema.rb +86 -0
- data/spec/semipublic/property/binary_spec.rb +14 -0
- data/spec/semipublic/property/boolean_spec.rb +48 -0
- data/spec/semipublic/property/class_spec.rb +36 -0
- data/spec/semipublic/property/date_spec.rb +44 -0
- data/spec/semipublic/property/date_time_spec.rb +47 -0
- data/spec/semipublic/property/decimal_spec.rb +83 -0
- data/spec/semipublic/property/discriminator_spec.rb +22 -0
- data/spec/semipublic/property/float_spec.rb +83 -0
- data/spec/semipublic/property/integer_spec.rb +83 -0
- data/spec/semipublic/property/lookup_spec.rb +27 -0
- data/spec/semipublic/property/serial_spec.rb +14 -0
- data/spec/semipublic/property/string_spec.rb +14 -0
- data/spec/semipublic/property/text_spec.rb +30 -0
- data/spec/semipublic/property/time_spec.rb +49 -0
- data/spec/semipublic/property_spec.rb +51 -0
- data/spec/shared/flags_shared_spec.rb +36 -0
- data/spec/shared/identity_function_group.rb +5 -0
- data/spec/shared/public_property_spec.rb +229 -0
- data/spec/shared/semipublic_property_spec.rb +159 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +58 -0
- data/spec/unit/bcrypt_hash_spec.rb +154 -0
- data/spec/unit/csv_spec.rb +139 -0
- data/spec/unit/dirty_minder_spec.rb +64 -0
- data/spec/unit/enum_spec.rb +125 -0
- data/spec/unit/epoch_time_spec.rb +72 -0
- data/spec/unit/file_path_spec.rb +75 -0
- data/spec/unit/flag_spec.rb +114 -0
- data/spec/unit/ip_address_spec.rb +109 -0
- data/spec/unit/json_spec.rb +127 -0
- data/spec/unit/paranoid_boolean_spec.rb +142 -0
- data/spec/unit/paranoid_datetime_spec.rb +149 -0
- data/spec/unit/regexp_spec.rb +62 -0
- data/spec/unit/uri_spec.rb +64 -0
- data/spec/unit/yaml_spec.rb +111 -0
- data/tasks/spec.rake +40 -0
- data/tasks/yard.rake +9 -0
- data/tasks/yardstick.rake +19 -0
- metadata +350 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
!binary "U0hBMQ==":
|
|
3
|
+
metadata.gz: !binary |-
|
|
4
|
+
Mzk3NGRlZjc5N2E0Nzc4MjFkZmI5ZDA3MWNiNDVjNTE3NzQ1ZTM5Mg==
|
|
5
|
+
data.tar.gz: !binary |-
|
|
6
|
+
YmZlNzI5MzMzMjdlZDQwYjExZjcxYjZiNjA5YTkyZTBmM2QxOGZlMQ==
|
|
7
|
+
SHA512:
|
|
8
|
+
metadata.gz: !binary |-
|
|
9
|
+
ZmViYjY2MmFiMjRmOGZiM2U1M2ZhY2MyN2I4YzJhZDc4NDcyYTcwZWE3ODQy
|
|
10
|
+
MTA5OWQ2ODUzMmRhN2M3ZWM2MWUyODkxOWU0ZmU2OTFjZGIwN2Y1ZmVkZGNh
|
|
11
|
+
Nzk3M2I3NzhmOTNiZDcxNjVkY2E2ZWE2MTY1MmQ1NGIwMjc3OTI=
|
|
12
|
+
data.tar.gz: !binary |-
|
|
13
|
+
NzcxYzU2NDRiMjU5NjVkYTVhNjNiZGEyMGRhYWVlYmYxOTc2ZDBhN2Q0YjE2
|
|
14
|
+
NzI3MTYzNDg5ODRjZTY1Y2U1N2JiYmMzZDdmNDlhYTBkYmZiYTJiMmFjMjk1
|
|
15
|
+
MWUzMmExYjQ5NGQxN2IxZjc2ZTIwZGU0ZGIzNzE4ZGM5Y2JiYTg=
|
data/.gitignore
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
## MAC OS
|
|
2
|
+
.DS_Store
|
|
3
|
+
._*
|
|
4
|
+
|
|
5
|
+
## TEXTMATE
|
|
6
|
+
*.tmproj
|
|
7
|
+
tmtags
|
|
8
|
+
|
|
9
|
+
## EMACS
|
|
10
|
+
*~
|
|
11
|
+
\#*
|
|
12
|
+
.\#*
|
|
13
|
+
|
|
14
|
+
## VIM
|
|
15
|
+
*.swp
|
|
16
|
+
|
|
17
|
+
## Rubinius
|
|
18
|
+
*.rbc
|
|
19
|
+
|
|
20
|
+
## PROJECT::GENERAL
|
|
21
|
+
*.gem
|
|
22
|
+
coverage
|
|
23
|
+
rdoc
|
|
24
|
+
pkg
|
|
25
|
+
tmp
|
|
26
|
+
doc
|
|
27
|
+
log
|
|
28
|
+
.yardoc
|
|
29
|
+
measurements
|
|
30
|
+
|
|
31
|
+
## BUNDLER
|
|
32
|
+
.bundle
|
|
33
|
+
Gemfile.*
|
|
34
|
+
|
|
35
|
+
## PROJECT::SPECIFIC
|
data/Gemfile
ADDED
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
Code to adapt dm-types and dm-core properties to Active Record copyright (c) 2013 Martin Emde
|
|
2
|
+
Code from dm-types and dm-core originally Copyright (c) 2011 Sam Smoot, Dan Kubb
|
|
3
|
+
|
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
5
|
+
a copy of this software and associated documentation files (the
|
|
6
|
+
"Software"), to deal in the Software without restriction, including
|
|
7
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
8
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
9
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
10
|
+
the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be
|
|
13
|
+
included in all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
17
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
19
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
20
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
21
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Ardm
|
|
2
|
+
|
|
3
|
+
ActiveRecord plugin to provide a smooth migration from DataMapper to ActiveRecord.
|
|
4
|
+
|
|
5
|
+
## Why
|
|
6
|
+
|
|
7
|
+
Ardm is intended for applications running Rails with DataMapper 1.2 who need
|
|
8
|
+
to migrate to ActiveRecord. Lets examine some of the reasons why you might
|
|
9
|
+
move to ActiveRecord.
|
|
10
|
+
|
|
11
|
+
* DataMapper is no longer under development. Ruby Object Mapper (ROM) is the
|
|
12
|
+
imlicit replacement for DataMapper, but it's not a supported migration. ROM
|
|
13
|
+
is a completely new codebase and very few of the idioms transfer.
|
|
14
|
+
* DataMapper produces inefficient queries. Includes, joins, and subqueries are
|
|
15
|
+
either not supported or incorrect. Enabling subqueries in DM speeds up queries
|
|
16
|
+
but causes other subtle query problems than can produce bad SQL that may
|
|
17
|
+
select incorrect records.
|
|
18
|
+
* DataMapper cannot currently run on Rails4. Someone may take the initiative to
|
|
19
|
+
upgrade DataMapper to work on Rails4, but I think you're much better off
|
|
20
|
+
moving to ActiveRecord.
|
|
21
|
+
* Arel is awesome. ActiveRecord and Arel together is quite nice. With the added
|
|
22
|
+
support properties and the advances in Rails4, I think this upgrade is a must.
|
|
23
|
+
* ActiveRecord is used in more applications, better tested, and more performant.
|
|
24
|
+
|
|
25
|
+
## Installation
|
|
26
|
+
|
|
27
|
+
Incremental migration from DataMapper to ActiveRecord.
|
|
28
|
+
|
|
29
|
+
ActiveRecord requires your models to inherit from ActiveRecord::Base, but makes
|
|
30
|
+
it difficult to approach the migration incrementally. All or nothing is a scary
|
|
31
|
+
way to switch ORMs. To solve this, Ardm supplies Ardm::Record.
|
|
32
|
+
|
|
33
|
+
Ardm::Record will be the new base class. You'll need to search and replace
|
|
34
|
+
all models that include DataMapper::Resource, remove it, and add Ardm::Record
|
|
35
|
+
as the base class. If your model is STI, add it to the base model and remove
|
|
36
|
+
DataMapper::Resource from all models.
|
|
37
|
+
|
|
38
|
+
Example:
|
|
39
|
+
|
|
40
|
+
class MyModel
|
|
41
|
+
include DataMapper::Resource
|
|
42
|
+
# ...
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# The model above changes to:
|
|
46
|
+
|
|
47
|
+
class MyModel < Ardm::Record
|
|
48
|
+
# ...
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
With this new base clase you can switch between ActiveRecord and DataMapper
|
|
52
|
+
by flipping a swith in your application. This approach allows you to continue
|
|
53
|
+
developing your application in DataMapper while you work on teasing out all
|
|
54
|
+
the "datamapper-isms" from your code. This library attempts to take care of
|
|
55
|
+
most DataMapper features, but there are probably tons of small variations
|
|
56
|
+
that are not accounted for.
|
|
57
|
+
|
|
58
|
+
## Usage
|
|
59
|
+
|
|
60
|
+
require 'ardm'
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
## Copyright
|
|
65
|
+
|
|
66
|
+
This is an adaptation of the original DataMapper source code to allow
|
|
67
|
+
users of the now defunct DataMapper to migrate to ActiveRecord.
|
|
68
|
+
Much of this code was originally written by Sam Smoot and Dan Kubb as
|
|
69
|
+
[dm-types](https://github.com/datamapper/dm-types) and
|
|
70
|
+
[dm-core](https://github.com/datamapper/dm-core). See LICENSE for details.
|
data/Rakefile
ADDED
data/ardm.gemspec
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
require File.expand_path('../lib/ardm/version', __FILE__)
|
|
3
|
+
|
|
4
|
+
Gem::Specification.new do |gem|
|
|
5
|
+
gem.authors = [ 'Martin Emde', 'Dan Kubb' ]
|
|
6
|
+
gem.email = [ "me@martinemde.com" ]
|
|
7
|
+
gem.summary = "ActiveRecord plugin to provide a smooth migration from DataMapper to ActiveRecord"
|
|
8
|
+
gem.description = gem.summary
|
|
9
|
+
gem.homepage = "http://github.com/engineyard/ardm"
|
|
10
|
+
|
|
11
|
+
gem.files = `git ls-files`.split("\n")
|
|
12
|
+
gem.test_files = `git ls-files -- {spec}/*`.split("\n")
|
|
13
|
+
gem.extra_rdoc_files = %w[LICENSE README.md]
|
|
14
|
+
|
|
15
|
+
gem.name = "ardm"
|
|
16
|
+
gem.require_paths = [ "lib" ]
|
|
17
|
+
gem.version = Ardm::VERSION
|
|
18
|
+
|
|
19
|
+
gem.add_runtime_dependency('activesupport', '>= 3.2')
|
|
20
|
+
gem.add_runtime_dependency('bcrypt-ruby', '~> 3.0.0')
|
|
21
|
+
gem.add_runtime_dependency('fastercsv', '~> 1.5.4')
|
|
22
|
+
gem.add_runtime_dependency('multi_json', '> 1.3.2')
|
|
23
|
+
gem.add_runtime_dependency('stringex', '~> 1.3.3')
|
|
24
|
+
gem.add_runtime_dependency('uuidtools', '~> 2.1.2')
|
|
25
|
+
gem.add_runtime_dependency('coercible')
|
|
26
|
+
|
|
27
|
+
gem.add_development_dependency('rake', '~> 0.9.2')
|
|
28
|
+
gem.add_development_dependency('rspec', '~> 2.0')
|
|
29
|
+
end
|
data/db/.gitignore
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
*.sqlite
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
require 'active_support/concern'
|
|
2
|
+
|
|
3
|
+
module Ardm
|
|
4
|
+
module ActiveRecord
|
|
5
|
+
module Associations
|
|
6
|
+
extend ActiveSupport::Concern
|
|
7
|
+
|
|
8
|
+
def assign_attributes(attrs, *a)
|
|
9
|
+
new_attrs = attrs.inject({}) do |memo,(k,v)|
|
|
10
|
+
if assoc = self.class.reflect_on_association(k)
|
|
11
|
+
memo[assoc.foreign_key] = v && v.send(v.class.primary_key)
|
|
12
|
+
else
|
|
13
|
+
memo[k] = v
|
|
14
|
+
end
|
|
15
|
+
memo
|
|
16
|
+
end
|
|
17
|
+
super new_attrs, *a
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# Convert options from DM style to AR style.
|
|
22
|
+
#
|
|
23
|
+
# Keep any unknown keys to use as conditions.
|
|
24
|
+
def self.convert_options(klass, options, *keep)
|
|
25
|
+
keep += [:class_name, :foreign_key]
|
|
26
|
+
|
|
27
|
+
ar = options.dup
|
|
28
|
+
ar[:class_name] = ar.delete(:model) if ar[:model]
|
|
29
|
+
ar[:foreign_key] = ar.delete(:child_key) if ar[:child_key]
|
|
30
|
+
ar[:foreign_key] = ar[:foreign_key].first if ar[:foreign_key].respond_to?(:to_ary)
|
|
31
|
+
|
|
32
|
+
if ar[:foreign_key] && property = klass.properties[ar[:foreign_key]]
|
|
33
|
+
ar[:foreign_key] = property.field
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
if (conditions = ar.slice!(*keep)).any?
|
|
37
|
+
ar[:conditions] = conditions
|
|
38
|
+
end
|
|
39
|
+
ar
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
module ClassMethods
|
|
43
|
+
def belongs_to(field, options={})
|
|
44
|
+
options.delete(:default)
|
|
45
|
+
options.delete(:required)
|
|
46
|
+
opts = Ardm::ActiveRecord::Associations.convert_options(self, options)
|
|
47
|
+
super field, opts
|
|
48
|
+
assoc = reflect_on_association(field)
|
|
49
|
+
property assoc.foreign_key, Ardm::Property::Integer
|
|
50
|
+
nil
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def n
|
|
54
|
+
"many"
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def has(count, name, *args)
|
|
58
|
+
options = args.shift || {}
|
|
59
|
+
|
|
60
|
+
if String === options # has n, :name, 'Class', options: 'here'
|
|
61
|
+
options = (args.last || {}).merge(:model => options)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
unless Hash === options
|
|
65
|
+
raise ArgumentError, "bad has #{count} options format #{options.inspect}"
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
options[:order] = Ardm::ActiveRecord::Query.order(self, options[:order]) if options[:order]
|
|
69
|
+
opts = Ardm::ActiveRecord::Associations.convert_options(self, options, :through, :order)
|
|
70
|
+
|
|
71
|
+
case count
|
|
72
|
+
when 1 then has_one name, opts
|
|
73
|
+
when "many" then has_many name, opts
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
require 'active_support/concern'
|
|
2
|
+
|
|
3
|
+
require 'ardm/active_record/associations'
|
|
4
|
+
require 'ardm/active_record/dirty'
|
|
5
|
+
require 'ardm/active_record/hooks'
|
|
6
|
+
require 'ardm/active_record/is'
|
|
7
|
+
require 'ardm/active_record/inheritance'
|
|
8
|
+
require 'ardm/active_record/property'
|
|
9
|
+
require 'ardm/active_record/query'
|
|
10
|
+
require 'ardm/active_record/repository'
|
|
11
|
+
require 'ardm/active_record/storage_names'
|
|
12
|
+
require 'ardm/active_record/validations'
|
|
13
|
+
|
|
14
|
+
module Ardm
|
|
15
|
+
module ActiveRecord
|
|
16
|
+
# Include all the Ardm modules.
|
|
17
|
+
#
|
|
18
|
+
# You can use this directly if you want your own abstract base class.
|
|
19
|
+
#
|
|
20
|
+
# require 'ardm/active_record/base'
|
|
21
|
+
#
|
|
22
|
+
# class MyRecord < ActiveRecord::Base
|
|
23
|
+
# include Ardm::ActiveRecord::Base
|
|
24
|
+
# end
|
|
25
|
+
#
|
|
26
|
+
# Or Ardm::ActiveRecord::Base is built in to Ardm::Record
|
|
27
|
+
#
|
|
28
|
+
# require 'ardm/active_record/record'
|
|
29
|
+
#
|
|
30
|
+
# class MyRecord < Ardm::Record
|
|
31
|
+
# # already included
|
|
32
|
+
# end
|
|
33
|
+
#
|
|
34
|
+
module Base
|
|
35
|
+
extend ActiveSupport::Concern
|
|
36
|
+
|
|
37
|
+
include Ardm::ActiveRecord::Associations
|
|
38
|
+
include Ardm::ActiveRecord::Hooks
|
|
39
|
+
include Ardm::ActiveRecord::Dirty
|
|
40
|
+
include Ardm::ActiveRecord::Is
|
|
41
|
+
include Ardm::ActiveRecord::Inheritance
|
|
42
|
+
include Ardm::ActiveRecord::Property
|
|
43
|
+
include Ardm::ActiveRecord::Query
|
|
44
|
+
include Ardm::ActiveRecord::Repository
|
|
45
|
+
include Ardm::ActiveRecord::StorageNames
|
|
46
|
+
include Ardm::ActiveRecord::Validations
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module Ardm
|
|
2
|
+
module ActiveRecord
|
|
3
|
+
module Dirty
|
|
4
|
+
def dirty?
|
|
5
|
+
changed?
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def dirty_attributes
|
|
9
|
+
changes.inject({}) do |memo, (attr, val)|
|
|
10
|
+
property = properties[attr]
|
|
11
|
+
memo[property] = val
|
|
12
|
+
memo
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def method_missing(meth, *args, &block)
|
|
17
|
+
if meth.to_s =~ /^([\w_]+)_dirty\?$/
|
|
18
|
+
send("#{$1}_changed?", *args, &block)
|
|
19
|
+
else
|
|
20
|
+
super
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
require 'active_support/concern'
|
|
2
|
+
|
|
3
|
+
module Ardm
|
|
4
|
+
module ActiveRecord
|
|
5
|
+
module Hooks
|
|
6
|
+
extend ActiveSupport::Concern
|
|
7
|
+
|
|
8
|
+
module ClassMethods
|
|
9
|
+
def before(event, meth=nil, &block)
|
|
10
|
+
_ardm_hook(:before, event, meth, &block)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def after(event, meth=nil, &block)
|
|
14
|
+
_ardm_hook(:after, event, meth, &block)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def _ardm_hook(order, event, meth=nil, &block)
|
|
18
|
+
if event.to_sym == :valid?
|
|
19
|
+
event = "validation"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
if meth.nil?
|
|
23
|
+
send "#{order}_#{event}", &block
|
|
24
|
+
else
|
|
25
|
+
send "#{order}_#{event}", meth
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
require 'active_support/concern'
|
|
2
|
+
|
|
3
|
+
module Ardm
|
|
4
|
+
module ActiveRecord
|
|
5
|
+
module Inheritance
|
|
6
|
+
extend ActiveSupport::Concern
|
|
7
|
+
|
|
8
|
+
included do
|
|
9
|
+
# ActiveRecord would prefer that you not use the column "type"
|
|
10
|
+
# for anything other than single table inheritance.
|
|
11
|
+
# The solution is to point ActiveRecord elsewhere.
|
|
12
|
+
unless respond_to?(:inheritance_column=)
|
|
13
|
+
class_attribute :inheritance_column
|
|
14
|
+
end
|
|
15
|
+
self.inheritance_column = "override-active-record-default-sti-column-type"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
module ClassMethods
|
|
19
|
+
def new(attrs={}, *a, &b)
|
|
20
|
+
type = attrs && attrs.stringify_keys[inheritance_column.to_s]
|
|
21
|
+
if type && type != name && type != self
|
|
22
|
+
#puts "STI found for #{type} #{self}"
|
|
23
|
+
con = type.is_a?(Class) ? type : type.constantize
|
|
24
|
+
if con < self
|
|
25
|
+
con.new(attrs, *a, &b)
|
|
26
|
+
else
|
|
27
|
+
raise "Tried to create subclass from #{type} (from key #{inheritance_column}) that is not a subclass of #{name}."
|
|
28
|
+
end
|
|
29
|
+
else
|
|
30
|
+
#puts "No STI found for #{self} (#{attrs.inspect})"
|
|
31
|
+
super
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module Ardm
|
|
2
|
+
module ActiveRecord
|
|
3
|
+
module Is
|
|
4
|
+
module StateMachine
|
|
5
|
+
extend ActiveSupport::Concern
|
|
6
|
+
|
|
7
|
+
included do
|
|
8
|
+
include AASM
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
module ClassMethods
|
|
12
|
+
def is_state_machine(options, &block)
|
|
13
|
+
STDERR.puts "TODO: dm state machine on #{self}"
|
|
14
|
+
property options[:column], Ardm::Property::String, default: options[:initial]
|
|
15
|
+
aasm column: options[:column], &block
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
require 'active_support/concern'
|
|
2
|
+
require 'ardm/active_record/is/state_machine'
|
|
3
|
+
|
|
4
|
+
module Ardm
|
|
5
|
+
module ActiveRecord
|
|
6
|
+
module Is
|
|
7
|
+
extend ActiveSupport::Concern
|
|
8
|
+
|
|
9
|
+
module ClassMethods
|
|
10
|
+
def is(target, options={}, &block)
|
|
11
|
+
case target
|
|
12
|
+
when :state_machine
|
|
13
|
+
include Ardm::ActiveRecord::Is::StateMachine
|
|
14
|
+
is_state_machine(options, &block)
|
|
15
|
+
else
|
|
16
|
+
STDERR.puts "TODO: #{self} is #{target.inspect}, #{options.inspect}"
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
module Ardm
|
|
2
|
+
module ActiveRecord
|
|
3
|
+
module PredicateBuilder
|
|
4
|
+
class ArrayHandler # :nodoc:
|
|
5
|
+
def call(attribute, value)
|
|
6
|
+
values = value.map { |x| x.is_a?(::ActiveRecord::Base) ? x.id : x }
|
|
7
|
+
ranges, values = values.partition { |v| v.is_a?(::Range) }
|
|
8
|
+
|
|
9
|
+
values_predicate = if values.include?(nil)
|
|
10
|
+
values = values.compact
|
|
11
|
+
|
|
12
|
+
case values.length
|
|
13
|
+
when 0
|
|
14
|
+
attribute.eq(nil)
|
|
15
|
+
when 1
|
|
16
|
+
attribute.eq(values.first).or(attribute.eq(nil))
|
|
17
|
+
else
|
|
18
|
+
attribute.in(values).or(attribute.eq(nil))
|
|
19
|
+
end
|
|
20
|
+
else
|
|
21
|
+
attribute.in(values)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
array_predicates = ranges.map { |range| attribute.in(range) }
|
|
25
|
+
array_predicates << values_predicate
|
|
26
|
+
array_predicates.inject { |composite, predicate| composite.or(predicate) }
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
require 'active_support/concern'
|
|
2
|
+
|
|
3
|
+
module Ardm
|
|
4
|
+
module ActiveRecord
|
|
5
|
+
module PredicateBuilder
|
|
6
|
+
module Rails3
|
|
7
|
+
extend ActiveSupport::Concern
|
|
8
|
+
|
|
9
|
+
Base = ::ActiveRecord::Base
|
|
10
|
+
Relation = ::ActiveRecord::Relation
|
|
11
|
+
Collection = ::ActiveRecord::Associations::CollectionProxy
|
|
12
|
+
|
|
13
|
+
included do
|
|
14
|
+
class << self
|
|
15
|
+
alias_method :original_build_from_hash, :build_from_hash
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
class_attribute :handlers
|
|
19
|
+
self.handlers = []
|
|
20
|
+
|
|
21
|
+
register_handler(BasicObject, ->(attribute, value) { attribute.eq(value) })
|
|
22
|
+
register_handler(Class, ->(attribute, value) { attribute.eq(value.name) })
|
|
23
|
+
register_handler(Base, ->(attribute, value) { attribute.eq(value.id) })
|
|
24
|
+
register_handler(Range, ->(attribute, value) { attribute.in(value) })
|
|
25
|
+
register_handler(Relation, RelationHandler.new)
|
|
26
|
+
register_handler(Collection, ArrayHandler.new)
|
|
27
|
+
register_handler(Array, ArrayHandler.new)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
module ClassMethods
|
|
31
|
+
def resolve_column_aliases(klass, hash)
|
|
32
|
+
hash = hash.dup
|
|
33
|
+
hash.keys.grep(Symbol) do |key|
|
|
34
|
+
if klass.attribute_alias? key
|
|
35
|
+
hash[klass.attribute_alias(key)] = hash.delete key
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
hash
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def build_from_hash(klass, attributes, default_table)
|
|
42
|
+
queries = []
|
|
43
|
+
klass = attributes.klass # HAX (this method is added to the attributes hash by expand_hash_conditions_for_aggregates
|
|
44
|
+
|
|
45
|
+
attributes.each do |column, value|
|
|
46
|
+
table = default_table
|
|
47
|
+
|
|
48
|
+
if value.is_a?(Hash)
|
|
49
|
+
if value.empty?
|
|
50
|
+
queries << '1=0'
|
|
51
|
+
else
|
|
52
|
+
table = Arel::Table.new(column, default_table.engine)
|
|
53
|
+
association = klass.reflect_on_association(column.to_sym)
|
|
54
|
+
|
|
55
|
+
value.each do |k, v|
|
|
56
|
+
queries.concat expand(association && association.klass, table, k, v)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
else
|
|
60
|
+
if Ardm::Query::Operator === column
|
|
61
|
+
original = column
|
|
62
|
+
operator = column.operator
|
|
63
|
+
column = column.target.to_s
|
|
64
|
+
else
|
|
65
|
+
column = column.to_s
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
if column.include?('.')
|
|
69
|
+
table_name, column = column.split('.', 2)
|
|
70
|
+
table = Arel::Table.new(table_name, default_table.engine)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
query = expand(klass, table, column, value)
|
|
74
|
+
# TODO make nicer
|
|
75
|
+
if operator == :not
|
|
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
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
queries
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def expand(klass, table, column, value)
|
|
88
|
+
queries = []
|
|
89
|
+
|
|
90
|
+
# Find the foreign key when using queries such as:
|
|
91
|
+
# Post.where(author: author)
|
|
92
|
+
#
|
|
93
|
+
# For polymorphic relationships, find the foreign key and type:
|
|
94
|
+
# PriceEstimate.where(estimate_of: treasure)
|
|
95
|
+
if klass && reflection = klass.reflect_on_association(column.to_sym)
|
|
96
|
+
column = reflection.foreign_key
|
|
97
|
+
if value.is_a?(Base) && reflection.respond_to?(:polymorphic?) && reflection.polymorphic?
|
|
98
|
+
queries << build(table[reflection.foreign_type], value.class.base_class)
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
#puts "expand(#{klass.name}, #{column.inspect}, #{value.inspect})"
|
|
103
|
+
|
|
104
|
+
queries << build(table[column], value)
|
|
105
|
+
queries
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def references(attributes)
|
|
109
|
+
attributes.map do |key, value|
|
|
110
|
+
if value.is_a?(Hash)
|
|
111
|
+
key
|
|
112
|
+
else
|
|
113
|
+
key = key.to_s
|
|
114
|
+
key.split('.').first if key.include?('.')
|
|
115
|
+
end
|
|
116
|
+
end.compact
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Define how a class is converted to Arel nodes when passed to +where+.
|
|
120
|
+
# The handler can be any object that responds to +call+, and will be used
|
|
121
|
+
# for any value that +===+ the class given. For example:
|
|
122
|
+
#
|
|
123
|
+
# MyCustomDateRange = Struct.new(:start, :end)
|
|
124
|
+
# handler = proc do |column, range|
|
|
125
|
+
# Arel::Nodes::Between.new(column,
|
|
126
|
+
# Arel::Nodes::And.new([range.start, range.end])
|
|
127
|
+
# )
|
|
128
|
+
# end
|
|
129
|
+
# ActiveRecord::PredicateBuilder.register_handler(MyCustomDateRange, handler)
|
|
130
|
+
def register_handler(klass, handler)
|
|
131
|
+
handlers.unshift([klass, handler])
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
private
|
|
135
|
+
|
|
136
|
+
def build(attribute, value)
|
|
137
|
+
handler_for(value).call(attribute, value)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def handler_for(object)
|
|
141
|
+
handlers.detect { |klass, _| klass === object }.last
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|