hydra_attribute 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.
- data/.gitignore +20 -0
- data/.rspec +2 -0
- data/Appraisals +7 -0
- data/CHANGELOG.md +6 -0
- data/Gemfile +3 -0
- data/LICENSE +22 -0
- data/README.md +122 -0
- data/Rakefile +12 -0
- data/features/attribute_methods.feature +151 -0
- data/features/define_attributes.feature +61 -0
- data/features/load_associations.feature +45 -0
- data/features/order_conditions.feature +93 -0
- data/features/select_attributes.feature +56 -0
- data/features/step_definitions/class_steps.rb +32 -0
- data/features/step_definitions/model_steps.rb +31 -0
- data/features/step_definitions/record_steps.rb +103 -0
- data/features/support/env.rb +24 -0
- data/features/support/schema.rb +51 -0
- data/features/support/world.rb +31 -0
- data/features/typecast_attributes.feature +29 -0
- data/features/where_conditions.feature +77 -0
- data/gemfiles/3.1.gemfile +7 -0
- data/gemfiles/3.1.gemfile.lock +60 -0
- data/gemfiles/3.2.gemfile +7 -0
- data/gemfiles/3.2.gemfile.lock +60 -0
- data/hydra_attribute.gemspec +24 -0
- data/lib/generators/hydra_attribute/install/USAGE +8 -0
- data/lib/generators/hydra_attribute/install/install_generator.rb +11 -0
- data/lib/generators/hydra_attribute/install/templates/hydra_attribute.txt +11 -0
- data/lib/hydra_attribute.rb +31 -0
- data/lib/hydra_attribute/active_record.rb +7 -0
- data/lib/hydra_attribute/active_record/attribute_methods.rb +72 -0
- data/lib/hydra_attribute/active_record/attribute_methods/before_type_cast.rb +16 -0
- data/lib/hydra_attribute/active_record/attribute_methods/read.rb +13 -0
- data/lib/hydra_attribute/active_record/relation.rb +44 -0
- data/lib/hydra_attribute/active_record/relation/query_methods.rb +162 -0
- data/lib/hydra_attribute/active_record/scoping.rb +15 -0
- data/lib/hydra_attribute/association_builder.rb +40 -0
- data/lib/hydra_attribute/attribute_builder.rb +57 -0
- data/lib/hydra_attribute/attribute_proxy.rb +16 -0
- data/lib/hydra_attribute/builder.rb +25 -0
- data/lib/hydra_attribute/configuration.rb +47 -0
- data/lib/hydra_attribute/migration.rb +27 -0
- data/lib/hydra_attribute/railtie.rb +9 -0
- data/lib/hydra_attribute/version.rb +3 -0
- data/spec/hydra_attribute/active_record/relation/query_methods_spec.rb +286 -0
- data/spec/hydra_attribute/active_record/relation_spec.rb +93 -0
- data/spec/hydra_attribute/active_record/scoping_spec.rb +19 -0
- data/spec/hydra_attribute/active_record_spec.rb +20 -0
- data/spec/hydra_attribute/association_builder_spec.rb +95 -0
- data/spec/hydra_attribute/attribute_builder_spec.rb +70 -0
- data/spec/hydra_attribute/attribute_helpers_spec.rb +70 -0
- data/spec/hydra_attribute/builder_spec.rb +39 -0
- data/spec/hydra_attribute/configuration_spec.rb +96 -0
- data/spec/hydra_attribute_spec.rb +20 -0
- data/spec/spec_helper.rb +17 -0
- metadata +196 -0
@@ -0,0 +1,162 @@
|
|
1
|
+
module HydraAttribute
|
2
|
+
module ActiveRecord
|
3
|
+
module Relation
|
4
|
+
module QueryMethods
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
MULTI_VALUE_METHODS = [:hydra_joins_aliases, :hydra_select_values]
|
8
|
+
|
9
|
+
included do
|
10
|
+
attr_writer *MULTI_VALUE_METHODS
|
11
|
+
|
12
|
+
MULTI_VALUE_METHODS.each do |value|
|
13
|
+
class_eval <<-EOS, __FILE__, __LINE__ + 1
|
14
|
+
def #{value}; @#{value} ||= [] end
|
15
|
+
EOS
|
16
|
+
end
|
17
|
+
|
18
|
+
alias_method_chain :where, :hydra_attribute
|
19
|
+
end
|
20
|
+
|
21
|
+
def where_with_hydra_attribute(opts, *rest)
|
22
|
+
return self if opts.blank?
|
23
|
+
|
24
|
+
if opts.is_a?(Hash)
|
25
|
+
opts.inject(self) do |relation, (name, value)|
|
26
|
+
if klass.hydra_attribute_names.include?(name.to_s)
|
27
|
+
relation, name = relation.clone, name.to_s
|
28
|
+
relation.hydra_joins_aliases << hydra_ref_alias(name, value)
|
29
|
+
relation.joins_values += build_hydra_joins_values(name, value)
|
30
|
+
relation.where_values += build_where(build_hydra_where_options(name, value))
|
31
|
+
relation
|
32
|
+
else
|
33
|
+
relation.where_without_hydra_attribute(name => value)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
else
|
37
|
+
where_without_hydra_attribute(opts, *rest)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def build_arel
|
42
|
+
@order_values = build_order_values_for_arel(@order_values.uniq.reject(&:blank?))
|
43
|
+
|
44
|
+
if instance_variable_defined?(:@reorder_value) and instance_variable_get(:@reorder_value).present? # for compatibility with 3.1.x
|
45
|
+
@reorder_value = build_order_values_for_arel(@reorder_value.uniq.reject(&:blank?))
|
46
|
+
end
|
47
|
+
|
48
|
+
@hydra_select_values, @select_values = @select_values.partition { |value| klass.hydra_attribute_names.include?(value.to_s) }
|
49
|
+
@hydra_select_values.map!(&:to_s)
|
50
|
+
@select_values.map!{ |value| hydra_attr_helper.prepend_table_name(value) }
|
51
|
+
|
52
|
+
# force add ID for preloading hydra attributes
|
53
|
+
if @hydra_select_values.any? && @select_values.none? { |v| hydra_attr_helper.attr_eq_column?(v, klass.primary_key) }
|
54
|
+
@select_values << hydra_attr_helper.prepend_table_name(klass.primary_key)
|
55
|
+
@id_for_hydra_attributes = true
|
56
|
+
end
|
57
|
+
|
58
|
+
super
|
59
|
+
end
|
60
|
+
|
61
|
+
class Helper
|
62
|
+
attr_reader :relation, :klass, :connection
|
63
|
+
|
64
|
+
def initialize(relation)
|
65
|
+
@relation, @klass, @connection = relation, relation.klass, relation.connection
|
66
|
+
end
|
67
|
+
|
68
|
+
def attr_eq_column?(attr, column)
|
69
|
+
attr, column = attr.to_s, column.to_s
|
70
|
+
[
|
71
|
+
column,
|
72
|
+
"#{klass.table_name}.#{column}",
|
73
|
+
"#{klass.table_name}.#{connection.quote_column_name(column)}",
|
74
|
+
"#{klass.quoted_table_name}.#{column}",
|
75
|
+
"#{klass.quoted_table_name}.#{connection.quote_column_name(column)}"
|
76
|
+
].include?(attr)
|
77
|
+
end
|
78
|
+
|
79
|
+
def prepend_table_name(column)
|
80
|
+
case column
|
81
|
+
when Symbol, String
|
82
|
+
if column.to_s.include?('.') or column.to_s.include?(')')
|
83
|
+
column
|
84
|
+
else
|
85
|
+
klass.quoted_table_name + '.' + connection.quote_column_name(column.to_s)
|
86
|
+
end
|
87
|
+
else
|
88
|
+
column
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
private
|
94
|
+
|
95
|
+
def hydra_attr_helper
|
96
|
+
@hydra_attr_helper ||= Helper.new(self)
|
97
|
+
end
|
98
|
+
|
99
|
+
def build_order_values_for_arel(collection)
|
100
|
+
collection.map do |attribute|
|
101
|
+
attribute = attribute.respond_to?(:to_sql) ? attribute.to_sql : attribute.to_s
|
102
|
+
if klass.hydra_attribute_names.include?(attribute)
|
103
|
+
join_alias = hydra_ref_alias(attribute, 'inner') # alias for inner join
|
104
|
+
join_alias = hydra_ref_alias(attribute, nil) unless hydra_joins_aliases.include?(join_alias) # alias for left join
|
105
|
+
|
106
|
+
@joins_values += build_hydra_joins_values(attribute, nil) unless hydra_joins_aliases.include?(join_alias)
|
107
|
+
klass.connection.quote_table_name(join_alias) + '.' + klass.connection.quote_column_name('value')
|
108
|
+
else
|
109
|
+
hydra_attr_helper.prepend_table_name(attribute)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def build_hydra_joins_values(name, value)
|
115
|
+
ref_alias = hydra_ref_alias(name, value)
|
116
|
+
conn = klass.connection
|
117
|
+
quoted_ref_alias = conn.quote_table_name(ref_alias)
|
118
|
+
|
119
|
+
[[
|
120
|
+
"#{hydra_join_type(value)} JOIN",
|
121
|
+
conn.quote_table_name(hydra_ref_table(name)),
|
122
|
+
'AS',
|
123
|
+
quoted_ref_alias,
|
124
|
+
'ON',
|
125
|
+
"#{klass.quoted_table_name}.#{klass.quoted_primary_key}",
|
126
|
+
'=',
|
127
|
+
"#{quoted_ref_alias}.#{conn.quote_column_name(:entity_id)}",
|
128
|
+
'AND',
|
129
|
+
"#{quoted_ref_alias}.#{conn.quote_column_name(:entity_type)}",
|
130
|
+
'=',
|
131
|
+
conn.quote(klass.base_class.name),
|
132
|
+
'AND',
|
133
|
+
"#{quoted_ref_alias}.#{conn.quote_column_name(:name)}",
|
134
|
+
'=',
|
135
|
+
conn.quote(name)
|
136
|
+
].join(' ')]
|
137
|
+
end
|
138
|
+
|
139
|
+
def build_hydra_where_options(name, value)
|
140
|
+
{hydra_ref_alias(name, value) => {value: value}}
|
141
|
+
end
|
142
|
+
|
143
|
+
def hydra_ref_class(name)
|
144
|
+
type = klass.hydra_attributes[name]
|
145
|
+
HydraAttribute.config.associated_model_name(type).constantize
|
146
|
+
end
|
147
|
+
|
148
|
+
def hydra_ref_table(name)
|
149
|
+
hydra_ref_class(name).table_name
|
150
|
+
end
|
151
|
+
|
152
|
+
def hydra_ref_alias(name, value)
|
153
|
+
hydra_ref_table(name) + '_' + hydra_join_type(value).downcase + '_' + name
|
154
|
+
end
|
155
|
+
|
156
|
+
def hydra_join_type(value)
|
157
|
+
value.nil? ? 'LEFT' : 'INNER'
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module HydraAttribute
|
2
|
+
module ActiveRecord
|
3
|
+
module Scoping
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
module ClassMethods
|
7
|
+
def scoped(options = nil)
|
8
|
+
relation = super(options)
|
9
|
+
relation.singleton_class.send(:include, Relation) unless relation.is_a?(Relation)
|
10
|
+
relation
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module HydraAttribute
|
2
|
+
class AssociationBuilder
|
3
|
+
|
4
|
+
def initialize(klass, type)
|
5
|
+
@klass, @type = klass, type
|
6
|
+
end
|
7
|
+
|
8
|
+
def build
|
9
|
+
create_associated_model
|
10
|
+
add_association_for_class
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def create_associated_model
|
16
|
+
const = config.associated_const_name(@type)
|
17
|
+
unless namespace.const_defined?(const)
|
18
|
+
klass = namespace.const_set(const, Class.new(::ActiveRecord::Base))
|
19
|
+
klass.table_name = config.table_name(@type)
|
20
|
+
klass.attr_accessible :name, :value
|
21
|
+
klass.belongs_to :entity, polymorphic: true, touch: true, autosave: true
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def add_association_for_class
|
26
|
+
assoc = config.association(@type)
|
27
|
+
unless @klass.reflect_on_association(assoc)
|
28
|
+
@klass.has_many assoc, as: :entity, class_name: config.associated_model_name(@type), autosave: true, dependent: :destroy
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def config
|
33
|
+
HydraAttribute.config
|
34
|
+
end
|
35
|
+
|
36
|
+
def namespace
|
37
|
+
config.use_module_for_associated_models ? HydraAttribute : Object
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module HydraAttribute
|
2
|
+
class AttributeBuilder
|
3
|
+
NAME_COMPILABLE_REGEXP = /\A[a-zA-Z_]\w*[!?=]?\z/
|
4
|
+
CALL_COMPILABLE_REGEXP = /\A[a-zA-Z_]\w*[!?]?\z/
|
5
|
+
|
6
|
+
attr_reader :klass, :name, :type
|
7
|
+
|
8
|
+
def initialize(klass, name, type)
|
9
|
+
@klass, @name, @type = klass, name.to_s, type
|
10
|
+
end
|
11
|
+
|
12
|
+
def build
|
13
|
+
define_attribute_methods
|
14
|
+
save_attribute
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def define_attribute_methods
|
20
|
+
m = Module.new
|
21
|
+
@klass.attribute_method_matchers.each do |matcher|
|
22
|
+
current = matcher.method_name(name)
|
23
|
+
target = matcher.method_name(:value)
|
24
|
+
|
25
|
+
if current =~ NAME_COMPILABLE_REGEXP
|
26
|
+
defn = "def #{current}(*args)"
|
27
|
+
else
|
28
|
+
defn = "define_method(:'#{current}') do |*args|"
|
29
|
+
end
|
30
|
+
|
31
|
+
if target =~ CALL_COMPILABLE_REGEXP
|
32
|
+
send = "#{target}(*args)"
|
33
|
+
else
|
34
|
+
send = "send(:'#{target}', *args)"
|
35
|
+
end
|
36
|
+
|
37
|
+
body = "hydra_attribute_model('#{name}', :#{type}).#{send}"
|
38
|
+
if current.end_with?('=')
|
39
|
+
body = "v = #{body}; @hydra_attribute_names << '#{name}' unless @hydra_attribute_names.include?('#{name}'); v"
|
40
|
+
else
|
41
|
+
body.insert(0, "missing_attribute('#{name}', caller) unless @hydra_attribute_names.include?('#{name}'); ")
|
42
|
+
end
|
43
|
+
|
44
|
+
m.class_eval <<-EOS, __FILE__, __LINE__ + 1
|
45
|
+
#{defn}
|
46
|
+
#{body}
|
47
|
+
end
|
48
|
+
EOS
|
49
|
+
end
|
50
|
+
klass.send :include, m
|
51
|
+
end
|
52
|
+
|
53
|
+
def save_attribute
|
54
|
+
klass.instance_variable_get(:@hydra_attributes)[name] = type
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module HydraAttribute
|
2
|
+
module AttributeProxy
|
3
|
+
def use_proxy_to_hydra_attribute(symbol)
|
4
|
+
module_eval <<-EOS, __FILE__, __LINE__ + 1
|
5
|
+
def #{symbol}(attr_name)
|
6
|
+
if self.class.hydra_attribute_names.include?(attr_name)
|
7
|
+
type = self.class.hydra_attributes[attr_name]
|
8
|
+
hydra_attribute_model(attr_name, type).#{symbol}('value')
|
9
|
+
else
|
10
|
+
super
|
11
|
+
end
|
12
|
+
end
|
13
|
+
EOS
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module HydraAttribute
|
2
|
+
class Builder
|
3
|
+
attr_reader :klass
|
4
|
+
|
5
|
+
def initialize(klass)
|
6
|
+
@klass = klass
|
7
|
+
@klass.class_eval do
|
8
|
+
include ActiveRecord::Scoping
|
9
|
+
include ActiveRecord::AttributeMethods
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
SUPPORT_TYPES.each do |type|
|
14
|
+
class_eval <<-EOS, __FILE__, __LINE__ + 1
|
15
|
+
def #{type}(*attributes)
|
16
|
+
AssociationBuilder.new(klass, :#{type}).build
|
17
|
+
|
18
|
+
attributes.each do |attribute|
|
19
|
+
AttributeBuilder.new(klass, attribute, :#{type}).build
|
20
|
+
end
|
21
|
+
end
|
22
|
+
EOS
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module HydraAttribute
|
2
|
+
class Configuration
|
3
|
+
def self.add_setting(name, default_value)
|
4
|
+
attr_writer name
|
5
|
+
|
6
|
+
define_method name do
|
7
|
+
instance_variable_set("@#{name}", default_value) unless instance_variable_defined?("@#{name}")
|
8
|
+
instance_variable_get("@#{name}")
|
9
|
+
end
|
10
|
+
|
11
|
+
define_method "#{name}?" do
|
12
|
+
send(name).present?
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
add_setting :table_prefix, 'hydra_'
|
17
|
+
add_setting :association_prefix, 'hydra_'
|
18
|
+
add_setting :use_module_for_associated_models, true
|
19
|
+
|
20
|
+
def table_name(type)
|
21
|
+
"#{table_prefix}#{type}_attributes".to_sym
|
22
|
+
end
|
23
|
+
|
24
|
+
def association(type)
|
25
|
+
"#{association_prefix}#{type}_attributes".to_sym
|
26
|
+
end
|
27
|
+
|
28
|
+
# Return string for compatibility with ActiveRecord 3.1.x
|
29
|
+
def associated_model_name(type)
|
30
|
+
klass = associated_const_name(type).to_s
|
31
|
+
klass = "HydraAttribute::#{klass}" if use_module_for_associated_models?
|
32
|
+
klass
|
33
|
+
end
|
34
|
+
|
35
|
+
def associated_const_name(type)
|
36
|
+
"#{type.to_s.titlecase}Attribute".to_sym
|
37
|
+
end
|
38
|
+
|
39
|
+
def relation_execute_method
|
40
|
+
if ::ActiveRecord::VERSION::MINOR > 1
|
41
|
+
:exec_queries
|
42
|
+
else
|
43
|
+
:to_a
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module HydraAttribute
|
2
|
+
class Migration
|
3
|
+
def initialize(migration)
|
4
|
+
@migration = migration
|
5
|
+
end
|
6
|
+
|
7
|
+
def migrate
|
8
|
+
SUPPORT_TYPES.each do |type|
|
9
|
+
table_name = HydraAttribute.config.table_name(type)
|
10
|
+
@migration.create_table table_name do |t|
|
11
|
+
t.integer :entity_id
|
12
|
+
t.string :entity_type
|
13
|
+
t.string :name
|
14
|
+
t.send type, :value
|
15
|
+
end
|
16
|
+
|
17
|
+
@migration.add_index table_name, [:entity_id, :entity_type, :name], unique: true, name: "index_#{table_name}_on_attribute"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def rollback
|
22
|
+
SUPPORT_TYPES.each do |type|
|
23
|
+
@migration.drop_table HydraAttribute.config.table_name(type)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,286 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe HydraAttribute::ActiveRecord::Relation::QueryMethods do
|
4
|
+
let(:relation_class) do
|
5
|
+
mock(
|
6
|
+
:hydra_attributes => {'code' => :string},
|
7
|
+
:hydra_attribute_names => ['code'],
|
8
|
+
:hydra_attribute_types => [:string]
|
9
|
+
)
|
10
|
+
end
|
11
|
+
|
12
|
+
let(:relation) { mock(klass: relation_class, where: nil) }
|
13
|
+
|
14
|
+
before do
|
15
|
+
relation.singleton_class.send :include, ::ActiveRecord::QueryMethods
|
16
|
+
relation.singleton_class.send :include, HydraAttribute::ActiveRecord::Relation::QueryMethods
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '#where' do
|
20
|
+
let(:relation) do
|
21
|
+
mock_relation = mock(klass: relation_class)
|
22
|
+
mock_relation.instance_variable_set(:@where_values, [])
|
23
|
+
mock_relation.instance_variable_set(:@joins_values, [])
|
24
|
+
mock_relation.stub(:build_hydra_joins_values) { |name, value| ["join-#{name}-#{value}"] }
|
25
|
+
mock_relation.stub(:build_hydra_where_options) { |name, value| ["where-#{name}-#{value}"] }
|
26
|
+
mock_relation.stub(:build_where) { |value, *rest| ["#{value} #{rest}"] }
|
27
|
+
mock_relation
|
28
|
+
end
|
29
|
+
|
30
|
+
before do
|
31
|
+
module HydraAttribute
|
32
|
+
class StringAttribute
|
33
|
+
def self.table_name
|
34
|
+
'hydra_string_attributes'
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
after do
|
41
|
+
HydraAttribute.send :remove_const, :StringAttribute
|
42
|
+
end
|
43
|
+
|
44
|
+
describe 'first param is Hash' do
|
45
|
+
let(:params) { {'title' => 1} }
|
46
|
+
|
47
|
+
describe 'hash has not hydra attribute' do
|
48
|
+
it 'should call rails native "where" method' do
|
49
|
+
object = relation.where(params)
|
50
|
+
object.where_values.should == ['{"title"=>1} [[]]']
|
51
|
+
object.joins_values.should == []
|
52
|
+
object.hydra_joins_aliases.should == []
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe 'hash has hydra attribute' do
|
57
|
+
let(:params) { {'title' => 1, 'code' => 2, 'name' => 3} }
|
58
|
+
|
59
|
+
it 'should call both native and overwritten "where" method' do
|
60
|
+
copy_relation = relation.where(params)
|
61
|
+
copy_relation.where_values.should == ['{"title"=>1} [[]]', 'where-code-2 []', '{"name"=>3} [[]]']
|
62
|
+
copy_relation.joins_values.should == ['join-code-2']
|
63
|
+
copy_relation.hydra_joins_aliases.should == ['hydra_string_attributes_inner_code']
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe 'first param is not Hash' do
|
69
|
+
let(:params) { 'name = 1' }
|
70
|
+
|
71
|
+
it 'should call rails native "where" method' do
|
72
|
+
copy_relation = relation.where(params)
|
73
|
+
copy_relation.where_values.should == ['name = 1 [[]]']
|
74
|
+
copy_relation.joins_values.should == []
|
75
|
+
copy_relation.hydra_joins_aliases.should == []
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe '#build_arel' do
|
81
|
+
let(:arel) { mock.as_null_object }
|
82
|
+
|
83
|
+
let(:relation) do
|
84
|
+
mock_relation = mock(klass: relation_class, where: nil, build_select: nil)
|
85
|
+
mock_relation.stub_chain(:table, :from).and_return(arel)
|
86
|
+
mock_relation.instance_variable_set(:@joins_values, [])
|
87
|
+
mock_relation.instance_variable_set(:@order_values, [])
|
88
|
+
mock_relation.instance_variable_set(:@where_values, [])
|
89
|
+
mock_relation.instance_variable_set(:@having_values, [])
|
90
|
+
mock_relation.instance_variable_set(:@group_values, [])
|
91
|
+
mock_relation.instance_variable_set(:@select_values, [])
|
92
|
+
mock_relation
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'should update @order_values before generate the arel object' do
|
96
|
+
relation.stub(build_order_values_for_arel: %w(build_order))
|
97
|
+
relation.build_arel.should == arel
|
98
|
+
relation.instance_variable_get(:@order_values).should == %w(build_order)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
describe '#build_order_values_for_arel' do
|
103
|
+
let(:connection) do
|
104
|
+
conn = mock
|
105
|
+
conn.stub(:quote_column_name) { |column| column.to_s }
|
106
|
+
conn.stub(:quote) { |value| %Q("#{value.to_s}") }
|
107
|
+
conn.stub(:quote_table_name) { |table| table.to_s }
|
108
|
+
conn
|
109
|
+
end
|
110
|
+
|
111
|
+
let(:relation_class) do
|
112
|
+
mock(connection: connection, quoted_table_name: 'product', hydra_attribute_names: %w(code title price))
|
113
|
+
end
|
114
|
+
|
115
|
+
let(:relation) do
|
116
|
+
mock_relation = mock(klass: relation_class, connection: connection)
|
117
|
+
mock_relation.stub(where: mock_relation)
|
118
|
+
mock_relation.stub(:hydra_ref_alias) { |name, value| "#{name}_#{value}" }
|
119
|
+
mock_relation.stub(:build_hydra_joins_values) { |name, value| ["#{name}_#{value}_join"] }
|
120
|
+
mock_relation.instance_variable_set(:@joins_values, [])
|
121
|
+
mock_relation.instance_variable_set(:@hydra_joins_aliases, %w(code_inner title_))
|
122
|
+
mock_relation
|
123
|
+
end
|
124
|
+
|
125
|
+
describe 'collection has not hydra attributes' do
|
126
|
+
it 'should return the same collection' do
|
127
|
+
relation.send(:build_order_values_for_arel, %w(name zone)).should == %w(product.name product.zone)
|
128
|
+
relation.joins_values.should == []
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
describe 'collection has hydra attributes' do
|
133
|
+
it 'should change hydra attributes and join hydra tables' do
|
134
|
+
relation.send(:build_order_values_for_arel, %w(name code title price)).should == %w(product.name code_inner.value title_.value price_.value)
|
135
|
+
relation.joins_values.should == %w(price__join)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
describe '#build_hydra_joins_values' do
|
141
|
+
let(:connection) do
|
142
|
+
conn = mock
|
143
|
+
conn.stub(:quote_column_name) { |column| column.to_s }
|
144
|
+
conn.stub(:quote) { |value| %Q("#{value.to_s}") }
|
145
|
+
conn.stub(:quote_table_name) { |table| table.to_s }
|
146
|
+
conn
|
147
|
+
end
|
148
|
+
|
149
|
+
let(:relation_class) do
|
150
|
+
mock(
|
151
|
+
:connection => connection,
|
152
|
+
:base_class => mock(name: 'BaseClass'),
|
153
|
+
:quoted_primary_key => 'id',
|
154
|
+
:quoted_table_name => 'hydra_string_attributes'
|
155
|
+
)
|
156
|
+
end
|
157
|
+
|
158
|
+
let(:relation) do
|
159
|
+
mock_relation = mock(klass: relation_class)
|
160
|
+
mock_relation.stub(where: mock_relation)
|
161
|
+
mock_relation.stub(:hydra_ref_alias) { |name, value| "#{name}_#{value}" }
|
162
|
+
mock_relation.stub(:hydra_ref_table) { |name| "table_#{name}" }
|
163
|
+
mock_relation
|
164
|
+
end
|
165
|
+
|
166
|
+
describe 'value is nil' do
|
167
|
+
let(:value) { nil }
|
168
|
+
let(:sql) { 'LEFT JOIN table_name AS name_ ON hydra_string_attributes.id = name_.entity_id AND name_.entity_type = "BaseClass" AND name_.name = "name"' }
|
169
|
+
|
170
|
+
it 'should return array with one SQL query element' do
|
171
|
+
relation.send(:build_hydra_joins_values, :name, value).should == [sql]
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
describe 'value is not nil' do
|
176
|
+
let(:value) { 'value' }
|
177
|
+
let(:sql) { 'INNER JOIN table_name AS name_value ON hydra_string_attributes.id = name_value.entity_id AND name_value.entity_type = "BaseClass" AND name_value.name = "name"' }
|
178
|
+
|
179
|
+
it 'should return array with one SQL query element' do
|
180
|
+
relation.send(:build_hydra_joins_values, :name, value).should == [sql]
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
describe '#build_hydra_where_options' do
|
186
|
+
before do
|
187
|
+
module HydraAttribute
|
188
|
+
class StringAttribute
|
189
|
+
def self.table_name
|
190
|
+
'hydra_string_attributes'
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
after { HydraAttribute.send :remove_const, :StringAttribute }
|
197
|
+
|
198
|
+
it 'should create where options with table namespace' do
|
199
|
+
relation.send(:build_hydra_where_options, 'code', 'abc').should == {'hydra_string_attributes_inner_code' => { value: 'abc' }}
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
describe '#hydra_ref_class' do
|
204
|
+
before do
|
205
|
+
module HydraAttribute
|
206
|
+
class StringAttribute
|
207
|
+
def self.table_name
|
208
|
+
'hydra_string_attributes'
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
after { HydraAttribute.send :remove_const, :StringAttribute }
|
215
|
+
|
216
|
+
it 'should return class by attribute name' do
|
217
|
+
relation.send(:hydra_ref_class, 'code').should == HydraAttribute::StringAttribute
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
describe '#hydra_ref_table' do
|
222
|
+
before do
|
223
|
+
module HydraAttribute
|
224
|
+
class StringAttribute
|
225
|
+
def self.table_name
|
226
|
+
'hydra_string_attributes'
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
after { HydraAttribute.send :remove_const, :StringAttribute }
|
233
|
+
|
234
|
+
it 'should return table name' do
|
235
|
+
relation.send(:hydra_ref_table, 'code').should == 'hydra_string_attributes'
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
describe '#hydra_ref_alias' do
|
240
|
+
before do
|
241
|
+
module HydraAttribute
|
242
|
+
class StringAttribute
|
243
|
+
def self.table_name
|
244
|
+
'hydra_string_attributes'
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
after { HydraAttribute.send :remove_const, :StringAttribute }
|
251
|
+
|
252
|
+
describe 'value is nil' do
|
253
|
+
let(:value) { nil }
|
254
|
+
|
255
|
+
it 'should return generated alias name' do
|
256
|
+
relation.send(:hydra_ref_alias, 'code', value).should == 'hydra_string_attributes_left_code'
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
describe 'value is not nil' do
|
261
|
+
let(:value) { '' }
|
262
|
+
|
263
|
+
it 'should return generated alias name' do
|
264
|
+
relation.send(:hydra_ref_alias, 'code', value).should == 'hydra_string_attributes_inner_code'
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
describe '#hydra_join_type' do
|
270
|
+
describe 'value is nil' do
|
271
|
+
let(:value) { nil }
|
272
|
+
|
273
|
+
it 'should return "LEFT"' do
|
274
|
+
relation.send(:hydra_join_type, value).should == 'LEFT'
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
describe 'value is not nil' do
|
279
|
+
let(:value) { '' }
|
280
|
+
|
281
|
+
it 'should return "INNER"' do
|
282
|
+
relation.send(:hydra_join_type, value).should == 'INNER'
|
283
|
+
end
|
284
|
+
end
|
285
|
+
end
|
286
|
+
end
|