Class: Card::Query

Inherits:
Object
  • Object
show all
Includes:
Attributes, Clause, Conjunctions, Helpers, Interpretation, RelationalAttributes, Sorting
Defined in:
lib/card/query.rb,
lib/card/query/join.rb,
lib/card/query/value.rb,
lib/card/query/helpers.rb,
lib/card/query/sorting.rb,
lib/card/query/reference.rb,
lib/card/query/attributes.rb,
lib/card/query/conjunctions.rb,
lib/card/query/sql_statement.rb,
lib/card/query/interpretation.rb,
lib/card/query/relational_attributes.rb

Overview

Card::Query is for finding implicit lists (or counts of lists) of cards.

Search and Set cards use Card::Query to query the database, and it's also frequently used directly in code.

Query "statements" (objects, really) are made in WQL (Wagn Query Language). Because WQL is used by Wagneers, the primary language documentation is on wagn.org. (http://wagn.org/WQL_Syntax). Note that the examples there are in JSON, like Search card content, but statements in Card::Query are in ruby form.

In Wagn's current form, Card::Query generates and executes SQL statements. However, the SQL generation is largely (not yet fully) separated from the WQL statement interpretation.

The most common way to use Card::Query is as follows: list_of_cards = Card::Query.run(statement)

This is equivalent to: query = Card::Query.new(statement) list_of_cards = query.run

Upon initiation, the query is interpreted, and the following key objects are populated:

  • @join - an Array of Card::Query::Join objects
  • @conditions - an Array of conditions
  • @mod - a Hash of other query-altering keys
  • @subqueries - a list of other queries nested within this one

Each condition is either a SQL-ready string (boo) or an Array in this form: [ field_string_or_sym, Card::Value::Query object ]

Defined Under Namespace

Modules: Attributes, Clause, Conjunctions, Helpers, Interpretation, RelationalAttributes, Sorting Classes: Join, Reference, SqlStatement, Value

Constant Summary collapse

ATTRIBUTES =
{
  basic:           %w( id name key type_id content left_id right_id
                       creator_id updater_id codename read_rule_id        ),
  relational:      %w( type part left right
                       editor_of edited_by last_editor_of last_edited_by
                       creator_of created_by member_of member             ),
  plus_relational: %w(plus left_plus right_plus),
  ref_relational:  %w( refer_to referred_to_by
                       link_to linked_to_by
                       include included_by                                ),
  conjunction:     %w(and or all any),
  special:         %w(found_by not sort match complete extension_type),
  ignore:          %w(prepend append view params vars size)
}.each_with_object({}) do |pair, h|
  pair[1].each { |v| h[v.to_sym] = pair[0] }
end
CONJUNCTIONS =
{ any: :or, in: :or, or: :or, all: :and, and: :and }.freeze
MODIFIERS =
%w(conj return sort sort_as group dir limit offset)
.each_with_object({}) { |v, h| h[v.to_sym] = nil }
OPERATORS =
%w(!= = =~ < > in ~).each_with_object({}) { |v, h| h[v] = v }.merge(
  {
    eq: "=", gt: ">", lt: "<", match: "~", ne: "!=", "not in" => nil
  }.stringify_keys
)
DEFAULT_ORDER_DIRS =
{ update: "desc", relevance: "desc" }.freeze

Constants included from Sorting

Sorting::SORT_JOIN_TO_ITEM_MAP

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Helpers

#id_from_val, #join_cards, #join_references, #restrict, #restrict_reference, #table_alias, #table_id, #tick_table_seq!

Methods included from Conjunctions

#all, #any, #conjoin, #conjunction, #not

Methods included from Sorting

#sort, #sort_by_count

Methods included from Interpretation

#add_condition, #all_joins, #clause_to_hash, #current_conjunction, #interpret, #interpret_attributes, #interpret_by_key, #normalize_clause, #normalize_string_value, #normalize_value, #relate, #relate_compound, #relate_multi_value

Methods included from RelationalAttributes

#created_by, #creator_of, #edited_by, #editor_of, #junction, #last_edited_by, #last_editor_of, #left, #left_plus, #member, #member_of, #part, #plus, #right, #right_plus, #type

Methods included from Attributes

#complete, #extension_type, #found_by, #found_by_cards, #match

Methods included from Clause

#match_prep, #quote, #safe_sql

Constructor Details

#initialize(statement, comment = nil) ⇒ Query

Returns a new instance of Query.



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

def initialize statement, comment=nil
  @subqueries = []
  @conditions = []
  @joins = []
  @mods = {}
  @statement = statement.clone

  @context    = @statement.delete(:context) || nil
  @unjoined   = @statement.delete(:unjoined) || nil
  @superquery = @statement.delete(:superquery) || nil
  @vars       = @statement.delete(:vars) || {}
  @vars.symbolize_keys!

  @comment = comment || default_comment

  interpret @statement
  self
end

Instance Attribute Details

#commentObject (readonly)

Returns the value of attribute comment.



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

def comment
  @comment
end

#conditionsObject (readonly)

Returns the value of attribute conditions.



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

def conditions
  @conditions
end

#conditions_on_joinObject

Returns the value of attribute conditions_on_join.



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

def conditions_on_join
  @conditions_on_join
end

#joinsObject

Returns the value of attribute joins.



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

def joins
  @joins
end

#modsObject (readonly)

Returns the value of attribute mods.



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

def mods
  @mods
end

#statementObject (readonly)

Returns the value of attribute statement.



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

def statement
  @statement
end

#subqueriesObject (readonly)

Returns the value of attribute subqueries.



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

def subqueries
  @subqueries
end

#superqueryObject (readonly)

Returns the value of attribute superquery.



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

def superquery
  @superquery
end

#table_seqObject

Returns the value of attribute table_seq.



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

def table_seq
  @table_seq
end

#unjoinedObject

Returns the value of attribute unjoined.



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

def unjoined
  @unjoined
end

Class Method Details

.run(statement, comment = nil) ⇒ Object

By default a query returns card objects. This is accomplished by returning a card identifier from SQL and then hooking into our caching system (see Card::Fetch)



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

def self.run statement, comment=nil
  new(statement, comment).run
end

Instance Method Details

#contextObject



176
177
178
179
180
181
182
# File 'lib/card/query.rb', line 176

def context
  if !@context.nil?
    @context
  else
    @context = @superquery ? @superquery.context : ""
  end
end

#default_commentObject



116
117
118
119
# File 'lib/card/query.rb', line 116

def default_comment
  return if @superquery || !Card.config.sql_comments
  statement.to_s
end

#get_results(retrn) ⇒ Object

Returns Integer for :count, otherwise Array of Strings or Integers.

Returns:

  • Integer for :count, otherwise Array of Strings or Integers



135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/card/query.rb', line 135

def get_results retrn
  rows = run_sql
  if retrn == "name" && (statement[:prepend] || statement[:append])
    rows.map do |row|
      [statement[:prepend], row["name"], statement[:append]].compact * "+"
    end
  else
    case retrn
    when "count" then rows.first["count"].to_i
    when "raw"   then rows
    when /id$/   then rows.map { |row| row[retrn].to_i }
    else              rows.map { |row| row[retrn]      }
    end
  end
end

#rootObject

Query Hierarchy @root, @subqueries, and @superquery are used to track a hierarchy of query objects. This nesting allows to find, for example, cards that link to cards that link to cards....



166
167
168
# File 'lib/card/query.rb', line 166

def root
  @root ||= @superquery ? @superquery.root : self
end

#runObject

run the current query

Returns:

  • array of card objects by default



123
124
125
126
127
128
129
130
131
132
# File 'lib/card/query.rb', line 123

def run
  retrn = statement[:return].present? ? statement[:return].to_s : "card"
  if retrn == "card"
    get_results("name").map do |name|
      Card.fetch name, new: {}
    end
  else
    get_results retrn
  end
end

#run_sqlObject



151
152
153
154
155
# File 'lib/card/query.rb', line 151

def run_sql
  # puts "\nstatement = #{@statement}"
  # puts "sql = #{sql}"
  ActiveRecord::Base.connection.select_all(sql)
end

#sqlObject



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

def sql
  @sql ||= SqlStatement.new(self).build.to_s
end

#subquery(opts = {}) ⇒ Object



170
171
172
173
174
# File 'lib/card/query.rb', line 170

def subquery opts={}
  subquery = Query.new opts.merge(superquery: self)
  @subqueries << subquery
  subquery
end