Module: Repertoire::Faceting::PostgreSQLAdapter

Includes:
MigrationMethods
Included in:
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
Defined in:
lib/repertoire-faceting/adapters/postgresql_adapter.rb

Overview

:nodoc:

Defined Under Namespace

Modules: MigrationMethods

Instance Method Summary collapse

Methods included from MigrationMethods

#create_materialized_view, #drop_materialized_view, #faceting_api_sql, #refresh_materialized_view

Instance Method Details

#current_facet_api_bindingObject

Returns the currently active faceting API binding (only when installed as an extension)



33
34
35
# File 'lib/repertoire-faceting/adapters/postgresql_adapter.rb', line 33

def current_facet_api_binding
  @current_api_binding ||= select_value "SELECT extname FROM pg_extension WHERE extname LIKE 'faceting%';"
end

#facet_api_bindingsObject

Returns the available in-database faceting APIs (only when installed as an extension)



28
29
30
# File 'lib/repertoire-faceting/adapters/postgresql_adapter.rb', line 28

def facet_api_bindings
  @api_bindings ||= select_values "SELECT name FROM pg_available_extensions WHERE name LIKE 'faceting%'"
end

#facet_schemaObject

Methods for access to facet indices



41
42
43
44
45
# File 'lib/repertoire-faceting/adapters/postgresql_adapter.rb', line 41

def facet_schema
  # TODO. Not clear how to get the schema associated with a PostgreSQL extension from the
  #       system tables. So we limit to loading into a schema named 'facet' for now.
  'facet'
end

#facet_table_name(model_name, name) ⇒ Object



47
48
49
# File 'lib/repertoire-faceting/adapters/postgresql_adapter.rb', line 47

def facet_table_name(model_name, name)
  "#{facet_schema}.#{model_name}_#{name}_index"
end

#indexed_facets(model_name) ⇒ Object



51
52
53
54
55
56
# File 'lib/repertoire-faceting/adapters/postgresql_adapter.rb', line 51

def indexed_facets(model_name)
  sql = "SELECT matviewname FROM pg_matviews WHERE schemaname = 'facet'"
  tables = select_values(sql)

  tables.grep(/#{model_name}_(\w+)_(\d*)?index/) { $1 }
end

#mask_members_sql(masks, table_name, faceting_id) ⇒ Object



100
101
102
103
104
# File 'lib/repertoire-faceting/adapters/postgresql_adapter.rb', line 100

def mask_members_sql(masks, table_name, faceting_id)
  bit_and = " OPERATOR(#{facet_schema}.&) "
  exprs = masks.map { |mask| "(#{mask.to_sql})" }
  "INNER JOIN #{facet_schema}.members(#{exprs.join(bit_and)}) AS _refinements_id ON (#{table_name}.#{faceting_id} = _refinements_id)"
end

#population(facet, masks, signatures) ⇒ Object

Methods for running facet value counts



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/repertoire-faceting/adapters/postgresql_adapter.rb', line 72

def population(facet, masks, signatures)
  # Would be nice to use Arel here... but recent versions (~ 2.0.1) have removed the property of closure under
  # composition (e.g. joining two select managers / sub-selects)... why?!?
  sigs  = [ 'fct.signature' ]
  exprs = masks.map{|mask| "(#{mask.to_sql})"}
  sigs << 'mask.signature' unless masks.empty?

  bit_and = " OPERATOR(#{facet_schema}.&) "

  sql  = "SELECT fct.#{facet.facet_name}, #{facet_schema}.count(#{ sigs.join(bit_and) }) "
  sql += "FROM (#{signatures.to_sql}) AS fct "
  sql += ", (SELECT (#{exprs.join(bit_and)}) AS signature) AS mask " unless masks.empty?
  sql += "ORDER BY #{facet.order_values.join(', ')} " if facet.order_values.present?
  sql += "OFFSET #{facet.offset_value} "              if facet.offset_value.present?
  sql += "LIMIT #{facet.limit_value} "                if facet.limit_value.present?

  # run query and type cast
  results = query(sql)
  results = results.map { |key, count| [ key, count.to_i] }
  results = ActiveSupport::OrderedHash[results]

  # minimums and nils
  results.reject! { |key, count| count < (facet.minimum_value || 1) }
  results.delete(nil)            if facet.nils_value == :exclude

  results
end

#signature_wastage(table_name, faceting_id) ⇒ Object

Methods for managing packed id columns on models



62
63
64
65
66
# File 'lib/repertoire-faceting/adapters/postgresql_adapter.rb', line 62

def signature_wastage(table_name, faceting_id)
  sql = "SELECT #{facet_schema}.wastage(#{faceting_id}) FROM #{table_name}"
  result = select_value(sql)
  Float(result)
end