cartodb/services/data-repository/backend/sequel.rb
2020-06-15 10:58:47 +08:00

136 lines
3.2 KiB
Ruby

require 'sequel'
require 'uuidtools'
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
UUIDTools::UUID.timestamp_create
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