lib/trifle/stats/driver/postgres.rb in trifle-stats-1.2.0 vs lib/trifle/stats/driver/postgres.rb in trifle-stats-1.3.0

- old
+ new

@@ -14,58 +14,71 @@ @client = client @table_name = table_name @separator = '::' end - def inc(keys:, **values) - keys.map do |key| - pkey = key.join(separator) + def self.setup!(client = PG::Connection.new, table_name: 'trifle_stats') + client.exec("CREATE TABLE #{table_name} (key VARCHAR(255) PRIMARY KEY, data JSONB NOT NULL DEFAULT '{}'::jsonb)") # rubocop:disable Layout/LineLength + end - _inc_all(key: pkey, data: self.class.pack(hash: values)) + def inc(keys:, **values) + data = self.class.pack(hash: values) + client.transaction do |c| + keys.map do |key| + pkey = key.join(separator) + c.exec(inc_query(key: pkey, data: data)) + end end end - def _inc_all(key:, data:) - query = "INSERT INTO trifle_stats(key, data) VALUES ('#{key}', '#{data.to_json}') ON CONFLICT (key) DO UPDATE SET data = " + # rubocop:disable Layout/LineLength - data.inject('to_jsonb(trifle_stats.data)') { |o, (k, v)| "jsonb_set(#{o}, '{#{k}}', (COALESCE(trifle_stats.data->>'#{k}', '0')::int + #{v})::text::jsonb)" } # rubocop:disable Layout/LineLength - - client.exec(query) + def inc_query(key:, data:) + <<-SQL + INSERT INTO #{table_name} (key, data) VALUES ('#{key}', '#{data.to_json}') + ON CONFLICT (key) DO UPDATE SET data = + #{data.inject("to_jsonb(#{table_name}.data)") { |o, (k, v)| "jsonb_set(#{o}, '{#{k}}', (COALESCE(trifle_stats.data->>'#{k}', '0')::int + #{v})::text::jsonb)" }}; + SQL end def set(keys:, **values) - keys.map do |key| - pkey = key.join(separator) - - _set_all(key: pkey, data: self.class.pack(hash: values)) + data = self.class.pack(hash: values) + client.transaction do |c| + keys.map do |key| + pkey = key.join(separator) + c.exec(set_query(key: pkey, data: data)) + end end end - def _set_all(key:, data:) - query = "INSERT INTO trifle_stats(key, data) VALUES ('#{key}', '#{data.to_json}') ON CONFLICT (key) DO UPDATE SET data = " + # rubocop:disable Layout/LineLength - data.inject('to_jsonb(trifle_stats.data)') { |o, (k, v)| "jsonb_set(#{o}, '{#{k}}', (#{v})::text::jsonb)" } # rubocop:disable Layout/LineLength - - client.exec(query) + def set_query(key:, data:) + <<-SQL + INSERT INTO #{table_name} (key, data) VALUES ('#{key}', '#{data.to_json}') + ON CONFLICT (key) DO UPDATE SET data = + #{data.inject("to_jsonb(#{table_name}.data)") { |o, (k, v)| "jsonb_set(#{o}, '{#{k}}', (#{v})::text::jsonb)" }} + SQL end def get(keys:) pkeys = keys.map { |key| key.join(separator) } - data = _get_all(keys: pkeys) - map = data.inject({}) { |o, d| o.merge(d['key'] => d['data']) } + data = get_all(keys: pkeys) + map = data.inject({}) { |o, d| o.merge(d[:key] => d[:data]) } - pkeys.map { |pkey| self.class.unpack(hash: map[pkey]) || {} } + pkeys.map { |pkey| self.class.unpack(hash: map.fetch(pkey, {})) } end - def _get_all(keys:) - results = client.exec_params( - "SELECT * FROM #{table_name} WHERE key IN ('#{keys.join("', '")}');" - ).to_a + def get_all(keys:) + results = client.exec_params(get_query(keys: keys)).to_a results.map do |r| - r['data'] = JSON.parse(r['data']) - r + { key: r['key'], data: JSON.parse(r['data']) } rescue JSON::ParserError - r + { key: r['key'], data: {} } end + end + + def get_query(keys:) + <<-SQL + SELECT * FROM #{table_name} WHERE key IN ('#{keys.join("', '")}'); + SQL end end end end end