lib/github/kv.rb in github-ds-0.2.10 vs lib/github/kv.rb in github-ds-0.2.11
- old
+ new
@@ -49,12 +49,28 @@
ValueLengthError = Class.new(StandardError)
UnavailableError = Class.new(StandardError)
class MissingConnectionError < StandardError; end
- def initialize(encapsulated_errors = [SystemCallError], &conn_block)
+ attr_accessor :use_local_time
+
+ # initialize :: [Exception], Boolean, Proc -> nil
+ #
+ # Initialize a new KV instance.
+ #
+ # encapsulated_errors - An Array of Exception subclasses that, when raised,
+ # will be replaced with UnavailableError.
+ # use_local_time: - Whether to use Ruby's `Time.now` instaed of MySQL's
+ # `NOW()` function. This is mostly useful in testing
+ # where time needs to be modified (eg. Timecop).
+ # Default false.
+ # &conn_block - A block to call to open a new database connection.
+ #
+ # Returns nothing.
+ def initialize(encapsulated_errors = [SystemCallError], use_local_time: false, &conn_block)
@encapsulated_errors = encapsulated_errors
+ @use_local_time = use_local_time
@conn_block = conn_block
end
def connection
@conn_block.try(:call) || (raise MissingConnectionError, "KV must be initialized with a block that returns a connection")
@@ -91,12 +107,12 @@
#
def mget(keys)
validate_key_array(keys)
Result.new {
- kvs = GitHub::SQL.results(<<-SQL, :keys => keys, :connection => connection).to_h
- SELECT `key`, value FROM key_values WHERE `key` IN :keys AND (`expires_at` IS NULL OR `expires_at` > NOW())
+ kvs = GitHub::SQL.results(<<-SQL, :keys => keys, :now => now, :connection => connection).to_h
+ SELECT `key`, value FROM key_values WHERE `key` IN :keys AND (`expires_at` IS NULL OR `expires_at` > :now)
SQL
keys.map { |key| kvs[key] }
}
end
@@ -135,11 +151,11 @@
validate_key_value_hash(kvs)
validate_expires(expires) if expires
rows = kvs.map { |key, value|
value = value.is_a?(GitHub::SQL::Literal) ? value : GitHub::SQL::BINARY(value)
- [key, value, GitHub::SQL::NOW, GitHub::SQL::NOW, expires || GitHub::SQL::NULL]
+ [key, value, now, now, expires || GitHub::SQL::NULL]
}
encapsulate_error do
GitHub::SQL.run(<<-SQL, :rows => GitHub::SQL::ROWS(rows), :connection => connection)
INSERT INTO key_values (`key`, value, created_at, updated_at, expires_at)
@@ -184,12 +200,12 @@
#
def mexists(keys)
validate_key_array(keys)
Result.new {
- existing_keys = GitHub::SQL.values(<<-SQL, :keys => keys, :connection => connection).to_set
- SELECT `key` FROM key_values WHERE `key` IN :keys AND (`expires_at` IS NULL OR `expires_at` > NOW())
+ existing_keys = GitHub::SQL.values(<<-SQL, :keys => keys, :now => now, :connection => connection).to_set
+ SELECT `key` FROM key_values WHERE `key` IN :keys AND (`expires_at` IS NULL OR `expires_at` > :now)
SQL
keys.map { |key| existing_keys.include?(key) }
}
end
@@ -220,18 +236,18 @@
encapsulate_error {
# if the key already exists but has expired, prune it first. We could
# achieve the same thing with the right INSERT ... ON DUPLICATE KEY UPDATE
# query, but then we would not be able to rely on affected_rows
- GitHub::SQL.run(<<-SQL, :key => key, :connection => connection)
- DELETE FROM key_values WHERE `key` = :key AND expires_at <= NOW()
+ GitHub::SQL.run(<<-SQL, :key => key, :now => now, :connection => connection)
+ DELETE FROM key_values WHERE `key` = :key AND expires_at <= :now
SQL
value = value.is_a?(GitHub::SQL::Literal) ? value : GitHub::SQL::BINARY(value)
- sql = GitHub::SQL.run(<<-SQL, :key => key, :value => value, :expires => expires || GitHub::SQL::NULL, :connection => connection)
+ sql = GitHub::SQL.run(<<-SQL, :key => key, :value => value, :now => now, :expires => expires || GitHub::SQL::NULL, :connection => connection)
INSERT IGNORE INTO key_values (`key`, value, created_at, updated_at, expires_at)
- VALUES (:key, :value, NOW(), NOW(), :expires)
+ VALUES (:key, :value, :now, :now, :expires)
SQL
sql.affected_rows > 0
}
end
@@ -286,17 +302,21 @@
#
def ttl(key)
validate_key(key)
Result.new {
- GitHub::SQL.value(<<-SQL, :key => key, :connection => connection)
+ GitHub::SQL.value(<<-SQL, :key => key, :now => now, :connection => connection)
SELECT expires_at FROM key_values
- WHERE `key` = :key AND (expires_at IS NULL OR expires_at > NOW())
+ WHERE `key` = :key AND (expires_at IS NULL OR expires_at > :now)
SQL
}
end
private
+ def now
+ use_local_time ? Time.now : GitHub::SQL::NOW
+ end
+
def validate_key(key, error_message: nil)
unless key.is_a?(String)
raise TypeError, error_message || "key must be a String in #{self.class.name}, but was #{key.class}"
end