Module: Card::Query

Defined in:
lib/card/query.rb,
lib/card/query/join.rb,
lib/card/query/value.rb,
lib/card/query/clause.rb,
lib/card/query/act_query.rb,
lib/card/query/card_query.rb,
lib/card/query/action_query.rb,
lib/card/query/sql_statement.rb,
lib/card/query/abstract_query.rb,
lib/card/query/card_query/run.rb,
lib/card/query/reference_query.rb,
lib/card/query/abstract_query/tie.rb,
lib/card/query/card_query/sorting.rb,
lib/card/query/card_query/found_by.rb,
lib/card/query/sql_statement/joins.rb,
lib/card/query/sql_statement/order.rb,
lib/card/query/sql_statement/where.rb,
lib/card/query/card_query/conjunctions.rb,
lib/card/query/card_query/normalization.rb,
lib/card/query/card_query/interpretation.rb,
lib/card/query/abstract_query/query_helper.rb,
lib/card/query/card_query/match_attributes.rb,
lib/card/query/card_query/reference_attributes.rb,
lib/card/query/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 Deckers, the primary language documentation is on wagn.org. (https://decko.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 Decko'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: Clause Classes: AbstractQuery, ActQuery, ActionQuery, CardQuery, Join, ReferenceQuery, SqlStatement, Value

Constant Summary collapse

ATTRIBUTES =

After conversion, ATTRIBUTES is a Hash where the key is the attribute and the value is the attribute type: { id: :basic, name: :basic, key: :basic ...} This is used for rapid attribute type lookups in the interpretation phase.

{
  # Each of the "basic" fields corresponds directly to a database field.
  # their values are translated fairly directly into SQL-safe values.
  # (These are referred to as "properties" in WQL documentation. Need to
  # reconcile #EFM)
  basic:           %i[id name key type_id content left_id right_id
            creator_id updater_id codename read_rule_id],
  # "Relational" values can involve tying multiple queries together
  relational:      %i[type
                 part left right
                 editor_of edited_by last_editor_of last_edited_by
                 creator_of created_by
                 updater_of updated_by
                 link_to linked_to_by
                 include included_by

                 refer_to referred_to_by
                 member_of member

                 found_by not sort match name_match complete
                 extension_type],

  plus_relational: %i[plus left_plus right_plus],
  conjunction:     %i[and or all any],
  ignore:          %i[prepend append view params vars size]
}.each_with_object({}) do |pair, h|
  pair[1].each { |v| h[v] = pair[0] }
end
CONJUNCTIONS =
{ any: :or, in: :or, or: :or, all: :and, and: :and }.freeze
MODIFIERS =
%i[conj return sort sort_as group dir limit offset]
.each_with_object({}) { |v, h| h[v] = nil }
OPERATORS =
%w[!= = =~ < > in ~].each_with_object({}) { |v, h| h[v] = v }.merge(
  {
    eq: "=", gt: ">", lt: "<", match: "~", ne: "!=", "not in": "not in"
  }.stringify_keys
)
DEFAULT_ORDER_DIRS =
{ update: "desc", relevance: "desc" }.freeze

Class Method Summary collapse

Class Method Details

.class_for(type) ⇒ Object



95
96
97
# File 'lib/card/query.rb', line 95

def class_for type
  const_get "#{type.capitalize}Query"
end

.new(statement, comment = nil) ⇒ Object



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

def new statement, comment=nil
  Query::CardQuery.new statement, comment
end

.run(statement, comment = nil) ⇒ Object



91
92
93
# File 'lib/card/query.rb', line 91

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

.safe_sql(txt) ⇒ Object



99
100
101
102
103
104
# File 'lib/card/query.rb', line 99

def safe_sql txt
  txt = txt.to_s
  raise "WQL contains disallowed characters: #{txt}" if txt.match?(/[^\w\s*().,]/)

  txt
end