composite_primary_keys 8.1.7 → 8.1.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/History.rdoc +3 -0
- data/lib/composite_primary_keys/associations/preloader/association.rb +3 -4
- data/lib/composite_primary_keys/base.rb +1 -1
- data/lib/composite_primary_keys/composite_arrays.rb +50 -7
- data/lib/composite_primary_keys/connection_adapters/abstract_adapter.rb +1 -1
- data/lib/composite_primary_keys/relation/finder_methods.rb +2 -2
- data/lib/composite_primary_keys/version.rb +1 -1
- data/test/fixtures/db_definitions/mysql.sql +2 -2
- data/test/test_composite_arrays.rb +14 -0
- data/test/test_find.rb +8 -0
- data/test/test_ids.rb +3 -0
- metadata +11 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 98777241ea29aef880ba2b53631fb47686751a898df5b7200cd64a06fb84b838
|
4
|
+
data.tar.gz: 0f5d62c48beab81bcc7a31dd9a025af2867eeb8821482e2aabc0933ae10b95e5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 498c215b18b6056347095a00e81edf399cb0a684c8130413fbb0db87181451bf0801d9c5446b2d34d707137df0e984267d79a9f432accf0287003719a1e229b3
|
7
|
+
data.tar.gz: 1ed759331f302c751f4f93899d3d95945c8c768cd279f817b6431add9c7d97e5caa6b47f8500b8871fa6993a145b288fc6e56f7067ab2f5c479956a10e303d71
|
data/History.rdoc
CHANGED
@@ -64,7 +64,7 @@ module ActiveRecord
|
|
64
64
|
@preloaded_records.map { |record|
|
65
65
|
key = Array(association_key_name).map do |key_name|
|
66
66
|
record[key_name]
|
67
|
-
end.
|
67
|
+
end.to_composite_keys.to_s
|
68
68
|
|
69
69
|
[record, key]
|
70
70
|
}
|
@@ -77,7 +77,7 @@ module ActiveRecord
|
|
77
77
|
# owner[owner_key_name].to_s
|
78
78
|
Array(owner_key_name).map do |key_name|
|
79
79
|
owner[key_name]
|
80
|
-
end.
|
80
|
+
end.to_composite_keys.to_s
|
81
81
|
end
|
82
82
|
else
|
83
83
|
owners.group_by do |owner|
|
@@ -85,10 +85,9 @@ module ActiveRecord
|
|
85
85
|
# owner[owner_key_name]
|
86
86
|
Array(owner_key_name).map do |key_name|
|
87
87
|
owner[key_name]
|
88
|
-
end.
|
88
|
+
end.to_composite_keys.to_s
|
89
89
|
end
|
90
90
|
end
|
91
|
-
|
92
91
|
end
|
93
92
|
end
|
94
93
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
module CompositePrimaryKeys
|
2
2
|
ID_SEP = ','
|
3
3
|
ID_SET_SEP = ';'
|
4
|
+
ESCAPE_CHAR = '^'
|
4
5
|
|
5
6
|
module ArrayExtension
|
6
7
|
def to_composite_keys
|
@@ -8,12 +9,27 @@ module CompositePrimaryKeys
|
|
8
9
|
end
|
9
10
|
end
|
10
11
|
|
11
|
-
|
12
|
+
# Convert mixed representation of CPKs (by strings or arrays) to normalized
|
13
|
+
# representation (just by arrays).
|
14
|
+
#
|
15
|
+
# `ids` is Array that may contain:
|
16
|
+
# 1. A CPK represented by an array or a string.
|
17
|
+
# 2. An array of CPKs represented by arrays or strings.
|
18
|
+
#
|
19
|
+
# There is an issue. Let `ids` contain an array with serveral strings. We can't distinguish case 1
|
20
|
+
# from case 2 there in general. E.g. the item can be an array containing appropriate number of strings,
|
21
|
+
# and each string can contain appropriate number of commas. We consider case 2 to win there.
|
22
|
+
def self.normalize(ids, cpk_size)
|
12
23
|
ids.map do |id|
|
13
|
-
if id.
|
14
|
-
|
15
|
-
|
16
|
-
|
24
|
+
if Utils.cpk_as_array?(id, cpk_size) && id.any? { |item| !Utils.cpk_as_string?(item, cpk_size) }
|
25
|
+
# CPK as an array - case 1
|
26
|
+
id
|
27
|
+
elsif id.is_a?(Array)
|
28
|
+
# An array of CPKs - case 2
|
29
|
+
normalize(id, cpk_size)
|
30
|
+
elsif id.is_a?(String)
|
31
|
+
# CPK as a string - case 1
|
32
|
+
CompositeKeys.parse(id)
|
17
33
|
else
|
18
34
|
id
|
19
35
|
end
|
@@ -27,7 +43,7 @@ module CompositePrimaryKeys
|
|
27
43
|
when Array
|
28
44
|
value.to_composite_keys
|
29
45
|
when String
|
30
|
-
|
46
|
+
value.split(ID_SEP).map { |key| Utils.unescape_string_key(key) }.to_composite_keys
|
31
47
|
else
|
32
48
|
raise(ArgumentError, "Unsupported type: #{value}")
|
33
49
|
end
|
@@ -35,9 +51,36 @@ module CompositePrimaryKeys
|
|
35
51
|
|
36
52
|
def to_s
|
37
53
|
# Doing this makes it easier to parse Base#[](attr_name)
|
38
|
-
join(ID_SEP)
|
54
|
+
map { |key| Utils.escape_string_key(key.to_s) }.join(ID_SEP)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
module Utils
|
59
|
+
class << self
|
60
|
+
def escape_string_key(key)
|
61
|
+
key.gsub(Regexp.union(ESCAPE_CHAR, ID_SEP)) do |unsafe|
|
62
|
+
"#{ESCAPE_CHAR}#{unsafe.ord.to_s(16).upcase}"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def unescape_string_key(key)
|
67
|
+
key.gsub(/#{Regexp.escape(ESCAPE_CHAR)}[0-9a-fA-F]{2}/) do |escaped|
|
68
|
+
char = escaped.slice(1, 2).hex.chr
|
69
|
+
(char == ESCAPE_CHAR || char == ID_SEP) ? char : escaped
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def cpk_as_array?(value, pk_size)
|
74
|
+
# We don't permit Array to be an element of CPK.
|
75
|
+
value.is_a?(Array) && value.size == pk_size && value.none? { |item| item.is_a?(Array) }
|
76
|
+
end
|
77
|
+
|
78
|
+
def cpk_as_string?(value, pk_size)
|
79
|
+
value.is_a?(String) && value.count(ID_SEP) == pk_size - 1
|
80
|
+
end
|
39
81
|
end
|
40
82
|
end
|
83
|
+
private_constant :Utils
|
41
84
|
end
|
42
85
|
|
43
86
|
Array.send(:include, CompositePrimaryKeys::ArrayExtension)
|
@@ -84,7 +84,7 @@ module CompositePrimaryKeys
|
|
84
84
|
|
85
85
|
# CPK
|
86
86
|
# expects_array = ids.first.kind_of?(Array)
|
87
|
-
ids = CompositePrimaryKeys.normalize(ids)
|
87
|
+
ids = CompositePrimaryKeys.normalize(ids, @klass.primary_keys.length)
|
88
88
|
expects_array = ids.flatten != ids.flatten(1)
|
89
89
|
|
90
90
|
return ids.first if expects_array && ids.first.empty?
|
@@ -138,7 +138,7 @@ module CompositePrimaryKeys
|
|
138
138
|
|
139
139
|
result = ids.map do |cpk_ids|
|
140
140
|
cpk_ids = if cpk_ids.length == 1
|
141
|
-
cpk_ids.first
|
141
|
+
CompositePrimaryKeys::CompositeKeys.parse(cpk_ids.first)
|
142
142
|
else
|
143
143
|
cpk_ids.to_composite_keys
|
144
144
|
end
|
@@ -21,4 +21,18 @@ class CompositeArraysTest < ActiveSupport::TestCase
|
|
21
21
|
assert_equal CompositePrimaryKeys::CompositeKeys, keys.class
|
22
22
|
assert_equal '1,2,3', keys.to_s
|
23
23
|
end
|
24
|
+
|
25
|
+
def test_parse
|
26
|
+
assert_equal ['1', '2'], CompositePrimaryKeys::CompositeKeys.parse('1,2')
|
27
|
+
assert_equal ['The USA', '^Washington, D.C.'],
|
28
|
+
CompositePrimaryKeys::CompositeKeys.parse('The USA,^5EWashington^2C D.C.')
|
29
|
+
assert_equal ['The USA', '^Washington, D.C.'],
|
30
|
+
CompositePrimaryKeys::CompositeKeys.parse(['The USA', '^Washington, D.C.'])
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_to_s
|
34
|
+
assert_equal '1,2', CompositePrimaryKeys::CompositeKeys.new([1, 2]).to_s
|
35
|
+
assert_equal 'The USA,^5EWashington^2C D.C.',
|
36
|
+
CompositePrimaryKeys::CompositeKeys.new(['The USA', '^Washington, D.C.']).to_s
|
37
|
+
end
|
24
38
|
end
|
data/test/test_find.rb
CHANGED
@@ -41,6 +41,14 @@ class TestFind < ActiveSupport::TestCase
|
|
41
41
|
assert_equal(['The Netherlands', 'Amsterdam'], capitol.id)
|
42
42
|
end
|
43
43
|
|
44
|
+
def test_find_with_strings_with_comma_as_composite_keys
|
45
|
+
capitol = Capitol.create!(country: 'The USA', city: 'Washington, D.C.')
|
46
|
+
assert_equal ['The USA', 'Washington, D.C.'], capitol.id
|
47
|
+
|
48
|
+
assert_equal capitol, Capitol.find(['The USA', 'Washington, D.C.'])
|
49
|
+
assert_equal capitol, Capitol.find(capitol.to_param)
|
50
|
+
end
|
51
|
+
|
44
52
|
def test_find_each
|
45
53
|
room_assignments = []
|
46
54
|
RoomAssignment.find_each(:batch_size => 2) do |assignment|
|
data/test/test_ids.rb
CHANGED
@@ -40,6 +40,9 @@ class TestIds < ActiveSupport::TestCase
|
|
40
40
|
testing_with do
|
41
41
|
assert_equal '1,1', @first.to_param if composite?
|
42
42
|
end
|
43
|
+
|
44
|
+
capitol = Capitol.create!(country: 'The USA', city: 'Washington, D.C.')
|
45
|
+
assert_equal 'The USA,Washington^2C D.C.', capitol.to_param
|
43
46
|
end
|
44
47
|
|
45
48
|
def test_ids_to_s
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: composite_primary_keys
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 8.1.
|
4
|
+
version: 8.1.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Charlie Savage
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-01-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -28,30 +28,30 @@ dependencies:
|
|
28
28
|
name: sqlite3
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: 1.3.6
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: 1.3.6
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: pg
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '0'
|
47
|
+
version: '0.15'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - "
|
52
|
+
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '0'
|
54
|
+
version: '0.15'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: mysql2
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -285,7 +285,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
285
285
|
- !ruby/object:Gem::Version
|
286
286
|
version: '0'
|
287
287
|
requirements: []
|
288
|
-
rubygems_version: 3.0.
|
288
|
+
rubygems_version: 3.0.6
|
289
289
|
signing_key:
|
290
290
|
specification_version: 4
|
291
291
|
summary: Composite key support for ActiveRecord
|