lib/conceptql/query.rb in conceptql-0.2.0 vs lib/conceptql/query.rb in conceptql-0.3.0
- old
+ new
@@ -1,50 +1,96 @@
-require 'psych'
+require 'json'
+require 'open3'
require 'forwardable'
-require_relative 'behaviors/preppable'
-require_relative 'tree'
+require_relative 'scope'
+require_relative 'nodifier'
+require_relative 'sql_formatter'
module ConceptQL
class Query
extend Forwardable
- def_delegators :prepped_query, :all, :count, :execute, :order
+ def_delegators :query, :all, :count, :execute, :order, :profile
+ def_delegators :db, :profile_for
attr :statement
- def initialize(db, statement, tree = Tree.new)
+ def initialize(db, statement, opts={})
@db = db
- @db.extend_datasets(ConceptQL::Behaviors::Preppable)
- @statement = statement
- @tree = tree
+ @statement = extract_statement(statement)
+ opts = opts.dup
+ opts[:algorithm_fetcher] ||= proc do |alg|
+ statement, description = db[:concepts].where(concept_id: alg).get([:statement, :label])
+ statement = JSON.parse(statement) if statement.is_a?(String)
+ [statement, description]
+ end
+ @nodifier = opts[:nodifier] || Nodifier.new({ database_type: db.database_type}.merge(opts))
end
def query
- build_query(db)
+ nodifier.scope.with_ctes(operator.evaluate(db), db)
end
+ def query_cols(opts = {})
+ cols = operator.dynamic_columns
+ if opts[:cast]
+ cols = query_cols.each_with_object({}) do |column, h|
+ h[column] = operator.cast_column(column)
+ end
+ end
+ cols
+ end
+
def sql
- (tree.scope.sql(db) << operator.sql(db)).join(";\n\n") + ';'
+ SqlFormatter.new.format(query.sql)
+ rescue
+ puts $!.message
+ puts $!.backtrace.join("\n")
+ return "SQL unavailable for this statement"
end
- def types
- tree.root(self).types
+ def annotate(opts = {})
+ operator.annotate(db, opts)
end
- def operator
- @operator ||= tree.root(self)
+ def scope_annotate(opts = {})
+ annotate(opts)
+ nodifier.scope.annotation
end
- private
- attr :yaml, :tree, :db
+ def optimized
+ n = dup
+ n.instance_variable_set(:@operator, operator.optimized)
+ n
+ end
- def build_query(db)
- operator.evaluate(db).tap { |q| q.prep_proc = prep_proc }
+ def domains
+ operator.domains(db)
end
- def prep_proc
- @prep_proc = Proc.new { puts 'PREPPING'; tree.scope.prep(db) }
+ def operator
+ @operator ||= if statement.is_a?(Array)
+ if statement.first.is_a?(Array)
+ Operators::Invalid.new(nodifier, "invalid", errors: [["incomplete statement"]])
+ else
+ nodifier.create(*statement)
+ end
+ else
+ Operators::Invalid.new(nodifier, "invalid", errors: [["invalid root operator", statement.inspect]])
+ end
end
- def prepped_query
- query
+ def code_list(db)
+ operator.code_list(db)
+ end
+
+ private
+ attr :db, :nodifier
+
+
+ def extract_statement(stmt)
+ if stmt.is_a?(Array) && stmt.length == 1 && stmt.first.is_a?(Array)
+ stmt.first
+ else
+ stmt
+ end
end
end
end