135 lines
3.2 KiB
Ruby
135 lines
3.2 KiB
Ruby
require 'sequel'
|
|
|
|
module DataRepository
|
|
module Backend
|
|
class Sequel
|
|
PAGE = 1
|
|
PER_PAGE = 300
|
|
ARRAY_RE = %r{\[.*\]}
|
|
|
|
def initialize(db, relation=nil)
|
|
@db = db
|
|
@relation = relation.to_sym
|
|
::Sequel.extension(:pagination)
|
|
::Sequel.extension(:connection_validator)
|
|
@db.extension :pg_array if postgres?(@db)
|
|
end
|
|
|
|
def collection(filters={}, available_filters=[])
|
|
apply_filters(db[relation], filters, available_filters)
|
|
end
|
|
|
|
def store(key, data={})
|
|
naive_upsert_exposed_to_race_conditions(data)
|
|
end
|
|
|
|
def fetch(value, key=nil)
|
|
if key.nil?
|
|
parse( db[relation].where(id: value).first )
|
|
else
|
|
parse( db[relation].where(key.to_sym => value).first )
|
|
end
|
|
end
|
|
|
|
def delete(key)
|
|
db[relation].where(id: key).delete
|
|
end
|
|
|
|
def next_id
|
|
Carto::UUIDHelper.random_uuid
|
|
end
|
|
|
|
def apply_filters(dataset, filters={}, available_filters=[])
|
|
return dataset if filters.nil? || filters.empty?
|
|
available_filters = symbolize_elements(available_filters)
|
|
|
|
filters = symbolize_keys(filters).select { |key, value|
|
|
available_filters.include?(key)
|
|
} unless available_filters.empty?
|
|
|
|
dataset.where(filters)
|
|
end
|
|
|
|
def paginate(dataset, filter={}, record_count=nil)
|
|
page, per_page = pagination_params_from(filter)
|
|
dataset.paginate(page, per_page, record_count)
|
|
end
|
|
|
|
def transaction(&block)
|
|
db.transaction(&block)
|
|
end
|
|
|
|
private
|
|
|
|
attr_reader :relation, :db
|
|
|
|
def naive_upsert_exposed_to_race_conditions(data={})
|
|
data = send("serialize_for_#{backend_type}", data)
|
|
insert(data) unless update(data)
|
|
end
|
|
|
|
def insert(data={})
|
|
db[relation].insert(data)
|
|
end
|
|
|
|
def update(data={})
|
|
db[relation].where(id: data.fetch(:id)).update(data) != 0
|
|
end
|
|
|
|
def serialize_for_postgres(data)
|
|
Hash[
|
|
data.map { |key, value|
|
|
value = ::Sequel.pg_array(value) if value.is_a?(Array) && !value.empty?
|
|
[key, value]
|
|
}
|
|
]
|
|
end
|
|
|
|
def serialize_for_other_database(data={})
|
|
Hash[
|
|
data.map { |key, value|
|
|
value = value.to_s if value.is_a?(Array)
|
|
[key, value]
|
|
}
|
|
]
|
|
end
|
|
|
|
def backend_type
|
|
postgres?(db) ? :postgres : :other_database
|
|
end
|
|
|
|
def postgres?(db)
|
|
db.database_type == :postgres
|
|
end
|
|
|
|
def parse(attributes={})
|
|
return unless attributes
|
|
return attributes if postgres?(db)
|
|
|
|
Hash[
|
|
attributes.map do |key, value|
|
|
value = JSON.parse(value) if value =~ ARRAY_RE
|
|
[key, value]
|
|
end
|
|
]
|
|
end
|
|
|
|
def symbolize_elements(array=[])
|
|
array.map { |k| k.to_sym}
|
|
end
|
|
|
|
def symbolize_keys(hash={})
|
|
Hash[ hash.map { |k, v| [k.to_sym, v] } ]
|
|
end
|
|
|
|
def pagination_params_from(filter)
|
|
page = (filter.delete(:page) || PAGE).to_i
|
|
per_page = (filter.delete(:per_page) || PER_PAGE).to_i
|
|
|
|
[page, per_page]
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|