class WCC::Contentful::Store::PostgresStore::Query
Public Instance Methods
count()
click to toggle source
# File lib/wcc/contentful/store/postgres_store.rb, line 150 def count return @count if @count statement, params = finalize_statement('SELECT count(*)') result = store.exec_query(statement, params) @count = result.getvalue(0, 0).to_i end
first()
click to toggle source
# File lib/wcc/contentful/store/postgres_store.rb, line 158 def first return @first if @first statement, params = finalize_statement('SELECT t.*', ' LIMIT 1', depth: @options[:include]) result = store.exec_query(statement, params) return if result.num_tuples == 0 row = result.first entry = JSON.parse(row['data']) if @options[:include] && @options[:include] > 0 includes = decode_includes(row['includes']) entry = resolve_includes([entry, includes], @options[:include]) end entry end
result_set()
click to toggle source
# File lib/wcc/contentful/store/postgres_store.rb, line 175 def result_set return @result_set if @result_set statement, params = finalize_statement('SELECT t.*', depth: @options[:include]) @result_set = store.exec_query(statement, params) .lazy.map do |row| entry = JSON.parse(row['data']) includes = (decode_includes(row['includes']) if @options[:include] && @options[:include] > 0) [entry, includes] end rescue PG::ConnectionBad [] end
Private Instance Methods
_eq(path, expected, params)
click to toggle source
# File lib/wcc/contentful/store/postgres_store.rb, line 243 def _eq(path, expected, params) return " AND t.id = $#{push_param(expected, params)}" if path == %w[sys id] if path[3] == 'sys' # the path can be either an array or a singular json obj, and we have to dig # into it to detect whether it contains `{ "sys": { "id" => expected } }` expected = { 'sys' => { path[4] => expected } }.to_json return ' AND fn_contentful_jsonb_any_to_jsonb_array(t.data->' \ "#{quote_parameter_path(path.take(3))}) @> " \ "jsonb_build_array($#{push_param(expected, params)}::jsonb)" end " AND t.data->#{quote_parameter_path(path)}" \ " ? $#{push_param(expected, params)}::text" end
_join(join_path, expectation_path, expected, params, joins)
click to toggle source
# File lib/wcc/contentful/store/postgres_store.rb, line 268 def _join(join_path, expectation_path, expected, params, joins) # join back to the table using the links column (join_table_alias becomes s0, s1, s2) # this is faster because of the index join_table_alias = push_join(join_path, joins) # then apply the where clauses: # 1. that the joined entry has the data at the appropriate path # 2. that the entry joining to the other entry actually links at this path and not another <<~WHERE_CLAUSE AND #{join_table_alias}.data->#{quote_parameter_path(expectation_path)} ? $#{push_param(expected, params)}::text AND exists (select 1 from jsonb_array_elements(fn_contentful_jsonb_any_to_jsonb_array(t.data->#{quote_parameter_path(join_path)})) as link where link->'sys'->'id' ? #{join_table_alias}.id) WHERE_CLAUSE end
decode_includes(includes)
click to toggle source
# File lib/wcc/contentful/store/postgres_store.rb, line 194 def decode_includes(includes) return {} unless includes decoder = PG::TextDecoder::Array.new decoder.decode(includes) .map { |e| JSON.parse(e) } .each_with_object({}) do |entry, h| h[entry.dig('sys', 'id')] = entry end end
finalize_statement(select_statement, limit_statement = nil, depth: nil)
click to toggle source
# File lib/wcc/contentful/store/postgres_store.rb, line 205 def finalize_statement(select_statement, limit_statement = nil, depth: nil) statement = if content_type == 'Asset' "WHERE t.data->'sys'->>'type' = $1" else "WHERE t.data->'sys'->'contentType'->'sys'->>'id' = $1" end params = [content_type] joins = [] statement = conditions.reduce(statement) do |memo, condition| raise ArgumentError, "Operator #{condition.op} not supported" unless condition.op == :eq if condition.path_tuples.length == 1 memo + _eq(condition.path, condition.expected, params) else join_path, expectation_path = condition.path_tuples memo + _join(join_path, expectation_path, condition.expected, params, joins) end end table = 'contentful_raw' if depth && depth > 0 table = 'contentful_raw_includes' select_statement += ', t.includes' end statement = select_statement + " FROM #{table} AS t \n" + joins.join("\n") + "\n" + statement + (limit_statement || '') [statement, params] end
push_join(_path, joins)
click to toggle source
# File lib/wcc/contentful/store/postgres_store.rb, line 282 def push_join(_path, joins) table_alias = "s#{joins.length}" joins << "JOIN contentful_raw AS #{table_alias} ON " \ "#{table_alias}.id=ANY(t.links)" table_alias end
push_param(param, params)
click to toggle source
# File lib/wcc/contentful/store/postgres_store.rb, line 259 def push_param(param, params) params << param params.length end
quote_parameter_path(path)
click to toggle source
# File lib/wcc/contentful/store/postgres_store.rb, line 264 def quote_parameter_path(path) path.map { |p| "'#{p}'" }.join('->') end