Class: Praxis::Mapper::Query::Base

Inherits:
Object
  • Object
show all
Defined in:
lib/praxis-mapper/query/base.rb

Overview

Abstract base class for assembling read queries for a data store. May be implemented for SQL, CQL, etc. Collects query statistics.

See Also:

  • lib/support/memory_querylib/support/memory_query.rb

Direct Known Subclasses

Sequel, Sql, Support::MemoryQuery

Constant Summary collapse

MULTI_GET_BATCH_SIZE =
4_096

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(identity_map, model, &block) ⇒ Base

Sets up a read query.

Parameters:



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/praxis-mapper/query/base.rb', line 20

def initialize(identity_map, model, &block)

  @identity_map = identity_map
  @model = model

  @select = nil

  @where = nil

  @limit = nil
  @track = Set.new
  @load = Set.new
  @contexts = Set.new

  @statistics = Hash.new(0) # general-purpose hash

  if (selector = identity_map.selectors[model])
    self.apply_selector(selector)
  end

  if block_given?
    self.instance_eval(&block)
  end

end

Instance Attribute Details

#contextsObject (readonly)

Returns the value of attribute contexts.



12
13
14
# File 'lib/praxis-mapper/query/base.rb', line 12

def contexts
  @contexts
end

#identity_mapObject (readonly)

Returns the value of attribute identity_map.



12
13
14
# File 'lib/praxis-mapper/query/base.rb', line 12

def identity_map
  @identity_map
end

#modelObject (readonly)

Returns the value of attribute model.



12
13
14
# File 'lib/praxis-mapper/query/base.rb', line 12

def model
  @model
end

#statisticsObject (readonly)

Returns the value of attribute statistics.



12
13
14
# File 'lib/praxis-mapper/query/base.rb', line 12

def statistics
  @statistics
end

#where(value = nil) ⇒ Object

Gets or sets an SQL-like ‘WHERE’ clause to this query.

Examples:

where(“deployment_id=2”)

Parameters:

  • value (String) (defaults to: nil)

    a ‘WHERE’ clause



112
113
114
115
116
117
118
# File 'lib/praxis-mapper/query/base.rb', line 112

def where(value=nil)
  if value
    @where = value
  else
    return @where
  end
end

Instance Method Details

#_executeObject

Subclasses Must Implement



242
243
244
# File 'lib/praxis-mapper/query/base.rb', line 242

def _execute
  raise "subclass responsibility"
end

#_multi_get(identity, values) ⇒ Object

Subclasses Must Implement



237
238
239
# File 'lib/praxis-mapper/query/base.rb', line 237

def _multi_get(identity, values)
  raise "subclass responsibility"
end

#apply_selector(selector) ⇒ Object



46
47
48
49
50
51
52
53
54
# File 'lib/praxis-mapper/query/base.rb', line 46

def apply_selector(selector)
  if selector[:select]
    self.select(*selector[:select])
  end

  if selector[:track]
    self.track(*selector[:track])
  end
end

#connectionObject

Returns handle to configured data store.

Returns:

  • handle to configured data store



57
58
59
# File 'lib/praxis-mapper/query/base.rb', line 57

def connection
  identity_map.connection(model.repository_name)
end

#context(name = nil) ⇒ Object



161
162
163
164
165
166
167
168
169
# File 'lib/praxis-mapper/query/base.rb', line 161

def context(name=nil)
  @contexts << name
  spec = model.contexts.fetch(name) do
    raise "context #{name.inspect} not found for #{model}"
  end

  select(*spec[:select])
  track(*spec[:track])
end

#default_selectObject



97
98
99
100
101
102
103
104
105
# File 'lib/praxis-mapper/query/base.rb', line 97

def default_select
  model.identities.each_with_object({}).each do |identity, hash|
    if identity.is_a? Array
      identity.each { |id| hash[id] = nil }
    else
      hash[identity] = nil
    end
  end
end

#describeObject

Subclasses Must Implement the sql or “sql-like” representation of the query



248
249
250
# File 'lib/praxis-mapper/query/base.rb', line 248

def describe
  raise "subclass responsibility"
end

#executeArray

Executes assembled read query and returns all matching records.

Returns:

  • (Array)

    list of matching records, wrapped as models



216
217
218
219
220
221
222
223
224
225
226
# File 'lib/praxis-mapper/query/base.rb', line 216

def execute
  if self.frozen?
    raise TypeError.new "can not reuse a frozen query"
  end
  statistics[:execute] += 1

  rows = _execute

  statistics[:records_loaded] += rows.size
  to_records(rows)
end

#limit(value = nil) ⇒ Object

Gets or sets an SQL-like ‘LIMIT’ clause to this query.

Examples:

limit(“LIMIT 10 OFFSET 20”)

Parameters:

  • value (String) (defaults to: nil)

    a ‘LIMIT’ clause



125
126
127
128
129
130
131
# File 'lib/praxis-mapper/query/base.rb', line 125

def limit(value=nil)
  if value
    @limit = value
  else
    return @limit
  end
end

#load(*values, &block) ⇒ Object

Parameters:

  • *values (Array)

    a list of associations to load immediately after this



148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/praxis-mapper/query/base.rb', line 148

def load(*values, &block)
  if values.any?
    if block_given?
      raise "block and multiple values not supported" if values.size > 1
      @load << [values.first, block]
    else
      @load.merge(values)
    end
  else
    return @load
  end
end

#multi_get(identity, values, select: nil, raw: false) ⇒ Array

Executes multi-get read query and returns all matching records.

Parameters:

  • identity (Symbol|Array)

    a simple or composite key for this model

  • values (Array)

    list of identifier values (ideally a sorted set)

  • select (Array) (defaults to: nil)

    list of field names to select

  • raw (Boolean) (defaults to: false)

    return raw hashes instead of models (default false)

Returns:

  • (Array)

    list of matching records, wrapped as models



188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# File 'lib/praxis-mapper/query/base.rb', line 188

def multi_get(identity, values, select: nil, raw: false)
  if self.frozen?
    raise TypeError.new "can not reuse a frozen query"
  end

  statistics[:multi_get] += 1

  rows = []

  original_select = @select
  self.select(*select.flatten.uniq) if select

  values.each_slice(MULTI_GET_BATCH_SIZE) do |batch|
    rows += _multi_get(identity, batch)
  end

  statistics[:records_loaded] += rows.size

  return rows if raw
  to_records(rows)
ensure
  @select = original_select unless self.frozen?
end

#select(*fields) ⇒ Hash

Gets or sets an SQL-like ‘SELECT’ clause to this query. TODO: fix any specs or code that uses alias

Examples:

select(:account_id, “user_id”, => :created_at)

Parameters:

  • *fields (Array)

    list of fields, of type Symbol, String, or Hash

Returns:

  • (Hash)

    current list of fields



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/praxis-mapper/query/base.rb', line 68

def select(*fields)
  if fields.any?
    return @select if @select == true

    if @select.nil?
      @select = default_select
    end
    fields.each do |field|
      case field
      when Symbol, String
        if field == :* || field == "*"
          @select = true
          break
        else
          @select[field] = nil
        end
      when Hash
        field.each do |alias_name, column_name|
          @select[alias_name] = column_name
        end
      else
        raise "unknown field type: #{field.class.name}"
      end
    end
  else
    return @select
  end
end

#to_records(rows) ⇒ Object



228
229
230
231
232
233
234
# File 'lib/praxis-mapper/query/base.rb', line 228

def to_records(rows)
  rows.collect do |row|
    m = model.new(row)
    m._query = self
    m
  end
end

#track(*values, &block) ⇒ Object

Parameters:

  • *values (Array)

    a list of associations to track



134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/praxis-mapper/query/base.rb', line 134

def track(*values, &block)
  if values.any?
    if block_given?
      raise "block and multiple values not supported" if values.size > 1
      @track << [values.first, block]
    else
      @track.merge(values)
    end
  else
    return @track
  end
end

#tracked_associationsArray

Returns a list of associated models.

Returns:

  • (Array)

    a list of associated models



173
174
175
176
177
178
179
# File 'lib/praxis-mapper/query/base.rb', line 173

def tracked_associations
  track.collect do |(name, _)|
    model.associations.fetch(name) do
      raise "association #{name.inspect} not found for #{model}"
    end
  end.uniq
end