moneta 1.1.0 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.rubocop.yml +194 -0
- data/.travis.yml +65 -25
- data/CHANGES +36 -0
- data/CONTRIBUTORS +4 -2
- data/Gemfile +94 -65
- data/README.md +50 -25
- data/feature_matrix.yaml +3 -11
- data/lib/action_dispatch/middleware/session/moneta_store.rb +1 -0
- data/lib/active_support/cache/moneta_store.rb +5 -5
- data/lib/moneta.rb +20 -10
- data/lib/moneta/adapters/activerecord.rb +35 -19
- data/lib/moneta/adapters/activesupportcache.rb +3 -7
- data/lib/moneta/adapters/cassandra.rb +24 -16
- data/lib/moneta/adapters/client.rb +62 -21
- data/lib/moneta/adapters/couch.rb +225 -80
- data/lib/moneta/adapters/datamapper.rb +1 -0
- data/lib/moneta/adapters/file.rb +9 -6
- data/lib/moneta/adapters/hbase.rb +1 -1
- data/lib/moneta/adapters/kyotocabinet.rb +8 -7
- data/lib/moneta/adapters/leveldb.rb +1 -1
- data/lib/moneta/adapters/lmdb.rb +3 -4
- data/lib/moneta/adapters/lruhash.rb +29 -62
- data/lib/moneta/adapters/memcached.rb +1 -0
- data/lib/moneta/adapters/memcached/dalli.rb +1 -1
- data/lib/moneta/adapters/memcached/native.rb +10 -8
- data/lib/moneta/adapters/mongo.rb +256 -6
- data/lib/moneta/adapters/null.rb +1 -2
- data/lib/moneta/adapters/pstore.rb +3 -2
- data/lib/moneta/adapters/redis.rb +8 -4
- data/lib/moneta/adapters/restclient.rb +12 -3
- data/lib/moneta/adapters/riak.rb +2 -2
- data/lib/moneta/adapters/sequel.rb +137 -328
- data/lib/moneta/adapters/sequel/mysql.rb +66 -0
- data/lib/moneta/adapters/sequel/postgres.rb +80 -0
- data/lib/moneta/adapters/sequel/postgres_hstore.rb +240 -0
- data/lib/moneta/adapters/sequel/sqlite.rb +57 -0
- data/lib/moneta/adapters/sqlite.rb +25 -11
- data/lib/moneta/adapters/tokyotyrant.rb +1 -1
- data/lib/moneta/builder.rb +2 -3
- data/lib/moneta/create_support.rb +21 -0
- data/lib/moneta/dbm_adapter.rb +31 -0
- data/lib/moneta/{mixins.rb → defaults.rb} +3 -302
- data/lib/moneta/each_key_support.rb +27 -0
- data/lib/moneta/enumerable.rb +38 -0
- data/lib/moneta/expires.rb +12 -12
- data/lib/moneta/expires_support.rb +60 -0
- data/lib/moneta/fallback.rb +84 -0
- data/lib/moneta/hash_adapter.rb +68 -0
- data/lib/moneta/increment_support.rb +16 -0
- data/lib/moneta/lock.rb +7 -2
- data/lib/moneta/logger.rb +2 -2
- data/lib/moneta/nil_values.rb +35 -0
- data/lib/moneta/option_support.rb +51 -0
- data/lib/moneta/optionmerger.rb +0 -1
- data/lib/moneta/pool.rb +312 -30
- data/lib/moneta/proxy.rb +3 -3
- data/lib/moneta/server.rb +216 -65
- data/lib/moneta/shared.rb +13 -7
- data/lib/moneta/stack.rb +6 -6
- data/lib/moneta/synchronize.rb +3 -3
- data/lib/moneta/transformer.rb +68 -24
- data/lib/moneta/transformer/config.rb +63 -43
- data/lib/moneta/transformer/helper.rb +3 -3
- data/lib/moneta/transformer/helper/bson.rb +7 -14
- data/lib/moneta/utils.rb +3 -9
- data/lib/moneta/version.rb +1 -1
- data/lib/moneta/weak_each_key.rb +2 -4
- data/lib/rack/cache/moneta.rb +13 -11
- data/lib/rack/moneta_rest.rb +2 -2
- data/lib/rack/session/moneta.rb +3 -4
- data/moneta.gemspec +18 -4
- data/script/benchmarks +145 -46
- data/script/contributors +11 -6
- data/script/start-couchdb +27 -0
- data/script/start-hbase +3 -2
- data/script/start-services +3 -11
- data/spec/active_support/cache_moneta_store_spec.rb +30 -30
- data/spec/features/concurrent_create.rb +31 -10
- data/spec/features/concurrent_increment.rb +26 -19
- data/spec/features/create_expires.rb +15 -15
- data/spec/features/default_expires.rb +11 -12
- data/spec/features/expires.rb +215 -210
- data/spec/features/increment.rb +41 -41
- data/spec/features/store.rb +3 -3
- data/spec/helper.rb +23 -82
- data/spec/moneta/adapters/activerecord/standard_activerecord_spec.rb +1 -1
- data/spec/moneta/adapters/activerecord/standard_activerecord_with_expires_spec.rb +1 -1
- data/spec/moneta/adapters/activesupportcache/adapter_activesupportcache_spec.rb +4 -1
- data/spec/moneta/adapters/activesupportcache/adapter_activesupportcache_with_default_expires_spec.rb +4 -1
- data/spec/moneta/adapters/activesupportcache/standard_activesupportcache_spec.rb +14 -0
- data/spec/moneta/adapters/cassandra/standard_cassandra_spec.rb +1 -1
- data/spec/moneta/adapters/client/adapter_client_spec.rb +6 -6
- data/spec/moneta/adapters/client/client_helper.rb +24 -0
- data/spec/moneta/adapters/client/standard_client_tcp_spec.rb +8 -8
- data/spec/moneta/adapters/client/standard_client_unix_spec.rb +23 -7
- data/spec/moneta/adapters/couch/adapter_couch_spec.rb +199 -2
- data/spec/moneta/adapters/couch/standard_couch_spec.rb +9 -3
- data/spec/moneta/adapters/couch/standard_couch_with_expires_spec.rb +8 -2
- data/spec/moneta/adapters/daybreak/standard_daybreak_spec.rb +1 -1
- data/spec/moneta/adapters/daybreak/standard_daybreak_with_expires_spec.rb +1 -1
- data/spec/moneta/adapters/dbm/standard_dbm_spec.rb +1 -1
- data/spec/moneta/adapters/dbm/standard_dbm_with_expires_spec.rb +1 -1
- data/spec/moneta/adapters/faraday_helper.rb +9 -0
- data/spec/moneta/adapters/file/standard_file_spec.rb +2 -2
- data/spec/moneta/adapters/file/standard_file_with_expires_spec.rb +1 -1
- data/spec/moneta/adapters/gdbm/standard_gdbm_spec.rb +1 -1
- data/spec/moneta/adapters/gdbm/standard_gdbm_with_expires_spec.rb +1 -1
- data/spec/moneta/adapters/kyotocabinet/adapter_kyotocabinet_spec.rb +1 -1
- data/spec/moneta/adapters/kyotocabinet/standard_kyotocabinet_spec.rb +2 -2
- data/spec/moneta/adapters/kyotocabinet/standard_kyotocabinet_with_expires_spec.rb +2 -2
- data/spec/moneta/adapters/leveldb/standard_leveldb_spec.rb +1 -1
- data/spec/moneta/adapters/leveldb/standard_leveldb_with_expires_spec.rb +1 -1
- data/spec/moneta/adapters/lmdb/standard_lmdb_spec.rb +1 -1
- data/spec/moneta/adapters/lmdb/standard_lmdb_with_expires_spec.rb +1 -1
- data/spec/moneta/adapters/lruhash/adapter_lruhash_spec.rb +2 -2
- data/spec/moneta/adapters/lruhash/standard_lruhash_spec.rb +1 -1
- data/spec/moneta/adapters/lruhash/standard_lruhash_with_expires_spec.rb +1 -1
- data/spec/moneta/adapters/memcached/adapter_memcached_spec.rb +1 -1
- data/spec/moneta/adapters/memcached/dalli/adapter_memcached_dalli_spec.rb +1 -1
- data/spec/moneta/adapters/memcached/dalli/adapter_memcached_dalli_with_default_expires_spec.rb +1 -1
- data/spec/moneta/adapters/memcached/dalli/standard_memcached_dalli_spec.rb +1 -1
- data/spec/moneta/adapters/memcached/native/adapter_memcached_native_spec.rb +1 -1
- data/spec/moneta/adapters/memcached/native/adapter_memcached_native_with_default_expires_spec.rb +1 -1
- data/spec/moneta/adapters/memcached/native/standard_memcached_native_spec.rb +1 -1
- data/spec/moneta/adapters/memcached/standard_memcached_spec.rb +1 -1
- data/spec/moneta/adapters/{memcached/helper.rb → memcached_helper.rb} +0 -0
- data/spec/moneta/adapters/memory/standard_memory_spec.rb +1 -1
- data/spec/moneta/adapters/memory/standard_memory_with_compress_spec.rb +1 -1
- data/spec/moneta/adapters/memory/standard_memory_with_expires_spec.rb +1 -1
- data/spec/moneta/adapters/memory/standard_memory_with_json_key_serializer_spec.rb +1 -1
- data/spec/moneta/adapters/memory/standard_memory_with_json_serializer_spec.rb +1 -1
- data/spec/moneta/adapters/memory/standard_memory_with_json_value_serializer_spec.rb +2 -2
- data/spec/moneta/adapters/memory/standard_memory_with_prefix_spec.rb +39 -2
- data/spec/moneta/adapters/memory/standard_memory_with_snappy_compress_spec.rb +2 -2
- data/spec/moneta/adapters/mongo/adapter_mongo_spec.rb +18 -2
- data/spec/moneta/adapters/mongo/adapter_mongo_with_default_expires_spec.rb +5 -3
- data/spec/moneta/adapters/mongo/standard_mongo_spec.rb +2 -2
- data/spec/moneta/adapters/null/null_adapter_spec.rb +1 -1
- data/spec/moneta/adapters/pstore/standard_pstore_spec.rb +1 -1
- data/spec/moneta/adapters/pstore/standard_pstore_with_expires_spec.rb +1 -1
- data/spec/moneta/adapters/redis/standard_redis_spec.rb +1 -1
- data/spec/moneta/adapters/restclient/adapter_restclient_spec.rb +7 -5
- data/spec/moneta/adapters/restclient/helper.rb +12 -0
- data/spec/moneta/adapters/restclient/standard_restclient_spec.rb +9 -6
- data/spec/moneta/adapters/riak/standard_riak_with_expires_spec.rb +4 -0
- data/spec/moneta/adapters/sdbm/standard_sdbm_spec.rb +1 -1
- data/spec/moneta/adapters/sdbm/standard_sdbm_with_expires_spec.rb +1 -1
- data/spec/moneta/adapters/sequel/adapter_sequel_spec.rb +31 -79
- data/spec/moneta/adapters/sequel/helper.rb +75 -0
- data/spec/moneta/adapters/sequel/standard_sequel_spec.rb +5 -11
- data/spec/moneta/adapters/sequel/standard_sequel_with_expires_spec.rb +8 -9
- data/spec/moneta/adapters/sqlite/standard_sqlite_spec.rb +1 -1
- data/spec/moneta/adapters/sqlite/standard_sqlite_with_expires_spec.rb +1 -1
- data/spec/moneta/adapters/tdb/standard_tdb_spec.rb +1 -1
- data/spec/moneta/adapters/tdb/standard_tdb_with_expires_spec.rb +1 -1
- data/spec/moneta/adapters/tokyocabinet/standard_tokyocabinet_spec.rb +1 -1
- data/spec/moneta/adapters/tokyocabinet/standard_tokyocabinet_with_expires_spec.rb +1 -1
- data/spec/moneta/adapters/tokyotyrant/adapter_tokyotyrant_spec.rb +6 -2
- data/spec/moneta/adapters/tokyotyrant/helper.rb +12 -0
- data/spec/moneta/adapters/tokyotyrant/standard_tokyotyrant_spec.rb +5 -2
- data/spec/moneta/adapters/tokyotyrant/standard_tokyotyrant_with_expires_spec.rb +5 -1
- data/spec/moneta/adapters/yaml/standard_yaml_spec.rb +1 -1
- data/spec/moneta/adapters/yaml/standard_yaml_with_expires_spec.rb +1 -1
- data/spec/moneta/builder_spec.rb +22 -0
- data/spec/moneta/proxies/enumerable/enumerable_spec.rb +26 -0
- data/spec/moneta/proxies/expires/expires_file_spec.rb +1 -1
- data/spec/moneta/proxies/fallback/fallback_spec.rb +42 -0
- data/spec/moneta/proxies/pool/pool_spec.rb +319 -6
- data/spec/moneta/proxies/shared/shared_tcp_spec.rb +14 -4
- data/spec/moneta/proxies/shared/shared_unix_spec.rb +14 -4
- data/spec/moneta/proxies/transformer/transformer_bencode_spec.rb +1 -1
- data/spec/moneta/proxies/transformer/transformer_bert_spec.rb +3 -3
- data/spec/moneta/proxies/transformer/transformer_bson_spec.rb +2 -2
- data/spec/moneta/proxies/transformer/transformer_json_spec.rb +1 -1
- data/spec/moneta/proxies/transformer/transformer_key_marshal_spec.rb +1 -1
- data/spec/moneta/proxies/transformer/transformer_key_yaml_spec.rb +1 -1
- data/spec/moneta/proxies/transformer/transformer_marshal_base64_spec.rb +1 -1
- data/spec/moneta/proxies/transformer/transformer_marshal_escape_spec.rb +8 -4
- data/spec/moneta/proxies/transformer/transformer_marshal_hex_spec.rb +1 -1
- data/spec/moneta/proxies/transformer/transformer_marshal_hmac_spec.rb +1 -1
- data/spec/moneta/proxies/transformer/transformer_marshal_prefix_base64_spec.rb +33 -0
- data/spec/moneta/proxies/transformer/transformer_marshal_prefix_spec.rb +1 -1
- data/spec/moneta/proxies/transformer/transformer_marshal_qp_spec.rb +1 -1
- data/spec/moneta/proxies/transformer/transformer_marshal_spec.rb +1 -1
- data/spec/moneta/proxies/transformer/transformer_marshal_urlsafe_base64_spec.rb +1 -1
- data/spec/moneta/proxies/transformer/transformer_marshal_uuencode_spec.rb +1 -1
- data/spec/moneta/proxies/transformer/transformer_msgpack_spec.rb +1 -1
- data/spec/moneta/proxies/transformer/transformer_ox_spec.rb +1 -1
- data/spec/moneta/proxies/transformer/transformer_php_spec.rb +1 -1
- data/spec/moneta/proxies/transformer/transformer_tnet_spec.rb +1 -1
- data/spec/moneta/proxies/transformer/transformer_yaml_spec.rb +2 -2
- data/spec/moneta/proxies/weak_each_key/weak_each_key_spec.rb +0 -2
- data/spec/restserver.rb +55 -0
- data/spec/support/mongo_helper.rb +12 -0
- metadata +140 -32
- data/lib/moneta/adapters/mongo/base.rb +0 -103
- data/lib/moneta/adapters/mongo/moped.rb +0 -164
- data/lib/moneta/adapters/mongo/official.rb +0 -157
- data/script/install-kyotocabinet +0 -17
- data/spec/moneta/adapters/mongo/adapter_mongo_moped_spec.rb +0 -25
- data/spec/moneta/adapters/mongo/adapter_mongo_moped_with_default_expires_spec.rb +0 -12
- data/spec/moneta/adapters/mongo/adapter_mongo_official_spec.rb +0 -25
- data/spec/moneta/adapters/mongo/adapter_mongo_official_with_default_expires_spec.rb +0 -12
- data/spec/moneta/adapters/mongo/standard_mongo_moped_spec.rb +0 -7
- data/spec/moneta/adapters/mongo/standard_mongo_official_spec.rb +0 -7
- data/spec/quality_spec.rb +0 -51
@@ -0,0 +1,66 @@
|
|
1
|
+
module Moneta
|
2
|
+
module Adapters
|
3
|
+
class Sequel
|
4
|
+
# @api private
|
5
|
+
module MySQL
|
6
|
+
def store(key, value, options = {})
|
7
|
+
@store.call(key: key, value: blob(value))
|
8
|
+
value
|
9
|
+
end
|
10
|
+
|
11
|
+
def increment(key, amount = 1, options = {})
|
12
|
+
@backend.transaction do
|
13
|
+
# this creates a row-level lock even if there is no existing row (a
|
14
|
+
# "gap lock").
|
15
|
+
if row = @load_for_update.call(key: key)
|
16
|
+
# Integer() will raise an exception if the existing value cannot be parsed
|
17
|
+
amount += Integer(row[value_column])
|
18
|
+
@increment_update.call(key: key, value: amount)
|
19
|
+
else
|
20
|
+
@create.call(key: key, value: amount)
|
21
|
+
end
|
22
|
+
amount
|
23
|
+
end
|
24
|
+
rescue ::Sequel::SerializationFailure # Thrown on deadlock
|
25
|
+
tries ||= 0
|
26
|
+
(tries += 1) <= 3 ? retry : raise
|
27
|
+
end
|
28
|
+
|
29
|
+
def merge!(pairs, options = {}, &block)
|
30
|
+
@backend.transaction do
|
31
|
+
pairs = yield_merge_pairs(pairs, &block) if block_given?
|
32
|
+
@table
|
33
|
+
.on_duplicate_key_update
|
34
|
+
.import([key_column, value_column], blob_pairs(pairs).to_a)
|
35
|
+
end
|
36
|
+
|
37
|
+
self
|
38
|
+
end
|
39
|
+
|
40
|
+
def each_key
|
41
|
+
return super unless block_given? && @each_key_server && @table.respond_to?(:stream)
|
42
|
+
# Order is not required when streaming
|
43
|
+
@table.server(@each_key_server).select(key_column).paged_each do |row|
|
44
|
+
yield row[key_column]
|
45
|
+
end
|
46
|
+
self
|
47
|
+
end
|
48
|
+
|
49
|
+
protected
|
50
|
+
|
51
|
+
def prepare_store
|
52
|
+
@store = @table
|
53
|
+
.on_duplicate_key_update
|
54
|
+
.prepare(:insert, statement_id(:store), key_column => :$key, value_column => :$value)
|
55
|
+
end
|
56
|
+
|
57
|
+
def prepare_increment
|
58
|
+
@increment_update = @table
|
59
|
+
.where(key_column => :$key)
|
60
|
+
.prepare(:update, statement_id(:increment_update), value_column => :$value)
|
61
|
+
super
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module Moneta
|
2
|
+
module Adapters
|
3
|
+
# @api public
|
4
|
+
class Sequel
|
5
|
+
# @api private
|
6
|
+
module Postgres
|
7
|
+
def store(key, value, options = {})
|
8
|
+
@store.call(key: key, value: blob(value))
|
9
|
+
value
|
10
|
+
end
|
11
|
+
|
12
|
+
def increment(key, amount = 1, options = {})
|
13
|
+
result = @increment.call(key: key, value: blob(amount.to_s), amount: amount)
|
14
|
+
if row = result.first
|
15
|
+
row[value_column].to_i
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def delete(key, options = {})
|
20
|
+
result = @delete.call(key: key)
|
21
|
+
if row = result.first
|
22
|
+
row[value_column]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def merge!(pairs, options = {}, &block)
|
27
|
+
@backend.transaction do
|
28
|
+
pairs = yield_merge_pairs(pairs, &block) if block_given?
|
29
|
+
@table
|
30
|
+
.insert_conflict(target: key_column,
|
31
|
+
update: { value_column => ::Sequel[:excluded][value_column] })
|
32
|
+
.import([key_column, value_column], blob_pairs(pairs).to_a)
|
33
|
+
end
|
34
|
+
|
35
|
+
self
|
36
|
+
end
|
37
|
+
|
38
|
+
def each_key
|
39
|
+
return super unless block_given? && !@each_key_server && @table.respond_to?(:use_cursor)
|
40
|
+
# With a cursor, this will Just Work.
|
41
|
+
@table.select(key_column).paged_each do |row|
|
42
|
+
yield row[key_column]
|
43
|
+
end
|
44
|
+
self
|
45
|
+
end
|
46
|
+
|
47
|
+
protected
|
48
|
+
|
49
|
+
def prepare_store
|
50
|
+
@store = @table
|
51
|
+
.insert_conflict(target: key_column,
|
52
|
+
update: { value_column => ::Sequel[:excluded][value_column] })
|
53
|
+
.prepare(:insert, statement_id(:store), key_column => :$key, value_column => :$value)
|
54
|
+
end
|
55
|
+
|
56
|
+
def prepare_increment
|
57
|
+
update_expr = ::Sequel[:convert_to].function(
|
58
|
+
(::Sequel[:convert_from].function(
|
59
|
+
::Sequel[@table_name][value_column],
|
60
|
+
'UTF8'
|
61
|
+
).cast(Integer) + :$amount).cast(String),
|
62
|
+
'UTF8'
|
63
|
+
)
|
64
|
+
|
65
|
+
@increment = @table
|
66
|
+
.returning(value_column)
|
67
|
+
.insert_conflict(target: key_column, update: { value_column => update_expr })
|
68
|
+
.prepare(:insert, statement_id(:increment), key_column => :$key, value_column => :$value)
|
69
|
+
end
|
70
|
+
|
71
|
+
def prepare_delete
|
72
|
+
@delete = @table
|
73
|
+
.returning(value_column)
|
74
|
+
.where(key_column => :$key)
|
75
|
+
.prepare(:delete, statement_id(:delete))
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,240 @@
|
|
1
|
+
::Sequel.extension :pg_hstore_ops
|
2
|
+
|
3
|
+
module Moneta
|
4
|
+
module Adapters
|
5
|
+
class Sequel
|
6
|
+
# @api private
|
7
|
+
module PostgresHStore
|
8
|
+
def self.extended(mod)
|
9
|
+
mod.backend.extension :pg_hstore
|
10
|
+
mod.backend.extension :pg_array
|
11
|
+
end
|
12
|
+
|
13
|
+
def key?(key, options = {})
|
14
|
+
if @key
|
15
|
+
row = @key.call(row: @row, key: key) || false
|
16
|
+
row && row[:present]
|
17
|
+
else
|
18
|
+
@key_pl.get(key)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def store(key, value, options = {})
|
23
|
+
@backend.transaction do
|
24
|
+
create_row
|
25
|
+
@store.call(row: @row, pair: ::Sequel.hstore(key => value))
|
26
|
+
end
|
27
|
+
value
|
28
|
+
end
|
29
|
+
|
30
|
+
def load(key, options = {})
|
31
|
+
if row = @load.call(row: @row, key: key)
|
32
|
+
row[:value]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def delete(key, options = {})
|
37
|
+
@backend.transaction do
|
38
|
+
value = load(key, options)
|
39
|
+
@delete.call(row: @row, key: key)
|
40
|
+
value
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def increment(key, amount = 1, options = {})
|
45
|
+
@backend.transaction do
|
46
|
+
create_row
|
47
|
+
if row = @increment.call(row: @row, key: key, amount: amount).first
|
48
|
+
row[:value].to_i
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def create(key, value, options = {})
|
54
|
+
@backend.transaction do
|
55
|
+
create_row
|
56
|
+
1 ==
|
57
|
+
if @create
|
58
|
+
@create.call(row: @row, key: key, pair: ::Sequel.hstore(key => value))
|
59
|
+
else
|
60
|
+
@table
|
61
|
+
.where(key_column => @row)
|
62
|
+
.exclude(::Sequel[value_column].hstore.key?(key))
|
63
|
+
.update(value_column => ::Sequel[value_column].hstore.merge(key => value))
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def clear(options = {})
|
69
|
+
@clear.call(row: @row)
|
70
|
+
self
|
71
|
+
end
|
72
|
+
|
73
|
+
def values_at(*keys, **options)
|
74
|
+
if row = @values_at.call(row: @row, keys: ::Sequel.pg_array(keys))
|
75
|
+
row[:values].to_a
|
76
|
+
else
|
77
|
+
[]
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def slice(*keys, **options)
|
82
|
+
if row = @slice.call(row: @row, keys: ::Sequel.pg_array(keys))
|
83
|
+
row[:pairs].to_h
|
84
|
+
else
|
85
|
+
[]
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def merge!(pairs, options = {}, &block)
|
90
|
+
@backend.transaction do
|
91
|
+
create_row
|
92
|
+
pairs = yield_merge_pairs(pairs, &block) if block_given?
|
93
|
+
hash = Hash === pairs ? pairs : Hash[pairs.to_a]
|
94
|
+
@store.call(row: @row, pair: ::Sequel.hstore(hash))
|
95
|
+
end
|
96
|
+
|
97
|
+
self
|
98
|
+
end
|
99
|
+
|
100
|
+
def each_key
|
101
|
+
return enum_for(:each_key) { @size.call(row: @row)[:size] } unless block_given?
|
102
|
+
|
103
|
+
ds =
|
104
|
+
if @each_key_server
|
105
|
+
@table.server(@each_key_server)
|
106
|
+
else
|
107
|
+
@table
|
108
|
+
end
|
109
|
+
ds = ds.order(:skeys) unless @table.respond_to?(:use_cursor)
|
110
|
+
ds.where(key_column => @row)
|
111
|
+
.select(::Sequel[value_column].hstore.skeys)
|
112
|
+
.paged_each do |row|
|
113
|
+
yield row[:skeys]
|
114
|
+
end
|
115
|
+
self
|
116
|
+
end
|
117
|
+
|
118
|
+
protected
|
119
|
+
|
120
|
+
def create_row
|
121
|
+
@create_row.call(row: @row)
|
122
|
+
end
|
123
|
+
|
124
|
+
def create_table
|
125
|
+
key_column = self.key_column
|
126
|
+
value_column = self.value_column
|
127
|
+
|
128
|
+
@backend.create_table?(@table_name) do
|
129
|
+
column key_column, String, null: false, primary_key: true
|
130
|
+
column value_column, :hstore
|
131
|
+
index value_column, type: :gin
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def slice_for_update(pairs)
|
136
|
+
keys = pairs.map { |k, _| k }.to_a
|
137
|
+
if row = @slice_for_update.call(row: @row, keys: ::Sequel.pg_array(keys))
|
138
|
+
row[:pairs].to_h
|
139
|
+
else
|
140
|
+
{}
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def prepare_statements
|
145
|
+
super
|
146
|
+
prepare_create_row
|
147
|
+
prepare_clear
|
148
|
+
prepare_values_at
|
149
|
+
prepare_size
|
150
|
+
end
|
151
|
+
|
152
|
+
def prepare_create_row
|
153
|
+
@create_row = @table
|
154
|
+
.insert_ignore
|
155
|
+
.prepare(:insert, statement_id(:hstore_create_row), key_column => :$row, value_column => '')
|
156
|
+
end
|
157
|
+
|
158
|
+
def prepare_clear
|
159
|
+
@clear = @table.where(key_column => :$row).prepare(:update, statement_id(:hstore_clear), value_column => '')
|
160
|
+
end
|
161
|
+
|
162
|
+
def prepare_key
|
163
|
+
if defined?(JRUBY_VERSION)
|
164
|
+
@key_pl = ::Sequel::Dataset::PlaceholderLiteralizer.loader(@table) do |pl, ds|
|
165
|
+
ds.where(key_column => @row).select(::Sequel[value_column].hstore.key?(pl.arg))
|
166
|
+
end
|
167
|
+
else
|
168
|
+
@key = @table.where(key_column => :$row)
|
169
|
+
.select(::Sequel[value_column].hstore.key?(:$key).as(:present))
|
170
|
+
.prepare(:first, statement_id(:hstore_key))
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def prepare_store
|
175
|
+
@store = @table
|
176
|
+
.where(key_column => :$row)
|
177
|
+
.prepare(:update, statement_id(:hstore_store), value_column => ::Sequel[value_column].hstore.merge(:$pair))
|
178
|
+
end
|
179
|
+
|
180
|
+
def prepare_increment
|
181
|
+
pair = ::Sequel[:hstore]
|
182
|
+
.function(:$key, (
|
183
|
+
::Sequel[:coalesce].function(::Sequel[value_column].hstore[:$key].cast(Integer), 0) +
|
184
|
+
:$amount
|
185
|
+
).cast(String))
|
186
|
+
|
187
|
+
@increment = @table
|
188
|
+
.returning(::Sequel[value_column].hstore[:$key].as(:value))
|
189
|
+
.where(key_column => :$row)
|
190
|
+
.prepare(:update, statement_id(:hstore_increment), value_column => ::Sequel.join([value_column, pair]))
|
191
|
+
end
|
192
|
+
|
193
|
+
def prepare_load
|
194
|
+
@load = @table.where(key_column => :$row)
|
195
|
+
.select(::Sequel[value_column].hstore[:$key].as(:value))
|
196
|
+
.prepare(:first, statement_id(:hstore_load))
|
197
|
+
end
|
198
|
+
|
199
|
+
def prepare_delete
|
200
|
+
@delete = @table.where(key_column => :$row)
|
201
|
+
.prepare(:update, statement_id(:hstore_delete), value_column => ::Sequel[value_column].hstore.delete(:$key))
|
202
|
+
end
|
203
|
+
|
204
|
+
def prepare_create
|
205
|
+
# Under JRuby we can't use a prepared statement for queries involving
|
206
|
+
# the hstore `?` (key?) operator. See
|
207
|
+
# https://stackoverflow.com/questions/11940401/escaping-hstore-contains-operators-in-a-jdbc-prepared-statement
|
208
|
+
return if defined?(JRUBY_VERSION)
|
209
|
+
@create = @table
|
210
|
+
.where(key_column => :$row)
|
211
|
+
.exclude(::Sequel[value_column].hstore.key?(:$key))
|
212
|
+
.prepare(:update, statement_id(:hstore_create), value_column => ::Sequel[value_column].hstore.merge(:$pair))
|
213
|
+
end
|
214
|
+
|
215
|
+
def prepare_values_at
|
216
|
+
@values_at = @table
|
217
|
+
.where(key_column => :$row)
|
218
|
+
.select(::Sequel[value_column].hstore[::Sequel.cast(:$keys, :"text[]")].as(:values))
|
219
|
+
.prepare(:first, statement_id(:hstore_values_at))
|
220
|
+
end
|
221
|
+
|
222
|
+
def prepare_slice
|
223
|
+
slice = @table
|
224
|
+
.where(key_column => :$row)
|
225
|
+
.select(::Sequel[value_column].hstore.slice(:$keys).as(:pairs))
|
226
|
+
@slice = slice.prepare(:first, statement_id(:hstore_slice))
|
227
|
+
@slice_for_update = slice.for_update.prepare(:first, statement_id(:hstore_slice_for_update))
|
228
|
+
end
|
229
|
+
|
230
|
+
def prepare_size
|
231
|
+
@size = @backend
|
232
|
+
.from(@table.where(key_column => :$row)
|
233
|
+
.select(::Sequel[value_column].hstore.each))
|
234
|
+
.select { count.function.*.as(:size) }
|
235
|
+
.prepare(:first, statement_id(:hstore_size))
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Moneta
|
2
|
+
module Adapters
|
3
|
+
class Sequel
|
4
|
+
# @api private
|
5
|
+
module SQLite
|
6
|
+
def self.extended(mod)
|
7
|
+
version = mod.backend.get(::Sequel[:sqlite_version].function)
|
8
|
+
# See https://sqlite.org/lang_UPSERT.html
|
9
|
+
mod.instance_variable_set(:@can_upsert, ::Gem::Version.new(version) >= ::Gem::Version.new('3.24.0'))
|
10
|
+
end
|
11
|
+
|
12
|
+
def store(key, value, options = {})
|
13
|
+
@table.insert_conflict(:replace).insert(key_column => key, value_column => blob(value))
|
14
|
+
value
|
15
|
+
end
|
16
|
+
|
17
|
+
def increment(key, amount = 1, options = {})
|
18
|
+
return super unless @can_upsert
|
19
|
+
@backend.transaction do
|
20
|
+
@increment.call(key: key, value: blob(amount.to_s), amount: amount)
|
21
|
+
Integer(load(key))
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def merge!(pairs, options = {}, &block)
|
26
|
+
@backend.transaction do
|
27
|
+
pairs = yield_merge_pairs(pairs, &block) if block_given?
|
28
|
+
@table.insert_conflict(:replace).import([key_column, value_column], blob_pairs(pairs).to_a)
|
29
|
+
end
|
30
|
+
|
31
|
+
self
|
32
|
+
end
|
33
|
+
|
34
|
+
protected
|
35
|
+
|
36
|
+
def prepare_store
|
37
|
+
@store = @table
|
38
|
+
.insert_conflict(:replace)
|
39
|
+
.prepare(:insert, statement_id(:store), key_column => :$key, value_column => :$value)
|
40
|
+
end
|
41
|
+
|
42
|
+
def prepare_increment
|
43
|
+
return super unless @can_upsert
|
44
|
+
update_expr = (::Sequel[value_column].cast(Integer) + :$amount).cast(:blob)
|
45
|
+
@increment = @table
|
46
|
+
.insert_conflict(
|
47
|
+
target: key_column,
|
48
|
+
update: { value_column => update_expr },
|
49
|
+
update_where: ::Sequel.|({ value_column => blob("0") },
|
50
|
+
{ ::Sequel.~(::Sequel[value_column].cast(Integer)) => 0 })
|
51
|
+
)
|
52
|
+
.prepare(:insert, statement_id(:increment), key_column => :$key, value_column => :$value)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -30,14 +30,24 @@ module Moneta
|
|
30
30
|
@backend.journal_mode = journal_mode.to_s
|
31
31
|
end
|
32
32
|
@stmts =
|
33
|
-
[@exists
|
34
|
-
@select
|
33
|
+
[@exists = @backend.prepare("select exists(select 1 from #{@table} where k = ?)"),
|
34
|
+
@select = @backend.prepare("select v from #{@table} where k = ?"),
|
35
35
|
@replace = @backend.prepare("replace into #{@table} values (?, ?)"),
|
36
|
-
@delete
|
37
|
-
@clear
|
38
|
-
@create
|
39
|
-
@keys
|
40
|
-
@count
|
36
|
+
@delete = @backend.prepare("delete from #{@table} where k = ?"),
|
37
|
+
@clear = @backend.prepare("delete from #{@table}"),
|
38
|
+
@create = @backend.prepare("insert into #{@table} values (?, ?)"),
|
39
|
+
@keys = @backend.prepare("select k from #{@table}"),
|
40
|
+
@count = @backend.prepare("select count(*) from #{@table}")]
|
41
|
+
|
42
|
+
version = @backend.execute("select sqlite_version()").first.first
|
43
|
+
if @can_upsert = ::Gem::Version.new(version) >= ::Gem::Version.new('3.24.0')
|
44
|
+
@stmts << (@increment = @backend.prepare <<-SQL)
|
45
|
+
insert into #{@table} values (?, ?)
|
46
|
+
on conflict (k)
|
47
|
+
do update set v = cast(cast(v as integer) + ? as blob)
|
48
|
+
where v = '0' or v = X'30' or cast(v as integer) != 0
|
49
|
+
SQL
|
50
|
+
end
|
41
51
|
end
|
42
52
|
|
43
53
|
# (see Proxy#key?)
|
@@ -66,7 +76,11 @@ module Moneta
|
|
66
76
|
|
67
77
|
# (see Proxy#increment)
|
68
78
|
def increment(key, amount = 1, options = {})
|
69
|
-
@backend.transaction(:exclusive) { return super }
|
79
|
+
@backend.transaction(:exclusive) { return super } unless @can_upsert
|
80
|
+
@backend.transaction do
|
81
|
+
@increment.execute!(key, amount.to_s, amount)
|
82
|
+
return Integer(load(key))
|
83
|
+
end
|
70
84
|
end
|
71
85
|
|
72
86
|
# (see Proxy#clear)
|
@@ -77,7 +91,7 @@ module Moneta
|
|
77
91
|
|
78
92
|
# (see Default#create)
|
79
93
|
def create(key, value, options = {})
|
80
|
-
@create.execute!(key,value)
|
94
|
+
@create.execute!(key, value)
|
81
95
|
true
|
82
96
|
rescue SQLite3::ConstraintException
|
83
97
|
# If you know a better way to detect whether an insert-ignore
|
@@ -88,7 +102,7 @@ module Moneta
|
|
88
102
|
|
89
103
|
# (see Proxy#close)
|
90
104
|
def close
|
91
|
-
@stmts.each {|s| s.close }
|
105
|
+
@stmts.each { |s| s.close }
|
92
106
|
@backend.close
|
93
107
|
nil
|
94
108
|
end
|
@@ -120,7 +134,7 @@ module Moneta
|
|
120
134
|
|
121
135
|
# (see Proxy#merge!)
|
122
136
|
def merge!(pairs, options = {})
|
123
|
-
transaction =
|
137
|
+
transaction = @backend.transaction if block_given?
|
124
138
|
|
125
139
|
if block_given?
|
126
140
|
existing = Hash[slice(*pairs.map { |k, _| k }.to_a)]
|