@@ -12,43 +12,46 @@ class Entry < Record
12
12
13
13
class << self
14
14
def write ( key , value )
15
- upsert_all_no_query_cache ( [ { key : key , value : value } ] )
15
+ write_multi ( [ { key : key , value : value } ] )
16
16
end
17
17
18
18
def write_multi ( payloads )
19
- upsert_all_no_query_cache ( payloads )
19
+ without_query_cache do
20
+ upsert_all \
21
+ add_key_hash_and_byte_size ( payloads ) ,
22
+ unique_by : upsert_unique_by , on_duplicate : :update , update_only : [ :key , :value , :byte_size ]
23
+ end
20
24
end
21
25
22
26
def read ( key )
23
- result = select_all_no_query_cache ( [ key ] ) . first
24
- result [ 1 ] if result &.first == key
27
+ read_multi ( [ key ] ) [ key ]
25
28
end
26
29
27
30
def read_multi ( keys )
28
- results = select_all_no_query_cache ( keys ) . to_h
29
- results . except! ( results . keys - keys )
30
- end
31
-
32
- def delete_by_key ( key )
33
- delete_no_query_cache ( :key_hash , key_hash_for ( key ) ) > 0
31
+ without_query_cache do
32
+ find_by_sql ( [ select_sql ( keys ) , *key_hashes_for ( keys ) ] ) . pluck ( :key , :value ) . to_h
33
+ end
34
34
end
35
35
36
- def delete_multi ( keys )
37
- serialized_keys = keys . map { |key | key_hash_for ( key ) }
38
- delete_no_query_cache ( :key_hash , serialized_keys )
36
+ def delete_by_key ( *keys )
37
+ without_query_cache do
38
+ where ( key_hash : key_hashes_for ( keys ) ) . delete_all
39
+ end
39
40
end
40
41
41
42
def clear_truncate
42
43
connection . truncate ( table_name )
43
44
end
44
45
45
46
def clear_delete
46
- in_batches . delete_all
47
+ without_query_cache do
48
+ in_batches . delete_all
49
+ end
47
50
end
48
51
49
52
def lock_and_write ( key , &block )
50
53
transaction do
51
- uncached do
54
+ without_query_cache do
52
55
result = lock . where ( key_hash : key_hash_for ( key ) ) . pick ( :key , :value )
53
56
new_value = block . call ( result &.first == key ? result [ 1 ] : nil )
54
57
write ( key , new_value ) if new_value
@@ -58,33 +61,12 @@ def lock_and_write(key, &block)
58
61
end
59
62
60
63
def id_range
61
- uncached do
64
+ without_query_cache do
62
65
pick ( Arel . sql ( "max(id) - min(id) + 1" ) ) || 0
63
66
end
64
67
end
65
68
66
69
private
67
- def upsert_all_no_query_cache ( payloads )
68
- args = [ self . all ,
69
- connection_for_insert_all ,
70
- add_key_hash_and_byte_size ( payloads ) ] . compact
71
- options = { unique_by : upsert_unique_by ,
72
- on_duplicate : :update ,
73
- update_only : upsert_update_only }
74
- insert_all = ActiveRecord ::InsertAll . new ( *args , **options )
75
- sql = connection . build_insert_sql ( ActiveRecord ::InsertAll ::Builder . new ( insert_all ) )
76
-
77
- message = +"#{ self } "
78
- message << "Bulk " if payloads . many?
79
- message << "Upsert"
80
- # exec_query_method does not clear the query cache, exec_insert_all does
81
- connection . send exec_query_method , sql , message
82
- end
83
-
84
- def connection_for_insert_all
85
- Rails . version >= "7.2" ? connection : nil
86
- end
87
-
88
70
def add_key_hash_and_byte_size ( payloads )
89
71
payloads . map do |payload |
90
72
payload . dup . tap do |payload |
@@ -94,24 +76,10 @@ def add_key_hash_and_byte_size(payloads)
94
76
end
95
77
end
96
78
97
- def exec_query_method
98
- connection . respond_to? ( :internal_exec_query ) ? :internal_exec_query : :exec_query
99
- end
100
-
101
79
def upsert_unique_by
102
80
connection . supports_insert_conflict_target? ? :key_hash : nil
103
81
end
104
82
105
- def upsert_update_only
106
- [ :key , :value , :byte_size ]
107
- end
108
-
109
- def select_all_no_query_cache ( keys )
110
- uncached do
111
- find_by_sql ( [ select_sql ( keys ) , *key_hashes_for ( keys ) ] ) . pluck ( :key , :value )
112
- end
113
- end
114
-
115
83
def select_sql ( keys )
116
84
@get_sql ||= { }
117
85
@get_sql [ keys . count ] ||= \
@@ -121,24 +89,6 @@ def select_sql(keys)
121
89
. gsub ( "1111, 2222" , ( [ "?" ] * keys . count ) . join ( ", " ) )
122
90
end
123
91
124
- def delete_no_query_cache ( attribute , values )
125
- uncached do
126
- relation = where ( attribute => values )
127
- sql = connection . to_sql ( relation . arel . compile_delete ( relation . table [ primary_key ] ) )
128
-
129
- # exec_delete does not clear the query cache
130
- if connection . prepared_statements?
131
- connection . exec_delete ( sql , "#{ name } Delete All" , Array ( values ) )
132
- else
133
- connection . exec_delete ( sql , "#{ name } Delete All" )
134
- end
135
- end
136
- end
137
-
138
- def to_binary ( key )
139
- ActiveModel ::Type ::Binary . new . serialize ( key )
140
- end
141
-
142
92
def key_hash_for ( key )
143
93
# Need to unpack this as a signed integer - Postgresql and SQLite don't support unsigned integers
144
94
Digest ::SHA256 . digest ( key . to_s ) . unpack ( "q>" ) . first
@@ -151,6 +101,10 @@ def key_hashes_for(keys)
151
101
def byte_size_for ( payload )
152
102
payload [ :key ] . to_s . bytesize + payload [ :value ] . to_s . bytesize + ESTIMATED_ROW_OVERHEAD
153
103
end
104
+
105
+ def without_query_cache ( &block )
106
+ uncached ( dirties : false , &block )
107
+ end
154
108
end
155
109
end
156
110
end
0 commit comments