Module: Card::Query::Attributes

Included in:
Card::Query
Defined in:
lib/card/query/attributes.rb

Constant Summary collapse

SORT_JOIN_TO_ITEM_MAP =
{ left: 'left_id', right: 'right_id' }.freeze

Instance Method Summary collapse

Instance Method Details

#all(val) ⇒ Object Also known as: and

~~~~~~~ CONJUNCTION



266
267
268
# File 'lib/card/query/attributes.rb', line 266

def all val
  conjoin val, :and
end

#any(val) ⇒ Object Also known as: or, in



271
272
273
# File 'lib/card/query/attributes.rb', line 271

def any val
  conjoin val, :or
end

#complete(val) ⇒ Object



143
144
145
146
147
148
149
150
151
152
# File 'lib/card/query/attributes.rb', line 143

def complete val
  no_plus_card = (val =~ /\+/ ? '' : 'and right_id is null')
  # FIXME: -- this should really be more nuanced --
  # it breaks down after one plus

  add_condition(
    " lower(#{table_alias}.name) LIKE" \
    " lower(#{quote(val.to_s + '%')}) #{no_plus_card}"
  )
end

#conjoin(val, conj) ⇒ Object



277
278
279
280
281
282
283
284
285
# File 'lib/card/query/attributes.rb', line 277

def conjoin val, conj
  sq = subquery unjoined: true, conj: conj
  unless val.is_a? Array
    val = clause_to_hash(val).map { |key, value| { key => value } }
  end
  val.each do |val_item|
    sq.interpret val_item
  end
end

#conjunction(val) ⇒ Object



181
182
183
184
# File 'lib/card/query/attributes.rb', line 181

def conjunction val
  return unless [String, Symbol].member? val.class
  CONJUNCTIONS[val.to_sym]
end

#created_by(val) ⇒ Object



66
67
68
# File 'lib/card/query/attributes.rb', line 66

def created_by val
  restrict :creator_id, val
end

#creator_of(val) ⇒ Object



62
63
64
# File 'lib/card/query/attributes.rb', line 62

def creator_of val
  join_cards val, to_field: 'creator_id'
end

#edited_by(val) ⇒ Object



40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/card/query/attributes.rb', line 40

def edited_by val
  action_join = Join.new(
    from: self,
    to: ['card_actions', "an#{table_id true}", 'card_id']
  )
  joins << action_join
  act_join = Join.new(
    from: action_join,
    from_field: 'card_act_id',
    to: ['card_acts', "a#{table_id true}"]
  )
  join_cards val, from: act_join, from_field: 'actor_id'
end

#editor_of(val) ⇒ Object



26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/card/query/attributes.rb', line 26

def editor_of val
  act_join = Join.new(
    from: self,
    to: ['card_acts', "a#{table_id true}", 'actor_id']
  )
  joins << act_join
  action_join = Join.new(
    from: act_join,
    to: ['card_actions', "an#{table_id true}", 'card_act_id'],
    superjoin: act_join
  )
  join_cards val, from: action_join, from_field: 'card_id'
end

#extension_type(_val) ⇒ Object



154
155
156
157
158
# File 'lib/card/query/attributes.rb', line 154

def extension_type _val
  # DEPRECATED LONG AGO!!!
  Rails.logger.info 'using DEPRECATED extension_type in WQL'
  interpret right_plus: AccountID
end

#found_by(val) ⇒ Object

~~~~~~ SPECIAL



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/card/query/attributes.rb', line 100

def found_by val
  found_by_cards(val).compact.each do |c|
    if c && [SearchTypeID, SetID].include?(c.type_id)
      # FIXME: - move this check to set mods!

      subquery(
        c.get_query.merge unjoined: true, context: c.name
      )
    else
      raise BadQuery,
            '"found_by" value must be valid Search, ' \
            "but #{c.name} is a #{c.type_name}"
    end
  end
end

#found_by_cards(val) ⇒ Object



116
117
118
119
120
121
122
123
124
# File 'lib/card/query/attributes.rb', line 116

def found_by_cards val
  if val.is_a? Hash
    Query.run val
  else
    Array.wrap(val).map do |v|
      Card.fetch v.to_name.to_absolute(context), new: {}
    end
  end
end

#id_from_val(val) ⇒ Object



300
301
302
303
304
305
# File 'lib/card/query/attributes.rb', line 300

def id_from_val val
  case val
  when Integer then val
  when String  then Card.fetch_id(val)
  end
end

#join_cards(val, opts = {}) ⇒ Object



253
254
255
256
257
258
259
260
261
262
# File 'lib/card/query/attributes.rb', line 253

def join_cards val, opts={}
  conditions_on_join = opts.delete :conditions_on_join
  s = subquery
  join_opts = { from: self, to: s }.merge opts
  card_join = Join.new join_opts
  joins << card_join unless opts[:from].is_a? Join
  s.conditions_on_join = card_join if conditions_on_join
  s.interpret val
  s
end

#join_references(key, val) ⇒ Object

ATTRIBUTE HELPERS



162
163
164
165
166
167
168
169
170
# File 'lib/card/query/attributes.rb', line 162

def join_references key, val
  r = Reference.new(key, val, self)
  refjoin = Join.new(from: self, to: r, to_field: r.infield)
  joins << refjoin
  restrict_reference r, refjoin if r.cardquery
  r.conditions.each do |condition|
    refjoin.conditions << "#{r.table_alias}.#{condition}"
  end
end

#junction(val, side, to_field) ⇒ Object



92
93
94
95
96
# File 'lib/card/query/attributes.rb', line 92

def junction val, side, to_field
  part_clause, junction_clause = val.is_a?(Array) ? val : [val, {}]
  junction_val = clause_to_hash(junction_clause).merge side => part_clause
  join_cards junction_val, to_field: to_field
end

#last_edited_by(val) ⇒ Object



58
59
60
# File 'lib/card/query/attributes.rb', line 58

def last_edited_by val
  restrict :updater_id, val
end

#last_editor_of(val) ⇒ Object



54
55
56
# File 'lib/card/query/attributes.rb', line 54

def last_editor_of val
  join_cards val, to_field: 'updater_id'
end

#left(val) ⇒ Object



18
19
20
# File 'lib/card/query/attributes.rb', line 18

def left val
  restrict :left_id, val
end

#left_plus(val) ⇒ Object

~~~~~~ PLUS RELATIONAL



80
81
82
# File 'lib/card/query/attributes.rb', line 80

def left_plus val
  junction val, :left, :right_id
end

#match(val) ⇒ Object



126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/card/query/attributes.rb', line 126

def match val
  cxn, val = match_prep val
  val.gsub! /[^#{Card::Name::OK4KEY_RE}]+/, ' '
  return nil if val.strip.empty?

  val_list = val.split(/\s+/).map do |v|
    name_or_content = [
      "replace(#{table_alias}.name,'+',' ')",
      "#{table_alias}.db_content"
    ].map do |field|
      %(#{field} #{cxn.match quote("[[:<:]]#{v}[[:>:]]")})
    end
    "(#{name_or_content.join ' OR '})"
  end
  add_condition "(#{val_list.join ' AND '})"
end

#member(val) ⇒ Object



74
75
76
# File 'lib/card/query/attributes.rb', line 74

def member val
  interpret referred_to_by: { left: val, right: RolesID }
end

#member_of(val) ⇒ Object



70
71
72
# File 'lib/card/query/attributes.rb', line 70

def member_of val
  interpret right_plus: [RolesID, refer_to: val]
end

#not(val) ⇒ Object



287
288
289
290
# File 'lib/card/query/attributes.rb', line 287

def not val
  notjoin = join_cards val, conditions_on_join: true, side: 'LEFT'
  add_condition "#{notjoin.table_alias}.id is null"
end

#part(val) ⇒ Object



13
14
15
16
# File 'lib/card/query/attributes.rb', line 13

def part val
  right_val = val.is_a?(Integer) ? val : val.clone
  any(left: val, right: right_val)
end

#plus(val) ⇒ Object



88
89
90
# File 'lib/card/query/attributes.rb', line 88

def plus val
  any(left_plus: val, right_plus: val.deep_clone)
end

#restrict(id_field, val) ⇒ Object



292
293
294
295
296
297
298
# File 'lib/card/query/attributes.rb', line 292

def restrict id_field, val
  if (id = id_from_val(val))
    interpret id_field => id
  else
    join_cards val, from_field: id_field
  end
end

#restrict_reference(ref, refjoin) ⇒ Object



172
173
174
175
176
177
178
179
# File 'lib/card/query/attributes.rb', line 172

def restrict_reference ref, refjoin
  val = ref.cardquery
  if (id = id_from_val(val))
    add_condition "#{ref.table_alias}.#{ref.outfield} = #{id}"
  else
    join_cards val, from: refjoin, from_field: ref.outfield
  end
end

#right(val) ⇒ Object



22
23
24
# File 'lib/card/query/attributes.rb', line 22

def right val
  restrict :right_id, val
end

#right_plus(val) ⇒ Object



84
85
86
# File 'lib/card/query/attributes.rb', line 84

def right_plus val
  junction val, :right, :left_id
end

#sort(val) ⇒ Object



186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
# File 'lib/card/query/attributes.rb', line 186

def sort val
  return nil if @superquery
  sort_field = val[:return] || 'db_content'
  item = val.delete(:item) || 'left'

  if sort_field == 'count'
    sort_by_count val, item
  elsif (join_field = SORT_JOIN_TO_ITEM_MAP[item.to_sym])
    sq = join_cards(val, to_field: join_field,
                         side: 'LEFT',
                         conditions_on_join: true)
    @mods[:sort] ||= "#{sq.table_alias}.#{sort_field}"
  else
    raise BadQuery, "sort item: #{item} not yet implemented"
  end
end

#sort_by_count(val, item) ⇒ Object

EXPERIMENTAL!



204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
# File 'lib/card/query/attributes.rb', line 204

def sort_by_count val, item
  if item == 'referred_to'
    @mods[:sort] = 'coalesce(count,0)' # needed for postgres
    cs = Query.new(
      return: 'coalesce(count(*), 0) as count',
      group: 'sort_join_field',
      superquery: self
    )
    subselect = Query.new val.merge(return: 'id', superquery: self)
    cs.add_condition "referer_id in (#{subselect.sql})"
    # FIXME: - SQL generated before SQL phase
    cs.joins << Join.new(
      from: cs,
      to: %w(card_references wr referee_id)
    )
    cs.mods[:sort_join_field] = "#{cs.table_alias}.id as sort_join_field"
    # HACK!

    joins << Join.new(
      from: self,
      to: [cs, 'srtbl', 'sort_join_field']
    )
  else
    raise BadQuery, "count with item: #{item} not yet implemented"
  end
end

#table_aliasObject



231
232
233
234
235
236
237
238
239
# File 'lib/card/query/attributes.rb', line 231

def table_alias
  @table_alias ||= begin
    if @unjoined
      @superquery.table_alias
    else
      "c#{table_id}"
    end
  end
end

#table_id(force = false) ⇒ Object



241
242
243
244
245
246
247
# File 'lib/card/query/attributes.rb', line 241

def table_id force=false
  if force
    tick_table_seq!
  else
    @table_id ||= tick_table_seq!
  end
end

#tick_table_seq!Object



249
250
251
# File 'lib/card/query/attributes.rb', line 249

def tick_table_seq!
  root.table_seq = root.table_seq.to_i + 1
end

#type(val) ⇒ Object

~~~~~~ RELATIONAL



9
10
11
# File 'lib/card/query/attributes.rb', line 9

def type val
  restrict :type_id, val
end