Class: Superstore::Adapters::JsonbAdapter
Defined Under Namespace
Classes: QueryBuilder
Constant Summary
collapse
- PRIMARY_KEY_COLUMN =
'id'.freeze
- OJ_OPTIONS =
{mode: :compat}
- JSON_FUNCTIONS =
{
'jsonb_slice(data jsonb, keys text[])' => %{
SELECT json_object_agg(key, value)::jsonb
FROM (
SELECT * FROM jsonb_each(data)
) t
WHERE key =ANY(keys);
},
'jsonb_merge(data jsonb, merge_data jsonb)' => %{
SELECT json_object_agg(key, value)::jsonb
FROM (
WITH to_merge AS (
SELECT * FROM jsonb_each(merge_data)
)
SELECT *
FROM jsonb_each(data)
WHERE key NOT IN (SELECT key FROM to_merge)
UNION ALL
SELECT * FROM to_merge
) t;
},
'jsonb_delete(data jsonb, keys text[])' => %{
SELECT json_object_agg(key, value)::jsonb
FROM (
SELECT * FROM jsonb_each(data)
WHERE key <>ALL(keys)
) t;
},
}
Instance Attribute Summary
#config
Instance Method Summary
collapse
#batch, #batching?, #execute_batchable, #initialize
Instance Method Details
#active_record_klass ⇒ Object
99
100
101
|
# File 'lib/superstore/adapters/jsonb_adapter.rb', line 99
def active_record_klass
@active_record_klass ||= ActiveRecord::Base
end
|
#active_record_klass=(klass) ⇒ Object
95
96
97
|
# File 'lib/superstore/adapters/jsonb_adapter.rb', line 95
def active_record_klass=(klass)
@active_record_klass = klass
end
|
#connection ⇒ Object
91
92
93
|
# File 'lib/superstore/adapters/jsonb_adapter.rb', line 91
def connection
active_record_klass.connection
end
|
#create_ids_where_clause(ids) ⇒ Object
184
185
186
187
188
189
190
191
192
193
|
# File 'lib/superstore/adapters/jsonb_adapter.rb', line 184
def create_ids_where_clause(ids)
ids = ids.first if ids.is_a?(Array) && ids.one?
if ids.is_a?(Array)
id_list = ids.map { |id| quote(id) }.join(',')
"#{primary_key_column} IN (#{id_list})"
else
"#{primary_key_column} = #{quote(ids)}"
end
end
|
#create_table(table_name, options = {}) ⇒ Object
172
173
174
175
176
177
178
|
# File 'lib/superstore/adapters/jsonb_adapter.rb', line 172
def create_table(table_name, options = {})
ActiveRecord::Migration.create_table table_name, id: false do |t|
t.string :id, null: false
t.jsonb :document, null: false
end
connection.execute "ALTER TABLE \"#{table_name}\" ADD CONSTRAINT #{table_name}_pkey PRIMARY KEY (id)"
end
|
#define_jsonb_functions! ⇒ Object
243
244
245
246
247
248
249
250
251
252
253
254
255
|
# File 'lib/superstore/adapters/jsonb_adapter.rb', line 243
def define_jsonb_functions!
JSON_FUNCTIONS.each do |signature, body|
connection.execute %{
CREATE OR REPLACE FUNCTION public.#{signature}
RETURNS jsonb
IMMUTABLE
LANGUAGE sql
AS $$
#{body}
$$;
}
end
end
|
#delete(table, ids) ⇒ Object
160
161
162
163
164
|
# File 'lib/superstore/adapters/jsonb_adapter.rb', line 160
def delete(table, ids)
statement = "DELETE FROM #{table} WHERE #{create_ids_where_clause(ids)}"
execute_batchable statement
end
|
#drop_table(table_name) ⇒ Object
180
181
182
|
# File 'lib/superstore/adapters/jsonb_adapter.rb', line 180
def drop_table(table_name)
ActiveRecord::Migration.drop_table table_name
end
|
#execute(statement) ⇒ Object
103
104
105
|
# File 'lib/superstore/adapters/jsonb_adapter.rb', line 103
def execute(statement)
connection.execute statement
end
|
#execute_batch(statements) ⇒ Object
166
167
168
169
170
|
# File 'lib/superstore/adapters/jsonb_adapter.rb', line 166
def execute_batch(statements)
connection.transaction do
execute(statements * ";\n")
end
end
|
#fields_to_postgres_array(fields) ⇒ Object
199
200
201
202
|
# File 'lib/superstore/adapters/jsonb_adapter.rb', line 199
def fields_to_postgres_array(fields)
quoted_fields = fields.map { |field| quote(field) }.join(',')
"ARRAY[#{quoted_fields}]"
end
|
#insert(table, id, attributes) ⇒ Object
136
137
138
139
140
|
# File 'lib/superstore/adapters/jsonb_adapter.rb', line 136
def insert(table, id, attributes)
not_nil_attributes = attributes.reject { |key, value| value.nil? }
statement = "INSERT INTO #{table} (#{primary_key_column}, document) VALUES (#{quote(id)}, #{to_quoted_jsonb(not_nil_attributes)})"
execute_batchable statement
end
|
#primary_key_column ⇒ Object
87
88
89
|
# File 'lib/superstore/adapters/jsonb_adapter.rb', line 87
def primary_key_column
PRIMARY_KEY_COLUMN
end
|
#quote(value) ⇒ Object
195
196
197
|
# File 'lib/superstore/adapters/jsonb_adapter.rb', line 195
def quote(value)
connection.quote(value)
end
|
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
# File 'lib/superstore/adapters/jsonb_adapter.rb', line 120
def scroll(scope, batch_size)
statement = QueryBuilder.new(self, scope).to_query
cursor_name = "cursor_#{SecureRandom.hex(6)}"
fetch_sql = "FETCH FORWARD #{batch_size} FROM #{cursor_name}"
connection.transaction do
connection.execute "DECLARE #{cursor_name} NO SCROLL CURSOR FOR (#{statement})"
while (batch = connection.execute(fetch_sql)).any?
batch.each do |result|
yield result[primary_key_column], Oj.compat_load(result['document'])
end
end
end
end
|
#select(scope) ⇒ Object
112
113
114
115
116
117
118
|
# File 'lib/superstore/adapters/jsonb_adapter.rb', line 112
def select(scope)
statement = QueryBuilder.new(self, scope).to_query
connection.execute(statement).each do |result|
yield result[primary_key_column], Oj.compat_load(result['document'])
end
end
|
#to_ids(scope) ⇒ Object
107
108
109
110
|
# File 'lib/superstore/adapters/jsonb_adapter.rb', line 107
def to_ids(scope)
statement = QueryBuilder.new(self, scope.select('id')).to_query
connection.select_values(statement)
end
|
#to_quoted_jsonb(data) ⇒ Object
205
206
207
|
# File 'lib/superstore/adapters/jsonb_adapter.rb', line 205
def to_quoted_jsonb(data)
"#{quote(Oj.dump(data, OJ_OPTIONS))}::JSONB"
end
|
#update(table, id, attributes) ⇒ Object
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
|
# File 'lib/superstore/adapters/jsonb_adapter.rb', line 142
def update(table, id, attributes)
return if attributes.empty?
not_nil_attributes = attributes.reject { |key, value| value.nil? }
nil_attributes = attributes.select { |key, value| value.nil? }
if not_nil_attributes.any? && nil_attributes.any?
value_update = "jsonb_merge(jsonb_delete(document, #{fields_to_postgres_array(nil_attributes.keys)}), #{to_quoted_jsonb(not_nil_attributes)})"
elsif not_nil_attributes.any?
value_update = "jsonb_merge(document, #{to_quoted_jsonb(not_nil_attributes)})"
elsif nil_attributes.any?
value_update = "jsonb_delete(document, #{fields_to_postgres_array(nil_attributes.keys)})"
end
statement = "UPDATE #{table} SET document = #{value_update} WHERE #{primary_key_column} = #{quote(id)}"
execute_batchable statement
end
|