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' }

Instance Method Summary collapse

Instance Method Details

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

~~~~~~~ CONJUNCTION



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

def all val
  conjoin val, :and
end

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



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

def any val
  conjoin val, :or
end

#complete(val) ⇒ Object



146
147
148
149
150
151
152
153
154
# File 'lib/card/query/attributes.rb', line 146

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(name) LIKE lower(#{quote(val.to_s+'%')}) #{no_plus_card}"
  )
end

#conjoin(val, conj) ⇒ Object



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

def conjoin val, conj
  sq = subquery( unjoined: true, conj: conj )
  unless Array===val
    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



178
179
180
181
# File 'lib/card/query/attributes.rb', line 178

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 force=true}", 'card_id']
  )
  joins << action_join
  act_join = Join.new(
    from: action_join,
    from_field: 'card_act_id',
    to: ['card_acts', "a#{table_id force=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 force=true}", 'actor_id']
  )
  joins << act_join
  action_join = Join.new(
    from: act_join,
    to: ['card_actions', "an#{table_id force=true}", 'card_act_id'],
    superjoin: act_join
  )
  join_cards val, from: action_join, from_field: 'card_id'
end

#extension_type(val) ⇒ Object



156
157
158
159
160
# File 'lib/card/query/attributes.rb', line 156

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



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

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

end

#id_from_val(val) ⇒ Object



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

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

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



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

def join_cards val, opts={}
  conditions_on_join = opts.delete :conditions_on_join
  s = subquery
  card_join = Join.new({ from: self, to: s }.merge 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



166
167
168
169
170
171
172
173
174
175
176
# File 'lib/card/query/attributes.rb', line 166

def join_references key, val
  r = Reference.new( key, val, self )
  refjoin = Join.new(:from=>self, :to=>r, :to_field=>r.infield)
  joins << refjoin
  if r.cardquery
    join_cards r.cardquery, from: refjoin, from_field: r.outfield
  end
  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



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

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(#{self.table_alias}.name,'+',' ')",
      "#{self.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



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

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



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

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

#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



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

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
  else
    if 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

end

#sort_by_count(val, item) ⇒ Object

EXPERIMENTAL!



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
230
# File 'lib/card/query/attributes.rb', line 205

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:['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



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

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

#table_id(force = false) ⇒ Object



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

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

#tick_table_seq!Object



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

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