conceptql 0.0.5 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +19 -1
- data/conceptql.gemspec +1 -1
- data/lib/conceptql/behaviors/dottable.rb +20 -3
- data/lib/conceptql/cli.rb +3 -3
- data/lib/conceptql/graph.rb +1 -1
- data/lib/conceptql/graph_nodifier.rb +3 -2
- data/lib/conceptql/nodes/binary_operator_node.rb +2 -2
- data/lib/conceptql/nodes/casting_node.rb +4 -2
- data/lib/conceptql/nodes/define.rb +11 -20
- data/lib/conceptql/nodes/node.rb +22 -1
- data/lib/conceptql/nodes/recall.rb +6 -3
- data/lib/conceptql/nodifier.rb +2 -2
- data/lib/conceptql/query.rb +6 -2
- data/lib/conceptql/tree.rb +3 -2
- data/lib/conceptql/version.rb +1 -1
- metadata +9 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5d18bbb657fb80b014eb554e98b1329f98ecb64f
|
4
|
+
data.tar.gz: 80564c67d29d44af5c91cae68a0096eac546116b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2bfa1b9efeae75d2d96c3565cc9ffe38398667e5d15afbf8c9c4d5d835c48da685eb74561262db103f86d8f880e4957ac3bd53ffc26816c5ceec73b065a09457
|
7
|
+
data.tar.gz: 11a3813fdd1450c70b4f6aa866dffba16f2e22376ec6a625a77ef6840aeb777dbc8099ab3f40b78feae2080706ebdf40b0609d2cea017f89af5e67faee1823e0
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,25 @@
|
|
1
1
|
# Changelog
|
2
2
|
All notable changes to this project will be documented in this file.
|
3
3
|
|
4
|
+
## 0.0.6 - 2014-08-23
|
5
|
+
|
6
|
+
### Added
|
7
|
+
- Tree#defined to pass type information between Define and Recall.
|
8
|
+
- Node#sql to produce SQL for each node.
|
9
|
+
- Graph includes row count on each edge in the diagram.
|
10
|
+
|
11
|
+
### Deprecated
|
12
|
+
- Nothing.
|
13
|
+
|
14
|
+
### Removed
|
15
|
+
- Nothing.
|
16
|
+
|
17
|
+
### Fixed
|
18
|
+
- Bug in CastingNode that generate SQL returning multiple columns in a subquery.
|
19
|
+
- Made ruby-graphviz a dependency so calling programs don't bomb out.
|
20
|
+
- Define now passes rows on through like any other node!
|
21
|
+
|
22
|
+
|
4
23
|
## 0.0.5 - 2014-08-19
|
5
24
|
|
6
25
|
### Added
|
@@ -16,7 +35,6 @@ All notable changes to this project will be documented in this file.
|
|
16
35
|
- Bug in GraphNodifier not displaying types for `recall` nodes.
|
17
36
|
|
18
37
|
|
19
|
-
|
20
38
|
## 0.0.4 - 2014-08-19
|
21
39
|
|
22
40
|
### Added
|
data/conceptql.gemspec
CHANGED
@@ -22,8 +22,8 @@ Gem::Specification.new do |spec|
|
|
22
22
|
spec.add_dependency 'sequelizer', '~> 0.0'
|
23
23
|
spec.add_dependency 'thor', '~> 0.19'
|
24
24
|
spec.add_dependency 'pg', '~> 0.17'
|
25
|
+
spec.add_dependency 'ruby-graphviz', '~> 1.2'
|
25
26
|
spec.add_development_dependency 'bundler', '~> 1.5'
|
26
|
-
spec.add_development_dependency 'ruby-graphviz', '~> 1.2'
|
27
27
|
spec.add_development_dependency 'rake', '~> 10.3'
|
28
28
|
spec.add_development_dependency 'minitest', '~> 5.4'
|
29
29
|
spec.add_development_dependency 'guard-minitest', '~> 2.3'
|
@@ -49,9 +49,18 @@ module ConceptQL
|
|
49
49
|
end
|
50
50
|
end
|
51
51
|
|
52
|
-
def link_to(g, dest_node)
|
52
|
+
def link_to(g, dest_node, db = nil)
|
53
|
+
edge_options = {}
|
54
|
+
|
53
55
|
types.each do |type|
|
54
|
-
|
56
|
+
if db
|
57
|
+
my_n = my_n(db, type)
|
58
|
+
label = [' rows=' + my_count(db, type).to_s + ' ']
|
59
|
+
label << ' n=' + my_n.to_s + ' '
|
60
|
+
edge_options[:label] = label.join("\n")
|
61
|
+
edge_options[:style] = 'dashed' if my_n.zero?
|
62
|
+
end
|
63
|
+
e = g.add_edges(graph_node(g), dest_node, edge_options)
|
55
64
|
e[:color] = type_color(type)
|
56
65
|
end
|
57
66
|
end
|
@@ -63,9 +72,17 @@ module ConceptQL
|
|
63
72
|
end
|
64
73
|
graph_node(g)
|
65
74
|
children.each do |child|
|
66
|
-
child.link_to(g, graph_node(g))
|
75
|
+
child.link_to(g, graph_node(g), db)
|
67
76
|
end
|
68
77
|
end
|
78
|
+
|
79
|
+
def my_count(db, type)
|
80
|
+
evaluate(db).from_self.where(criterion_type: type.to_s).count
|
81
|
+
end
|
82
|
+
|
83
|
+
def my_n(db, type)
|
84
|
+
evaluate(db).from_self.where(criterion_type: type.to_s).select_group(:person_id).count
|
85
|
+
end
|
69
86
|
end
|
70
87
|
end
|
71
88
|
end
|
data/lib/conceptql/cli.rb
CHANGED
@@ -37,7 +37,7 @@ module ConceptQL
|
|
37
37
|
desc 'run_statement statement_file', 'Reads the ConceptQL statement from the statement file and executes it against the DB'
|
38
38
|
def run_statement(statement_file)
|
39
39
|
q = ConceptQL::Query.new(db(options), criteria_from_file(statement_file))
|
40
|
-
puts q.
|
40
|
+
puts q.sql
|
41
41
|
puts q.statement.to_yaml
|
42
42
|
pp q.execute
|
43
43
|
end
|
@@ -102,13 +102,13 @@ module ConceptQL
|
|
102
102
|
puts results.length
|
103
103
|
end
|
104
104
|
|
105
|
-
def graph_it(statement,
|
105
|
+
def graph_it(statement, title = nil)
|
106
106
|
require_relative 'graph'
|
107
107
|
require_relative 'tree'
|
108
108
|
ConceptQL::Graph.new(statement,
|
109
109
|
dangler: true,
|
110
110
|
title: title,
|
111
|
-
db: db
|
111
|
+
db: db(options)
|
112
112
|
).graph_it('/tmp/graph')
|
113
113
|
system('open /tmp/graph.pdf')
|
114
114
|
end
|
data/lib/conceptql/graph.rb
CHANGED
@@ -59,7 +59,7 @@ module ConceptQL
|
|
59
59
|
attr :values, :name
|
60
60
|
def initialize(name, values)
|
61
61
|
@name = name.to_s
|
62
|
-
super(values)
|
62
|
+
super(nil, values)
|
63
63
|
end
|
64
64
|
|
65
65
|
def display_name
|
@@ -171,7 +171,8 @@ module ConceptQL
|
|
171
171
|
def types
|
172
172
|
@types ||= {}
|
173
173
|
end
|
174
|
-
|
174
|
+
|
175
|
+
def create(type, values, tree)
|
175
176
|
if BINARY_OPERATOR_TYPES.include?(type)
|
176
177
|
return BinaryOperatorNode.new(type, values)
|
177
178
|
elsif type == :define
|
@@ -17,8 +17,8 @@ module ConceptQL
|
|
17
17
|
sub.send("#{cluster_name}_left").send('[]', shape: 'point', color: type_color(types))
|
18
18
|
sub.send("#{cluster_name}_right").send('[]', shape: 'point')
|
19
19
|
end
|
20
|
-
left.link_to(g, me.send("#{cluster_name}_left"))
|
21
|
-
right.link_to(g, me.send("#{cluster_name}_right"))
|
20
|
+
left.link_to(g, me.send("#{cluster_name}_left"), db)
|
21
|
+
right.link_to(g, me.send("#{cluster_name}_right"), db)
|
22
22
|
@__graph_node = me.send("#{cluster_name}_left")
|
23
23
|
end
|
24
24
|
|
@@ -67,7 +67,7 @@ module ConceptQL
|
|
67
67
|
# For each castable type in the stream, setup a query that
|
68
68
|
# casts each type to a set of IDs, union those IDs and fetch
|
69
69
|
# them from the source table
|
70
|
-
|
70
|
+
castable_type_query = to_me_types.map do |source_type|
|
71
71
|
source_ids = db.from(stream_query)
|
72
72
|
.where(criterion_type: source_type.to_s)
|
73
73
|
.select_group(:criterion_id)
|
@@ -77,8 +77,10 @@ module ConceptQL
|
|
77
77
|
db.from(source_table)
|
78
78
|
.where(source_type_id => source_ids)
|
79
79
|
.select(destination_type_id)
|
80
|
+
end.inject do |union_query, q|
|
81
|
+
union_query.union(q)
|
80
82
|
end
|
81
|
-
wheres << Sequel.expr(destination_type_id =>
|
83
|
+
wheres << Sequel.expr(destination_type_id => castable_type_query)
|
82
84
|
end
|
83
85
|
|
84
86
|
unless from_me_types.empty?
|
@@ -13,6 +13,10 @@ module ConceptQL
|
|
13
13
|
# and then insert that variable into the concept as needed.
|
14
14
|
# run the query once and subsequent calls
|
15
15
|
class Define < Node
|
16
|
+
def initialize(*args)
|
17
|
+
super
|
18
|
+
tree.defined[table_name] = self
|
19
|
+
end
|
16
20
|
# Create a temporary table and store the stream of results in that table.
|
17
21
|
# This "caches" the results so we only have to execute stream's query
|
18
22
|
# once.
|
@@ -39,35 +43,22 @@ module ConceptQL
|
|
39
43
|
# Also, things will blow up if you try to use a variable that hasn't been
|
40
44
|
# defined yet.
|
41
45
|
def query(db)
|
42
|
-
table_name = namify(arguments.first)
|
43
|
-
stash_types(db, table_name, types)
|
44
46
|
db.create_table!(table_name, temp: true, as: stream.evaluate(db))
|
45
|
-
db
|
47
|
+
db.from(table_name)
|
46
48
|
end
|
47
49
|
|
48
50
|
def types
|
49
51
|
stream.types
|
50
52
|
end
|
51
53
|
|
54
|
+
def sql(db)
|
55
|
+
db[db.send(:create_table_as_sql, table_name, stream.evaluate(db).sql, temp: true)].sql
|
56
|
+
end
|
57
|
+
|
52
58
|
private
|
53
59
|
|
54
|
-
|
55
|
-
|
56
|
-
# the type information outside of the "define" statement because the "recall"
|
57
|
-
# statement most likely doesn't have a reference to this node (that's the
|
58
|
-
# whole point).
|
59
|
-
#
|
60
|
-
# There is only one object shared between all the nodes: the database
|
61
|
-
# connection. We'll do something terrible and piggyback the type
|
62
|
-
# information about this variable on the database connection so that
|
63
|
-
# the "recall" node can pull that information back out.
|
64
|
-
#
|
65
|
-
# Ugh.
|
66
|
-
def stash_types(db, name, types)
|
67
|
-
def db.types
|
68
|
-
@types ||= {}
|
69
|
-
end
|
70
|
-
db.types[name] = types
|
60
|
+
def table_name
|
61
|
+
@table_name ||= namify(arguments.first)
|
71
62
|
end
|
72
63
|
end
|
73
64
|
end
|
data/lib/conceptql/nodes/node.rb
CHANGED
@@ -3,7 +3,8 @@ module ConceptQL
|
|
3
3
|
module Nodes
|
4
4
|
class Node
|
5
5
|
attr :values, :options
|
6
|
-
def initialize(*args)
|
6
|
+
def initialize(tree, *args)
|
7
|
+
@tree = tree
|
7
8
|
args.flatten!
|
8
9
|
if args.last.is_a?(Hash)
|
9
10
|
@options = args.pop.symbolize_keys
|
@@ -16,6 +17,10 @@ module ConceptQL
|
|
16
17
|
select_it(query(db))
|
17
18
|
end
|
18
19
|
|
20
|
+
def sql(db)
|
21
|
+
evaluate(db).sql
|
22
|
+
end
|
23
|
+
|
19
24
|
def select_it(query, specific_type = nil)
|
20
25
|
specific_type = type if specific_type.nil? && respond_to?(:type)
|
21
26
|
query.select(*columns(specific_type))
|
@@ -48,6 +53,22 @@ module ConceptQL
|
|
48
53
|
end
|
49
54
|
|
50
55
|
private
|
56
|
+
# There have been a few times now that I've wanted a node to be able
|
57
|
+
# to pass information to another node that is not directly a child
|
58
|
+
#
|
59
|
+
# Since tree is only object that touches each node in a statement,
|
60
|
+
# I'm going to employ tree as a way to communicate between nodes
|
61
|
+
#
|
62
|
+
# This is an ugly hack, but the use case for this hack is I'm changing
|
63
|
+
# the way `define` and `recall` nodes pass type information between
|
64
|
+
# each other. They used to take the type information onto the
|
65
|
+
# database connection, but there were issues where sometimes the
|
66
|
+
# type information was needed before we passed around the database
|
67
|
+
# connection.
|
68
|
+
#
|
69
|
+
# At least this way we don't have timing issues when reading types
|
70
|
+
attr :tree
|
71
|
+
|
51
72
|
def criterion_id
|
52
73
|
:criterion_id
|
53
74
|
end
|
@@ -20,13 +20,16 @@ module ConceptQL
|
|
20
20
|
# before we call #query. Probably time to reevaluate how we're caching
|
21
21
|
# the type information.
|
22
22
|
def query(db)
|
23
|
-
table_name = namify(arguments.first)
|
24
|
-
@types = db.types[table_name]
|
25
23
|
db.from(table_name)
|
26
24
|
end
|
27
25
|
|
28
26
|
def types
|
29
|
-
|
27
|
+
tree.defined[table_name].types
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
def table_name
|
32
|
+
@table_name ||= namify(arguments.first)
|
30
33
|
end
|
31
34
|
end
|
32
35
|
end
|
data/lib/conceptql/nodifier.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
require 'active_support/inflector'
|
2
2
|
module ConceptQL
|
3
3
|
class Nodifier
|
4
|
-
def create(type, values)
|
4
|
+
def create(type, values, tree)
|
5
5
|
require_relative "nodes/#{type}"
|
6
|
-
"conceptQL/nodes/#{type}".camelize.constantize.new(values)
|
6
|
+
"conceptQL/nodes/#{type}".camelize.constantize.new(tree, values)
|
7
7
|
end
|
8
8
|
end
|
9
9
|
end
|
data/lib/conceptql/query.rb
CHANGED
@@ -19,7 +19,7 @@ module ConceptQL
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def sql
|
22
|
-
|
22
|
+
nodes.map { |node| node.sql(db) }.join(";\n") + ';'
|
23
23
|
end
|
24
24
|
|
25
25
|
# To avoid a performance penalty, only execute the last
|
@@ -37,7 +37,11 @@ module ConceptQL
|
|
37
37
|
attr :yaml, :tree, :db
|
38
38
|
|
39
39
|
def build_query(db)
|
40
|
-
|
40
|
+
nodes.map { |n| n.evaluate(db) }
|
41
|
+
end
|
42
|
+
|
43
|
+
def nodes
|
44
|
+
@nodes ||= tree.root(self)
|
41
45
|
end
|
42
46
|
end
|
43
47
|
end
|
data/lib/conceptql/tree.rb
CHANGED
@@ -3,10 +3,11 @@ require 'active_support/core_ext/hash'
|
|
3
3
|
|
4
4
|
module ConceptQL
|
5
5
|
class Tree
|
6
|
-
attr :nodifier, :behavior
|
6
|
+
attr :nodifier, :behavior, :defined
|
7
7
|
def initialize(opts = {})
|
8
8
|
@nodifier = opts.fetch(:nodifier, Nodifier.new)
|
9
9
|
@behavior = opts.fetch(:behavior, nil)
|
10
|
+
@defined = {}
|
10
11
|
end
|
11
12
|
|
12
13
|
def root(*queries)
|
@@ -23,7 +24,7 @@ module ConceptQL
|
|
23
24
|
end
|
24
25
|
type = obj.keys.first
|
25
26
|
values = traverse(obj[type])
|
26
|
-
obj = nodifier.create(type, values)
|
27
|
+
obj = nodifier.create(type, values, self)
|
27
28
|
obj.extend(behavior) if behavior
|
28
29
|
obj
|
29
30
|
when Array
|
data/lib/conceptql/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: conceptql
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryan Duryea
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-08-
|
11
|
+
date: 2014-08-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -67,33 +67,33 @@ dependencies:
|
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0.17'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
70
|
+
name: ruby-graphviz
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
73
|
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: '1.
|
76
|
-
type: :
|
75
|
+
version: '1.2'
|
76
|
+
type: :runtime
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: '1.
|
82
|
+
version: '1.2'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
84
|
+
name: bundler
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
87
|
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: '1.
|
89
|
+
version: '1.5'
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version: '1.
|
96
|
+
version: '1.5'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
98
|
name: rake
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|