lib/rodbot/db.rb
# frozen_string_literal: true
require 'json'
using Rodbot::Refinements
module Rodbot
# Uniform key/value database interface for various backends
#
# Keys can be namespaced using the colon as separator:
#
# * 'color' - color key without namespace
# * 'bike:color' - color key within the bike namespace
# * 'vehicle:bike:color' - color key within... you get the idea
#
# Furthermore, keys can be entered either as colon separated keys or as
# list of symbols. The following are therefore equivalent:
#
# Rodbot.db.get('vehicle:bike:color')
# Rodbot.db.get(:vehicle, :bike, :color)
#
# Same goes for the star wildcard which is only allowed last:
#
# Rodbot.db.scan('vehicle:*')
# Rodbot.db.scan(:vehicle, :*)
#
# The interface is simple and straightforward:
#
# @example Set a value
# Rodbot.db.set(:name) { 'John' }
#
# @example Set a value which expires after 30 seconds
# Rodbot.db.set(:name, expires_in: 30) { 'John' }
#
# @example Replace an existing value
# Rodbot.db.set(:name) { 'John' }
# Rodbot.db.set(:name) { 'Bob' } # replaces John with Bob
#
# @example Update an existing value
# Rodbot.db.set(:name) { 'John' }
# Rodbot.db.set(:name) { |n| "#{n} Doe" } # replaces John with John Doe
#
# @example Get a value
# Rodbot.db.set(:name) { 'John' }
# Rodbot.db.get(:name) # => 'John'
#
# @example Delete a value
# Rodbot.db.set(:name) { 'John' }
# Rodbot.db.delete(:name) # => 'John'
# Rodbot.db.get(:name) # => nil
#
# @example Scan for keys
# Rodbot.db.set(:first_name) { 'John' }
# Rodbot.db.set(:last_name) { 'Doe' }
# Rodbot.db.scan(:*) # => [:first_name, :last_name]
#
# @example Delete all keys
# Rodbot.db.flush
#
# Please note that {JSON} is used to serialize which has an influence on
# what you get back after deserialization:
#
# * Primitive types such as String, Integer or TrueClass are preserved.
# * Any other object is converted to String, incuding...
# * Symbol values are converted to String
# * Symbol elements in an array are converted to String
# * Symbol values in a hash are converted to String
#
# However, hash keys are always converted to Symbol - mainly because Rubyland
# favours Symbol keys over String keys for visual reasons.
class Db
attr_reader :url
# @param url [String] connection URL of the backend
def initialize(url)
@url = url
extend "rodbot/db/#{url.split('://').first}".constantize
end
private
def serialize(object)
object.to_json
end
def deserialize(string)
JSON.parse(string, symbolize_names: true) if string
end
end
end