composite_primary_keys 7.0.15 → 7.0.16
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 +4 -4
- data/History.rdoc +4 -0
- data/lib/composite_primary_keys.rb +5 -0
- data/lib/composite_primary_keys/arel/visitors/to_sql.rb +20 -0
- data/lib/composite_primary_keys/associations/join_dependency/join_association.rb +22 -22
- data/lib/composite_primary_keys/associations/preloader/belongs_to.rb +19 -19
- data/lib/composite_primary_keys/composite_predicates.rb +50 -50
- data/lib/composite_primary_keys/composite_relation.rb +48 -48
- data/lib/composite_primary_keys/connection_adapters/postgresql_adapter.rb +60 -46
- data/lib/composite_primary_keys/fixtures.rb +22 -22
- data/lib/composite_primary_keys/locking/optimistic.rb +55 -55
- data/lib/composite_primary_keys/relation/query_methods.rb +40 -40
- data/lib/composite_primary_keys/version.rb +1 -1
- data/tasks/databases/oracle.rake +25 -25
- data/test/connections/databases.ci.yml +15 -15
- data/test/connections/native_oracle/connection.rb +11 -11
- data/test/connections/native_oracle_enhanced/connection.rb +16 -16
- data/test/fixtures/comment.rb +7 -7
- data/test/fixtures/db_definitions/db2-create-tables.sql +126 -126
- data/test/fixtures/db_definitions/db2-drop-tables.sql +18 -18
- data/test/fixtures/db_definitions/oracle.drop.sql +45 -45
- data/test/fixtures/db_definitions/oracle.sql +223 -223
- data/test/fixtures/dorm.rb +2 -2
- data/test/fixtures/membership.rb +6 -6
- data/test/fixtures/membership_statuses.yml +16 -16
- data/test/fixtures/memberships.yml +10 -10
- data/test/fixtures/product_tariffs.yml +14 -14
- data/test/fixtures/reference_code.rb +7 -7
- data/test/fixtures/restaurants_suburb.rb +2 -2
- data/test/fixtures/suburb.rb +5 -5
- data/test/fixtures/topic.rb +5 -5
- data/test/fixtures/topic_source.rb +6 -6
- data/test/fixtures/topic_sources.yml +3 -3
- data/test/fixtures/topics.yml +8 -8
- data/test/fixtures/users.yml +10 -10
- data/test/test_attribute_methods.rb +63 -63
- data/test/test_calculations.rb +42 -42
- data/test/test_callbacks.rb +99 -99
- data/test/test_delete_all.rb +5 -0
- data/test/test_dumpable.rb +15 -15
- data/test/test_nested_attributes.rb +124 -124
- data/test/test_optimistic.rb +18 -18
- data/test/test_predicates.rb +40 -40
- data/test/test_santiago.rb +23 -23
- data/test/test_suite.rb +34 -34
- data/test/test_touch.rb +23 -23
- data/test/test_update.rb +71 -71
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a3eaf57bc39ed46c4a72d72d5340f36e808066af
|
4
|
+
data.tar.gz: 34c682ff2f92cfa89c1f198b33101b4a9f255cdb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f807e7a2cd19630d36813aaebc4ada9c08d386c66723f01d3d66b51d220c586c1f94145c26192a5968a7f1b2c0261f8486e78882b09099e93f6609505877bab1
|
7
|
+
data.tar.gz: 6b1b0a788652b9912159ba9f6529778688275cf3648055e73b2f51239a2604c27f7527d92d86468b1d2c05adc4dad6942ef454b2bf4d0c43ce6a607dff51ffc8
|
data/History.rdoc
CHANGED
@@ -30,6 +30,9 @@ unless defined?(ActiveRecord)
|
|
30
30
|
require 'active_record'
|
31
31
|
end
|
32
32
|
|
33
|
+
# Arel files we override
|
34
|
+
require 'arel/visitors/to_sql'
|
35
|
+
|
33
36
|
# AR files we override
|
34
37
|
require 'active_record/counter_cache'
|
35
38
|
require 'active_record/fixtures'
|
@@ -66,6 +69,8 @@ require 'active_record/relation/query_methods'
|
|
66
69
|
require 'active_record/validations/uniqueness'
|
67
70
|
|
68
71
|
# CPK files
|
72
|
+
require 'composite_primary_keys/arel/visitors/to_sql'
|
73
|
+
|
69
74
|
require 'composite_primary_keys/persistence'
|
70
75
|
require 'composite_primary_keys/base'
|
71
76
|
require 'composite_primary_keys/core'
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Arel
|
2
|
+
module Visitors
|
3
|
+
class ToSql
|
4
|
+
def visit_Arel_Nodes_In o, a
|
5
|
+
if Array === o.right && o.right.empty?
|
6
|
+
'1=0'
|
7
|
+
else
|
8
|
+
a = o.left if Arel::Attributes::Attribute === o.left
|
9
|
+
# CPK
|
10
|
+
#"#{visit o.left, a} IN (#{visit o.right, a})"
|
11
|
+
if o.left.name.is_a?(Array)
|
12
|
+
"(#{visit o.left, a}) IN (#{visit o.right, a})"
|
13
|
+
else
|
14
|
+
"#{visit o.left, a} IN (#{visit o.right, a})"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -1,22 +1,22 @@
|
|
1
|
-
module ActiveRecord
|
2
|
-
module Associations
|
3
|
-
class JoinDependency
|
4
|
-
class JoinAssociation
|
5
|
-
def build_constraint(klass, table, key, foreign_table, foreign_key)
|
6
|
-
# CPK
|
7
|
-
# constraint = table[key].eq(foreign_table[foreign_key])
|
8
|
-
constraint = cpk_join_predicate(table, key, foreign_table, foreign_key)
|
9
|
-
|
10
|
-
if klass.finder_needs_type_condition?
|
11
|
-
constraint = table.create_and([
|
12
|
-
constraint,
|
13
|
-
klass.send(:type_condition, table)
|
14
|
-
])
|
15
|
-
end
|
16
|
-
|
17
|
-
constraint
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
1
|
+
module ActiveRecord
|
2
|
+
module Associations
|
3
|
+
class JoinDependency
|
4
|
+
class JoinAssociation
|
5
|
+
def build_constraint(klass, table, key, foreign_table, foreign_key)
|
6
|
+
# CPK
|
7
|
+
# constraint = table[key].eq(foreign_table[foreign_key])
|
8
|
+
constraint = cpk_join_predicate(table, key, foreign_table, foreign_key)
|
9
|
+
|
10
|
+
if klass.finder_needs_type_condition?
|
11
|
+
constraint = table.create_and([
|
12
|
+
constraint,
|
13
|
+
klass.send(:type_condition, table)
|
14
|
+
])
|
15
|
+
end
|
16
|
+
|
17
|
+
constraint
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -1,19 +1,19 @@
|
|
1
|
-
module ActiveRecord
|
2
|
-
module Associations
|
3
|
-
class Preloader
|
4
|
-
class BelongsTo
|
5
|
-
def query_scope(ids)
|
6
|
-
# CPK
|
7
|
-
# scope.where(association_key.in(ids))
|
8
|
-
|
9
|
-
if association_key_name.is_a?(Array)
|
10
|
-
predicate = cpk_in_predicate(table, association_key_name, ids)
|
11
|
-
scope.where(predicate)
|
12
|
-
else
|
13
|
-
scope.where(association_key.in(ids))
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
1
|
+
module ActiveRecord
|
2
|
+
module Associations
|
3
|
+
class Preloader
|
4
|
+
class BelongsTo
|
5
|
+
def query_scope(ids)
|
6
|
+
# CPK
|
7
|
+
# scope.where(association_key.in(ids))
|
8
|
+
|
9
|
+
if association_key_name.is_a?(Array)
|
10
|
+
predicate = cpk_in_predicate(table, association_key_name, ids)
|
11
|
+
scope.where(predicate)
|
12
|
+
else
|
13
|
+
scope.where(association_key.in(ids))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -1,51 +1,51 @@
|
|
1
|
-
module CompositePrimaryKeys
|
2
|
-
module Predicates
|
3
|
-
def cpk_and_predicate(predicates)
|
4
|
-
if predicates.length == 1
|
5
|
-
predicates.first
|
6
|
-
else
|
7
|
-
Arel::Nodes::And.new(predicates)
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
def cpk_or_predicate(predicates)
|
12
|
-
or_predicate = predicates.map do |predicate|
|
13
|
-
::Arel::Nodes::Grouping.new(predicate)
|
14
|
-
end.inject do |memo, node|
|
15
|
-
::Arel::Nodes::Or.new(memo, node)
|
16
|
-
end
|
17
|
-
::Arel::Nodes::Grouping.new(or_predicate)
|
18
|
-
end
|
19
|
-
|
20
|
-
def cpk_id_predicate(table, keys, values)
|
21
|
-
eq_predicates = keys.zip(values).map do |key, value|
|
22
|
-
table[key].eq(value)
|
23
|
-
end
|
24
|
-
cpk_and_predicate(eq_predicates)
|
25
|
-
end
|
26
|
-
|
27
|
-
def cpk_join_predicate(table1, key1, table2, key2)
|
28
|
-
key1_fields = Array(key1).map {|key| table1[key]}
|
29
|
-
key2_fields = Array(key2).map {|key| table2[key]}
|
30
|
-
|
31
|
-
eq_predicates = key1_fields.zip(key2_fields).map do |key_field1, key_field2|
|
32
|
-
key_field1.eq(key_field2)
|
33
|
-
end
|
34
|
-
cpk_and_predicate(eq_predicates)
|
35
|
-
end
|
36
|
-
|
37
|
-
def cpk_in_predicate(table, primary_keys, ids)
|
38
|
-
and_predicates = ids.map do |id|
|
39
|
-
cpk_id_predicate(table, primary_keys, id)
|
40
|
-
end
|
41
|
-
cpk_or_predicate(and_predicates)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
ActiveRecord::Associations::AssociationScope.send(:include, CompositePrimaryKeys::Predicates)
|
47
|
-
ActiveRecord::Associations::JoinDependency::JoinAssociation.send(:include, CompositePrimaryKeys::Predicates)
|
48
|
-
ActiveRecord::Associations::Preloader::Association.send(:include, CompositePrimaryKeys::Predicates)
|
49
|
-
ActiveRecord::Associations::HasManyThroughAssociation.send(:include, CompositePrimaryKeys::Predicates)
|
50
|
-
ActiveRecord::Relation.send(:include, CompositePrimaryKeys::Predicates)
|
1
|
+
module CompositePrimaryKeys
|
2
|
+
module Predicates
|
3
|
+
def cpk_and_predicate(predicates)
|
4
|
+
if predicates.length == 1
|
5
|
+
predicates.first
|
6
|
+
else
|
7
|
+
Arel::Nodes::And.new(predicates)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def cpk_or_predicate(predicates)
|
12
|
+
or_predicate = predicates.map do |predicate|
|
13
|
+
::Arel::Nodes::Grouping.new(predicate)
|
14
|
+
end.inject do |memo, node|
|
15
|
+
::Arel::Nodes::Or.new(memo, node)
|
16
|
+
end
|
17
|
+
::Arel::Nodes::Grouping.new(or_predicate)
|
18
|
+
end
|
19
|
+
|
20
|
+
def cpk_id_predicate(table, keys, values)
|
21
|
+
eq_predicates = keys.zip(values).map do |key, value|
|
22
|
+
table[key].eq(value)
|
23
|
+
end
|
24
|
+
cpk_and_predicate(eq_predicates)
|
25
|
+
end
|
26
|
+
|
27
|
+
def cpk_join_predicate(table1, key1, table2, key2)
|
28
|
+
key1_fields = Array(key1).map {|key| table1[key]}
|
29
|
+
key2_fields = Array(key2).map {|key| table2[key]}
|
30
|
+
|
31
|
+
eq_predicates = key1_fields.zip(key2_fields).map do |key_field1, key_field2|
|
32
|
+
key_field1.eq(key_field2)
|
33
|
+
end
|
34
|
+
cpk_and_predicate(eq_predicates)
|
35
|
+
end
|
36
|
+
|
37
|
+
def cpk_in_predicate(table, primary_keys, ids)
|
38
|
+
and_predicates = ids.map do |id|
|
39
|
+
cpk_id_predicate(table, primary_keys, id)
|
40
|
+
end
|
41
|
+
cpk_or_predicate(and_predicates)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
ActiveRecord::Associations::AssociationScope.send(:include, CompositePrimaryKeys::Predicates)
|
47
|
+
ActiveRecord::Associations::JoinDependency::JoinAssociation.send(:include, CompositePrimaryKeys::Predicates)
|
48
|
+
ActiveRecord::Associations::Preloader::Association.send(:include, CompositePrimaryKeys::Predicates)
|
49
|
+
ActiveRecord::Associations::HasManyThroughAssociation.send(:include, CompositePrimaryKeys::Predicates)
|
50
|
+
ActiveRecord::Relation.send(:include, CompositePrimaryKeys::Predicates)
|
51
51
|
ActiveRecord::PredicateBuilder.send(:extend, CompositePrimaryKeys::Predicates)
|
@@ -1,48 +1,48 @@
|
|
1
|
-
module CompositePrimaryKeys
|
2
|
-
module CompositeRelation
|
3
|
-
include CompositePrimaryKeys::ActiveRecord::Batches
|
4
|
-
include CompositePrimaryKeys::ActiveRecord::Calculations
|
5
|
-
include CompositePrimaryKeys::ActiveRecord::FinderMethods
|
6
|
-
include CompositePrimaryKeys::ActiveRecord::QueryMethods
|
7
|
-
|
8
|
-
def delete(id_or_array)
|
9
|
-
# CPK
|
10
|
-
if self.composite?
|
11
|
-
id_or_array = if id_or_array.is_a?(CompositePrimaryKeys::CompositeKeys)
|
12
|
-
[id_or_array]
|
13
|
-
else
|
14
|
-
Array(id_or_array)
|
15
|
-
end
|
16
|
-
|
17
|
-
id_or_array.each do |id|
|
18
|
-
# Is the passed in id actually a record?
|
19
|
-
id = id.kind_of?(::ActiveRecord::Base) ? id.id : id
|
20
|
-
where(cpk_id_predicate(table, self.primary_key, id)).delete_all
|
21
|
-
end
|
22
|
-
else
|
23
|
-
where(primary_key => id_or_array).delete_all
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
def destroy(id_or_array)
|
28
|
-
# Without CPK:
|
29
|
-
#if id.is_a?(Array)
|
30
|
-
# id.map { |one_id| destroy(one_id) }
|
31
|
-
#else
|
32
|
-
# find(id).destroy
|
33
|
-
#end
|
34
|
-
|
35
|
-
id_or_array = if id_or_array.kind_of?(CompositePrimaryKeys::CompositeKeys)
|
36
|
-
[id_or_array]
|
37
|
-
else
|
38
|
-
Array(id_or_array)
|
39
|
-
end
|
40
|
-
|
41
|
-
id_or_array.each do |id|
|
42
|
-
where(cpk_id_predicate(table, self.primary_key, id)).each do |record|
|
43
|
-
record.destroy
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
1
|
+
module CompositePrimaryKeys
|
2
|
+
module CompositeRelation
|
3
|
+
include CompositePrimaryKeys::ActiveRecord::Batches
|
4
|
+
include CompositePrimaryKeys::ActiveRecord::Calculations
|
5
|
+
include CompositePrimaryKeys::ActiveRecord::FinderMethods
|
6
|
+
include CompositePrimaryKeys::ActiveRecord::QueryMethods
|
7
|
+
|
8
|
+
def delete(id_or_array)
|
9
|
+
# CPK
|
10
|
+
if self.composite?
|
11
|
+
id_or_array = if id_or_array.is_a?(CompositePrimaryKeys::CompositeKeys)
|
12
|
+
[id_or_array]
|
13
|
+
else
|
14
|
+
Array(id_or_array)
|
15
|
+
end
|
16
|
+
|
17
|
+
id_or_array.each do |id|
|
18
|
+
# Is the passed in id actually a record?
|
19
|
+
id = id.kind_of?(::ActiveRecord::Base) ? id.id : id
|
20
|
+
where(cpk_id_predicate(table, self.primary_key, id)).delete_all
|
21
|
+
end
|
22
|
+
else
|
23
|
+
where(primary_key => id_or_array).delete_all
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def destroy(id_or_array)
|
28
|
+
# Without CPK:
|
29
|
+
#if id.is_a?(Array)
|
30
|
+
# id.map { |one_id| destroy(one_id) }
|
31
|
+
#else
|
32
|
+
# find(id).destroy
|
33
|
+
#end
|
34
|
+
|
35
|
+
id_or_array = if id_or_array.kind_of?(CompositePrimaryKeys::CompositeKeys)
|
36
|
+
[id_or_array]
|
37
|
+
else
|
38
|
+
Array(id_or_array)
|
39
|
+
end
|
40
|
+
|
41
|
+
id_or_array.each do |id|
|
42
|
+
where(cpk_id_predicate(table, self.primary_key, id)).each do |record|
|
43
|
+
record.destroy
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -1,46 +1,60 @@
|
|
1
|
-
module ActiveRecord
|
2
|
-
module ConnectionAdapters
|
3
|
-
class PostgreSQLAdapter
|
4
|
-
def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
|
5
|
-
unless pk
|
6
|
-
# Extract the table from the insert sql. Yuck.
|
7
|
-
table_ref = extract_table_ref_from_insert_sql(sql)
|
8
|
-
pk = primary_key(table_ref) if table_ref
|
9
|
-
end
|
10
|
-
|
11
|
-
if pk
|
12
|
-
# CPK
|
13
|
-
# select_value("#{sql} RETURNING #{quote_column_name(pk)}")
|
14
|
-
select_value("#{sql} RETURNING #{quote_column_names(pk)}")
|
15
|
-
else
|
16
|
-
super
|
17
|
-
end
|
18
|
-
end
|
19
|
-
alias :create :insert
|
20
|
-
|
21
|
-
def sql_for_insert(sql, pk, id_value, sequence_name, binds)
|
22
|
-
unless pk
|
23
|
-
# Extract the table from the insert sql. Yuck.
|
24
|
-
table_ref = extract_table_ref_from_insert_sql(sql)
|
25
|
-
pk = primary_key(table_ref) if table_ref
|
26
|
-
end
|
27
|
-
|
28
|
-
# CPK
|
29
|
-
# sql = "#{sql} RETURNING #{quote_column_name(pk)}" if pk
|
30
|
-
sql = "#{sql} RETURNING #{quote_column_names(pk)}" if pk
|
31
|
-
|
32
|
-
[sql, binds]
|
33
|
-
end
|
34
|
-
|
35
|
-
# Returns a single value if query returns a single element
|
36
|
-
# otherwise returns an array coresponding to the composite keys
|
37
|
-
#
|
38
|
-
def last_inserted_id(result)
|
39
|
-
row = result && result.rows.first
|
40
|
-
if Array === row
|
41
|
-
row.size == 1 ? row[0] : row
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
|
46
|
-
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
class PostgreSQLAdapter
|
4
|
+
def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
|
5
|
+
unless pk
|
6
|
+
# Extract the table from the insert sql. Yuck.
|
7
|
+
table_ref = extract_table_ref_from_insert_sql(sql)
|
8
|
+
pk = primary_key(table_ref) if table_ref
|
9
|
+
end
|
10
|
+
|
11
|
+
if pk
|
12
|
+
# CPK
|
13
|
+
# select_value("#{sql} RETURNING #{quote_column_name(pk)}")
|
14
|
+
select_value("#{sql} RETURNING #{quote_column_names(pk)}")
|
15
|
+
else
|
16
|
+
super
|
17
|
+
end
|
18
|
+
end
|
19
|
+
alias :create :insert
|
20
|
+
|
21
|
+
def sql_for_insert(sql, pk, id_value, sequence_name, binds)
|
22
|
+
unless pk
|
23
|
+
# Extract the table from the insert sql. Yuck.
|
24
|
+
table_ref = extract_table_ref_from_insert_sql(sql)
|
25
|
+
pk = primary_key(table_ref) if table_ref
|
26
|
+
end
|
27
|
+
|
28
|
+
# CPK
|
29
|
+
# sql = "#{sql} RETURNING #{quote_column_name(pk)}" if pk
|
30
|
+
sql = "#{sql} RETURNING #{quote_column_names(pk)}" if pk
|
31
|
+
|
32
|
+
[sql, binds]
|
33
|
+
end
|
34
|
+
|
35
|
+
# Returns a single value if query returns a single element
|
36
|
+
# otherwise returns an array coresponding to the composite keys
|
37
|
+
#
|
38
|
+
def last_inserted_id(result)
|
39
|
+
row = result && result.rows.first
|
40
|
+
if Array === row
|
41
|
+
row.size == 1 ? row[0] : row
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
module Quoting
|
46
|
+
def quote_column_name(name) #:nodoc:
|
47
|
+
# CPK
|
48
|
+
# PGconn.quote_ident(name.to_s)
|
49
|
+
if name.is_a?(Array)
|
50
|
+
name.map do |column|
|
51
|
+
PGconn.quote_ident(column.to_s)
|
52
|
+
end.join(', ')
|
53
|
+
else
|
54
|
+
PGconn.quote_ident(name.to_s)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|