conceptql 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/CHANGELOG.md +53 -1
- data/Guardfile +52 -24
- data/conceptql.gemspec +5 -3
- data/doc/spec.md +2 -2
- data/lib/conceptql/behaviors/debuggable.rb +70 -0
- data/lib/conceptql/behaviors/dottable.rb +28 -14
- data/lib/conceptql/behaviors/metadatable.rb +97 -0
- data/lib/conceptql/behaviors/preppable.rb +20 -0
- data/lib/conceptql/cli.rb +31 -5
- data/lib/conceptql/converter.rb +65 -0
- data/lib/conceptql/debugger.rb +48 -0
- data/lib/conceptql/graph.rb +14 -13
- data/lib/conceptql/graph_nodifier.rb +49 -17
- data/lib/conceptql/nodifier.rb +31 -6
- data/lib/conceptql/operators/after.rb +25 -0
- data/lib/conceptql/operators/any_overlap.rb +15 -0
- data/lib/conceptql/operators/before.rb +21 -0
- data/lib/conceptql/{nodes/binary_operator_node.rb → operators/binary_operator_operator.rb} +12 -8
- data/lib/conceptql/{nodes/casting_node.rb → operators/casting_operator.rb} +8 -7
- data/lib/conceptql/{nodes → operators}/complement.rb +14 -11
- data/lib/conceptql/operators/concept.rb +70 -0
- data/lib/conceptql/{nodes → operators}/condition_type.rb +13 -5
- data/lib/conceptql/operators/contains.rb +17 -0
- data/lib/conceptql/operators/count.rb +26 -0
- data/lib/conceptql/operators/cpt.rb +25 -0
- data/lib/conceptql/{nodes → operators}/date_range.rb +11 -6
- data/lib/conceptql/operators/death.rb +23 -0
- data/lib/conceptql/operators/drug_type_concept.rb +21 -0
- data/lib/conceptql/{nodes → operators}/during.rb +9 -3
- data/lib/conceptql/operators/equal.rb +13 -0
- data/lib/conceptql/operators/except.rb +28 -0
- data/lib/conceptql/operators/filter.rb +21 -0
- data/lib/conceptql/{nodes → operators}/first.rb +7 -5
- data/lib/conceptql/{nodes → operators}/from.rb +2 -2
- data/lib/conceptql/operators/from_seer_visits.rb +23 -0
- data/lib/conceptql/{nodes → operators}/gender.rb +6 -6
- data/lib/conceptql/operators/hcpcs.rb +25 -0
- data/lib/conceptql/operators/icd10.rb +28 -0
- data/lib/conceptql/operators/icd9.rb +28 -0
- data/lib/conceptql/operators/icd9_procedure.rb +25 -0
- data/lib/conceptql/{nodes → operators}/intersect.rb +7 -3
- data/lib/conceptql/{nodes → operators}/last.rb +7 -5
- data/lib/conceptql/operators/loinc.rb +25 -0
- data/lib/conceptql/operators/medcode.rb +28 -0
- data/lib/conceptql/operators/medcode_procedure.rb +27 -0
- data/lib/conceptql/operators/ndc.rb +29 -0
- data/lib/conceptql/operators/numeric.rb +54 -0
- data/lib/conceptql/operators/observation_by_enttype.rb +29 -0
- data/lib/conceptql/operators/observation_period.rb +30 -0
- data/lib/conceptql/operators/occurrence.rb +70 -0
- data/lib/conceptql/operators/one_in_two_out.rb +62 -0
- data/lib/conceptql/{nodes/node.rb → operators/operator.rb} +84 -52
- data/lib/conceptql/operators/overlapped_by.rb +23 -0
- data/lib/conceptql/operators/overlaps.rb +19 -0
- data/lib/conceptql/operators/pass_thru.rb +11 -0
- data/lib/conceptql/{nodes → operators}/person.rb +8 -4
- data/lib/conceptql/operators/person_filter.rb +13 -0
- data/lib/conceptql/{nodes → operators}/place_of_service_code.rb +7 -7
- data/lib/conceptql/operators/procedure_occurrence.rb +25 -0
- data/lib/conceptql/operators/prodcode.rb +29 -0
- data/lib/conceptql/{nodes → operators}/race.rb +7 -7
- data/lib/conceptql/operators/recall.rb +38 -0
- data/lib/conceptql/operators/rxnorm.rb +24 -0
- data/lib/conceptql/operators/snomed.rb +24 -0
- data/lib/conceptql/operators/snomed_condition.rb +26 -0
- data/lib/conceptql/{nodes/source_vocabulary_node.rb → operators/source_vocabulary_operator.rb} +7 -4
- data/lib/conceptql/{nodes/standard_vocabulary_node.rb → operators/standard_vocabulary_operator.rb} +6 -4
- data/lib/conceptql/{nodes → operators}/started_by.rb +9 -3
- data/lib/conceptql/{nodes → operators}/sum.rb +9 -4
- data/lib/conceptql/{nodes/temporal_node.rb → operators/temporal_operator.rb} +7 -4
- data/lib/conceptql/{nodes → operators}/time_window.rb +19 -7
- data/lib/conceptql/operators/to_seer_visits.rb +24 -0
- data/lib/conceptql/operators/trim_date_end.rb +55 -0
- data/lib/conceptql/operators/trim_date_start.rb +56 -0
- data/lib/conceptql/{nodes → operators}/union.rb +6 -2
- data/lib/conceptql/operators/visit.rb +15 -0
- data/lib/conceptql/{nodes → operators}/visit_occurrence.rb +7 -3
- data/lib/conceptql/query.rb +19 -17
- data/lib/conceptql/scope.rb +69 -0
- data/lib/conceptql/tree.rb +33 -18
- data/lib/conceptql/utils/temp_table.rb +72 -0
- data/lib/conceptql/version.rb +1 -1
- data/spec/conceptql/behaviors/dottable_spec.rb +39 -51
- data/spec/conceptql/converter_spec.rb +51 -0
- data/spec/conceptql/date_adjuster_spec.rb +15 -15
- data/spec/conceptql/operators/after_spec.rb +16 -0
- data/spec/conceptql/operators/before_spec.rb +16 -0
- data/spec/conceptql/{nodes/casting_node_spec.rb → operators/casting_operator_spec.rb} +16 -20
- data/spec/conceptql/operators/complement_spec.rb +15 -0
- data/spec/conceptql/operators/concept_spec.rb +40 -0
- data/spec/conceptql/{nodes → operators}/condition_type_spec.rb +39 -24
- data/spec/conceptql/operators/contains_spec.rb +19 -0
- data/spec/conceptql/operators/cpt_spec.rb +29 -0
- data/spec/conceptql/operators/date_range_spec.rb +33 -0
- data/spec/conceptql/operators/death_spec.rb +10 -0
- data/spec/conceptql/operators/during_spec.rb +30 -0
- data/spec/conceptql/operators/except_spec.rb +15 -0
- data/spec/conceptql/operators/first_spec.rb +35 -0
- data/spec/conceptql/operators/from_spec.rb +13 -0
- data/spec/conceptql/operators/gender_spec.rb +27 -0
- data/spec/conceptql/operators/hcpcs_spec.rb +29 -0
- data/spec/conceptql/operators/icd10_spec.rb +34 -0
- data/spec/conceptql/operators/icd9_procedure_spec.rb +29 -0
- data/spec/conceptql/operators/icd9_spec.rb +34 -0
- data/spec/conceptql/operators/intersect_spec.rb +28 -0
- data/spec/conceptql/operators/last_spec.rb +36 -0
- data/spec/conceptql/operators/loinc_spec.rb +29 -0
- data/spec/conceptql/operators/medcode_procedure_spec.rb +34 -0
- data/spec/conceptql/operators/medcode_spec.rb +34 -0
- data/spec/conceptql/operators/observation_period_spec.rb +10 -0
- data/spec/conceptql/operators/occurrence_spec.rb +87 -0
- data/spec/conceptql/operators/overlapped_by_spec.rb +32 -0
- data/spec/conceptql/operators/overlaps_spec.rb +21 -0
- data/spec/conceptql/operators/person_filter_spec.rb +15 -0
- data/spec/conceptql/operators/person_spec.rb +10 -0
- data/spec/conceptql/{nodes → operators}/place_of_service_code_spec.rb +6 -8
- data/spec/conceptql/operators/procedure_occurrence_spec.rb +10 -0
- data/spec/conceptql/operators/prodcode_spec.rb +35 -0
- data/spec/conceptql/operators/query_double.rb +20 -0
- data/spec/conceptql/operators/query_double_spec.rb +7 -0
- data/spec/conceptql/operators/race_spec.rb +21 -0
- data/spec/conceptql/operators/rxnorm_spec.rb +29 -0
- data/spec/conceptql/operators/snomed_spec.rb +29 -0
- data/spec/conceptql/operators/source_vocabulary_operator_spec.rb +35 -0
- data/spec/conceptql/operators/standard_vocabulary_operator_spec.rb +35 -0
- data/spec/conceptql/operators/started_by_spec.rb +22 -0
- data/spec/conceptql/{nodes/temporal_node_spec.rb → operators/temporal_operator_spec.rb} +11 -17
- data/spec/conceptql/operators/time_window_spec.rb +77 -0
- data/spec/conceptql/operators/union_spec.rb +21 -0
- data/spec/conceptql/operators/visit_occurrence_spec.rb +10 -0
- data/spec/conceptql/query_spec.rb +10 -9
- data/spec/conceptql/tree_spec.rb +24 -28
- data/spec/doubles/stream_for_casting_double.rb +1 -1
- data/spec/doubles/stream_for_occurrence_double.rb +1 -1
- data/spec/doubles/stream_for_temporal_double.rb +1 -1
- data/spec/spec_helper.rb +74 -58
- metadata +202 -133
- data/lib/conceptql/nodes/after.rb +0 -12
- data/lib/conceptql/nodes/before.rb +0 -11
- data/lib/conceptql/nodes/concept.rb +0 -38
- data/lib/conceptql/nodes/count.rb +0 -23
- data/lib/conceptql/nodes/cpt.rb +0 -20
- data/lib/conceptql/nodes/death.rb +0 -19
- data/lib/conceptql/nodes/define.rb +0 -96
- data/lib/conceptql/nodes/drug_type_concept.rb +0 -18
- data/lib/conceptql/nodes/equal.rb +0 -11
- data/lib/conceptql/nodes/except.rb +0 -11
- data/lib/conceptql/nodes/hcpcs.rb +0 -20
- data/lib/conceptql/nodes/icd10.rb +0 -23
- data/lib/conceptql/nodes/icd9.rb +0 -23
- data/lib/conceptql/nodes/icd9_procedure.rb +0 -20
- data/lib/conceptql/nodes/loinc.rb +0 -20
- data/lib/conceptql/nodes/numeric.rb +0 -40
- data/lib/conceptql/nodes/occurrence.rb +0 -49
- data/lib/conceptql/nodes/pass_thru.rb +0 -11
- data/lib/conceptql/nodes/person_filter.rb +0 -12
- data/lib/conceptql/nodes/procedure_occurrence.rb +0 -21
- data/lib/conceptql/nodes/recall.rb +0 -50
- data/lib/conceptql/nodes/rxnorm.rb +0 -20
- data/lib/conceptql/nodes/snomed.rb +0 -19
- data/lib/conceptql/nodes/visit.rb +0 -11
- data/spec/conceptql/nodes/after_spec.rb +0 -18
- data/spec/conceptql/nodes/before_spec.rb +0 -18
- data/spec/conceptql/nodes/complement_spec.rb +0 -15
- data/spec/conceptql/nodes/concept_spec.rb +0 -34
- data/spec/conceptql/nodes/cpt_spec.rb +0 -31
- data/spec/conceptql/nodes/date_range_spec.rb +0 -35
- data/spec/conceptql/nodes/death_spec.rb +0 -12
- data/spec/conceptql/nodes/during_spec.rb +0 -32
- data/spec/conceptql/nodes/except_spec.rb +0 -18
- data/spec/conceptql/nodes/first_spec.rb +0 -37
- data/spec/conceptql/nodes/from_spec.rb +0 -15
- data/spec/conceptql/nodes/gender_spec.rb +0 -29
- data/spec/conceptql/nodes/hcpcs_spec.rb +0 -31
- data/spec/conceptql/nodes/icd10_spec.rb +0 -36
- data/spec/conceptql/nodes/icd9_procedure_spec.rb +0 -31
- data/spec/conceptql/nodes/icd9_spec.rb +0 -36
- data/spec/conceptql/nodes/intersect_spec.rb +0 -33
- data/spec/conceptql/nodes/last_spec.rb +0 -38
- data/spec/conceptql/nodes/loinc_spec.rb +0 -31
- data/spec/conceptql/nodes/occurrence_spec.rb +0 -89
- data/spec/conceptql/nodes/person_filter_spec.rb +0 -18
- data/spec/conceptql/nodes/person_spec.rb +0 -12
- data/spec/conceptql/nodes/procedure_occurrence_spec.rb +0 -12
- data/spec/conceptql/nodes/query_double.rb +0 -19
- data/spec/conceptql/nodes/race_spec.rb +0 -23
- data/spec/conceptql/nodes/rxnorm_spec.rb +0 -31
- data/spec/conceptql/nodes/snomed_spec.rb +0 -31
- data/spec/conceptql/nodes/source_vocabulary_node_spec.rb +0 -37
- data/spec/conceptql/nodes/standard_vocabulary_node_spec.rb +0 -40
- data/spec/conceptql/nodes/started_by_spec.rb +0 -25
- data/spec/conceptql/nodes/time_window_spec.rb +0 -85
- data/spec/conceptql/nodes/union_spec.rb +0 -25
- data/spec/conceptql/nodes/visit_occurrence_spec.rb +0 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bb925d74153217fcb29ee4c4e5874827005246be
|
4
|
+
data.tar.gz: 41ae6d964b8a6ae82b37098adcda8548917543bd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f62d0381dbd1ceabed67e9fff58d95975bf4cff27a957f03aa0ba495ca7726b22af3727d26acd4f683ca048a17dac858dffd2bef7f2e0707cae7e5cfd29e6677
|
7
|
+
data.tar.gz: 004743713781e5ea7cf7281ea071597ac8fa0959714571639d97d69a9fdd67b03692b10b9e1c77802230f57149212e9daf5077459d02db86814759051b44cc62
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,58 @@
|
|
1
1
|
# Changelog
|
2
2
|
All notable changes to this project will be documented in this file.
|
3
3
|
|
4
|
+
## Unreleased
|
5
|
+
|
6
|
+
### Added
|
7
|
+
- Optimized After/Before nodes when multi-person results are in the right stream.
|
8
|
+
- Set end_date as coalesce(end_date, start_date) to make range if end_date missing.
|
9
|
+
- Nodes
|
10
|
+
- AnyOverlap
|
11
|
+
- Contains
|
12
|
+
- Filter
|
13
|
+
- Ndc
|
14
|
+
- ObservationPeriod
|
15
|
+
- OneInTwoOut
|
16
|
+
- OverlappedBy
|
17
|
+
- Overlaps
|
18
|
+
- TrimDateEnd
|
19
|
+
- TrimDateStart
|
20
|
+
- Nodes for CPRD
|
21
|
+
- Medcode
|
22
|
+
- MedcodeProcedure
|
23
|
+
- ObservationByEnttype
|
24
|
+
- Prodcode
|
25
|
+
- Nodes for SEER
|
26
|
+
- FromSeerVisits
|
27
|
+
- ToSeerVisits
|
28
|
+
- Ability to limit results to a set of patients by setting Tree#person_ids
|
29
|
+
- "units_source_value" and "source_value" columns in results
|
30
|
+
- TimeWindow supports date literals
|
31
|
+
- ConditionType supports search for "primary"
|
32
|
+
- Nodifier#to_metadata
|
33
|
+
|
34
|
+
### Changed
|
35
|
+
- Except now allows :ignore_date option
|
36
|
+
- Comparison is only done on criterion_id/type
|
37
|
+
- DateRange START/END use observation_period instead of visit_occurrence
|
38
|
+
- Operator#columns value_as_numeric => value_as_number
|
39
|
+
- Syntax is now more "lispy"
|
40
|
+
- Recall now uses any labeled operator as if that operator was fed to "Define" operator
|
41
|
+
- Nodes now called Operators
|
42
|
+
|
43
|
+
### Deprecated
|
44
|
+
- Nothing.
|
45
|
+
|
46
|
+
### Removed
|
47
|
+
- Let/Define operators
|
48
|
+
|
49
|
+
### Fixed
|
50
|
+
- Many broken specs.
|
51
|
+
- Union calls #from_self on incoming streams to avoid column issues
|
52
|
+
- Concept node now works again
|
53
|
+
- Define ensures tables are built
|
54
|
+
|
55
|
+
|
4
56
|
## 0.1.1 - 2014-09-18
|
5
57
|
|
6
58
|
### Added
|
@@ -13,7 +65,7 @@ All notable changes to this project will be documented in this file.
|
|
13
65
|
- Nothing.
|
14
66
|
|
15
67
|
### Fixed
|
16
|
-
- Calling Query#sql no longer creates a bunch of temporary tables
|
68
|
+
- Calling Query#sql no longer creates a bunch of temporary tables.
|
17
69
|
|
18
70
|
|
19
71
|
## 0.1.0 - 2014-09-04
|
data/Guardfile
CHANGED
@@ -1,28 +1,56 @@
|
|
1
1
|
# A sample Guardfile
|
2
2
|
# More info at https://github.com/guard/guard#readme
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
#
|
19
|
-
|
20
|
-
#
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
#
|
27
|
-
|
4
|
+
|
5
|
+
# Note: The cmd option is now required due to the increasing number of ways
|
6
|
+
# rspec may be run, below are examples of the most common uses.
|
7
|
+
# * bundler: 'bundle exec rspec'
|
8
|
+
# * bundler binstubs: 'bin/rspec'
|
9
|
+
# * spring: 'bin/rspec' (This will use spring if running and you have
|
10
|
+
# installed the spring binstubs per the docs)
|
11
|
+
# * zeus: 'zeus rspec' (requires the server to be started separately)
|
12
|
+
# * 'just' rspec: 'rspec'
|
13
|
+
|
14
|
+
guard :rspec, cmd: "bundle exec rspec" do
|
15
|
+
require "guard/rspec/dsl"
|
16
|
+
dsl = Guard::RSpec::Dsl.new(self)
|
17
|
+
|
18
|
+
# Feel free to open issues for suggestions and improvements
|
19
|
+
|
20
|
+
# RSpec files
|
21
|
+
rspec = dsl.rspec
|
22
|
+
watch(rspec.spec_helper) { rspec.spec_dir }
|
23
|
+
watch(rspec.spec_support) { rspec.spec_dir }
|
24
|
+
watch(rspec.spec_files)
|
25
|
+
|
26
|
+
# Ruby files
|
27
|
+
ruby = dsl.ruby
|
28
|
+
dsl.watch_spec_files_for(ruby.lib_files)
|
29
|
+
|
30
|
+
# Rails files
|
31
|
+
rails = dsl.rails(view_extensions: %w(erb haml slim))
|
32
|
+
dsl.watch_spec_files_for(rails.app_files)
|
33
|
+
dsl.watch_spec_files_for(rails.views)
|
34
|
+
|
35
|
+
watch(rails.controllers) do |m|
|
36
|
+
[
|
37
|
+
rspec.spec.("routing/#{m[1]}_routing"),
|
38
|
+
rspec.spec.("controllers/#{m[1]}_controller"),
|
39
|
+
rspec.spec.("acceptance/#{m[1]}")
|
40
|
+
]
|
41
|
+
end
|
42
|
+
|
43
|
+
# Rails config changes
|
44
|
+
watch(rails.spec_helper) { rspec.spec_dir }
|
45
|
+
watch(rails.routes) { "#{rspec.spec_dir}/routing" }
|
46
|
+
watch(rails.app_controller) { "#{rspec.spec_dir}/controllers" }
|
47
|
+
|
48
|
+
# Capybara features specs
|
49
|
+
watch(rails.view_dirs) { |m| rspec.spec.("features/#{m[1]}") }
|
50
|
+
|
51
|
+
# Turnip features and steps
|
52
|
+
watch(%r{^spec/acceptance/(.+)\.feature$})
|
53
|
+
watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) do |m|
|
54
|
+
Dir[File.join("**/#{m[1]}.feature")][0] || "spec/acceptance"
|
55
|
+
end
|
28
56
|
end
|
data/conceptql.gemspec
CHANGED
@@ -18,13 +18,15 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ['lib']
|
20
20
|
|
21
|
-
spec.add_dependency '
|
21
|
+
spec.add_dependency 'facets', '~> 3.0'
|
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
25
|
spec.add_dependency 'ruby-graphviz', '~> 1.2'
|
26
|
+
spec.add_dependency 'csv2xlsx', '~> 0'
|
26
27
|
spec.add_development_dependency 'bundler', '~> 1.5'
|
27
28
|
spec.add_development_dependency 'rake', '~> 10.3'
|
28
|
-
spec.add_development_dependency '
|
29
|
-
spec.add_development_dependency 'guard-
|
29
|
+
spec.add_development_dependency 'rspec', '~> 3.2'
|
30
|
+
spec.add_development_dependency 'guard-rspec', '~> 4.5'
|
31
|
+
spec.add_development_dependency 'byebug', '~> 4.0'
|
30
32
|
end
|
data/doc/spec.md
CHANGED
@@ -153,7 +153,7 @@ Virtually all other nodes add, remove, filter, or otherwise alter streams of res
|
|
153
153
|
Because streams represent sets of results, its makes sense to include a nodes that operate on sets
|
154
154
|
|
155
155
|
### Union
|
156
|
-
- Takes any number of
|
156
|
+
- Takes any number of upstream nodes and aggregates their streams
|
157
157
|
- Unions together streams with identical types
|
158
158
|
- Think of streams with the same type flowing together into a single stream
|
159
159
|
- We're really just gathering the union of all IDs for identically-typed streams
|
@@ -1333,7 +1333,7 @@ Just like Filter has an :as option, add one to Except node. This would simplify
|
|
1333
1333
|
|
1334
1334
|
|
1335
1335
|
### How to Handle fact_relationship Table from CDMv5
|
1336
|
-
Each relationship type could be a binary node box read as L <relationship> R. E.g. L '
|
1336
|
+
Each relationship type could be a binary node box read as L <relationship> R. E.g. L 'downstream of' R would take a L stream and only pass on downstreams of rows in R stream.
|
1337
1337
|
|
1338
1338
|
We could implement a single node that takes a relationship as an argument (on top of the L and R arguments) or we could create a node class for each relationship. I think it would be better to have a single relationship node class and take the relationship as the argument.
|
1339
1339
|
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require_relative '../behaviors/dottable'
|
2
|
+
require_relative '../operators/operator'
|
3
|
+
require_relative '../operators/binary_operator_operator'
|
4
|
+
require 'csv'
|
5
|
+
module ConceptQL
|
6
|
+
module Behaviors
|
7
|
+
module Debuggable
|
8
|
+
include Dottable
|
9
|
+
class ResultPrinter
|
10
|
+
attr :db, :dir, :type, :watch_ids, :operator
|
11
|
+
def initialize(db, dir, type, watch_ids, operator)
|
12
|
+
@db = db
|
13
|
+
@dir = dir
|
14
|
+
@type = type
|
15
|
+
@watch_ids = watch_ids
|
16
|
+
@operator = operator
|
17
|
+
end
|
18
|
+
|
19
|
+
def make_file
|
20
|
+
CSV.open(file_path, 'w') do |csv|
|
21
|
+
csv << ConceptQL::Operators::Operator::COLUMNS
|
22
|
+
results.each do |result|
|
23
|
+
csv << result
|
24
|
+
end
|
25
|
+
end
|
26
|
+
file_path
|
27
|
+
end
|
28
|
+
|
29
|
+
def file_path
|
30
|
+
@file_path ||= dir + file_name
|
31
|
+
end
|
32
|
+
|
33
|
+
def file_name
|
34
|
+
@file_name ||= [operator.operator_name, abbreviate(type)].join('_')
|
35
|
+
end
|
36
|
+
|
37
|
+
def results
|
38
|
+
q = operator.evaluate(db)
|
39
|
+
.from_self
|
40
|
+
.where(criterion_type: type.to_s)
|
41
|
+
unless watch_ids.empty?
|
42
|
+
q = q.where(person_id: watch_ids)
|
43
|
+
end
|
44
|
+
|
45
|
+
q.order([:person_id, :criterion_type, :start_date, :end_date, :criterion_id])
|
46
|
+
.select_map(ConceptQL::Operators::Operator::COLUMNS)
|
47
|
+
end
|
48
|
+
|
49
|
+
def abbreviate(type)
|
50
|
+
type.to_s.split('_').map(&:chars).map(&:first).join('')
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def print_results(db, dir, watch_ids)
|
55
|
+
print_prep(db) if respond_to?(:print_prep)
|
56
|
+
kids = upstreams
|
57
|
+
if self.is_a?(ConceptQL::Operators::BinaryOperatorOperator)
|
58
|
+
kids = [left, right]
|
59
|
+
end
|
60
|
+
files = kids.map do |upstream|
|
61
|
+
upstream.print_results(db, dir, watch_ids)
|
62
|
+
end
|
63
|
+
files += types.map do |type|
|
64
|
+
ResultPrinter.new(db, dir, type, watch_ids, self).make_file
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
@@ -1,4 +1,6 @@
|
|
1
|
-
require '
|
1
|
+
require 'facets/string/snakecase'
|
2
|
+
require 'facets/string/titlecase'
|
3
|
+
|
2
4
|
module ConceptQL
|
3
5
|
module Behaviors
|
4
6
|
module Dottable
|
@@ -15,13 +17,23 @@ module ConceptQL
|
|
15
17
|
observation: 'magenta',
|
16
18
|
misc: 'black'
|
17
19
|
}
|
18
|
-
|
19
|
-
|
20
|
+
|
21
|
+
def operator_number
|
22
|
+
@__operator_number ||= (@@counter += 1)
|
23
|
+
end
|
24
|
+
|
25
|
+
def reset_operator_number
|
26
|
+
@@counter = 0
|
27
|
+
end
|
28
|
+
|
29
|
+
def operator_name
|
30
|
+
@__operator_name ||= self.class.name.split('::').last.snakecase.gsub(/\W/, '_').downcase + "_#{operator_number}"
|
20
31
|
end
|
21
32
|
|
22
33
|
def display_name
|
23
34
|
@__display_name ||= begin
|
24
|
-
output = self.class.name.split('::').last.
|
35
|
+
output = self.class.name.split('::').last.snakecase.titlecase
|
36
|
+
#output += " #{operator_number}"
|
25
37
|
output += ": #{arguments.join(', ')}" unless arguments.empty?
|
26
38
|
if output.length > 100
|
27
39
|
parts = output.split
|
@@ -39,9 +51,9 @@ module ConceptQL
|
|
39
51
|
types.length == 1 ? TYPE_COLORS[types.first] || 'black' : 'black'
|
40
52
|
end
|
41
53
|
|
42
|
-
def
|
43
|
-
@
|
44
|
-
me = g.add_nodes(
|
54
|
+
def graph_operator(g)
|
55
|
+
@__graph_operator ||= begin
|
56
|
+
me = g.add_nodes(operator_name)
|
45
57
|
me[:label] = display_name
|
46
58
|
me[:color] = type_color(types)
|
47
59
|
me[:shape] = shape if respond_to?(:shape)
|
@@ -49,7 +61,7 @@ module ConceptQL
|
|
49
61
|
end
|
50
62
|
end
|
51
63
|
|
52
|
-
def link_to(g,
|
64
|
+
def link_to(g, dest_operator, db = nil)
|
53
65
|
edge_options = {}
|
54
66
|
|
55
67
|
types.each do |type|
|
@@ -60,23 +72,25 @@ module ConceptQL
|
|
60
72
|
edge_options[:label] = label.join("\n")
|
61
73
|
edge_options[:style] = 'dashed' if my_n.zero?
|
62
74
|
end
|
63
|
-
e = g.add_edges(
|
75
|
+
e = g.add_edges(graph_operator(g), dest_operator, edge_options)
|
64
76
|
e[:color] = type_color(type)
|
65
77
|
end
|
66
78
|
end
|
67
79
|
|
68
80
|
def graph_it(g, db)
|
69
81
|
graph_prep(db) if respond_to?(:graph_prep)
|
70
|
-
|
71
|
-
|
82
|
+
upstreams.each do |upstream|
|
83
|
+
upstream.graph_it(g, db)
|
72
84
|
end
|
73
|
-
|
74
|
-
|
75
|
-
|
85
|
+
operator = graph_operator(g)
|
86
|
+
upstreams.each do |upstream|
|
87
|
+
upstream.link_to(g, graph_operator(g), db)
|
76
88
|
end
|
89
|
+
operator
|
77
90
|
end
|
78
91
|
|
79
92
|
def my_count(db, type)
|
93
|
+
puts "counting #{operator_name} #{type}"
|
80
94
|
evaluate(db).from_self.where(criterion_type: type.to_s).count
|
81
95
|
end
|
82
96
|
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'facets/kernel/meta_def'
|
2
|
+
require 'facets/string/snakecase'
|
3
|
+
|
4
|
+
module Metadatable
|
5
|
+
def preferred_name(value = nil)
|
6
|
+
return @preferred_name unless value
|
7
|
+
@preferred_name = value
|
8
|
+
end
|
9
|
+
|
10
|
+
def desc(value = nil)
|
11
|
+
return @desc unless value
|
12
|
+
@desc = value
|
13
|
+
end
|
14
|
+
|
15
|
+
def predominant_types(*values)
|
16
|
+
return @predominant_types if values.empty?
|
17
|
+
@predominant_types = values
|
18
|
+
end
|
19
|
+
|
20
|
+
def argument(name, options = {})
|
21
|
+
(@arguments ||= [])
|
22
|
+
@arguments << [name, options]
|
23
|
+
end
|
24
|
+
|
25
|
+
def option(name, options = {})
|
26
|
+
@options ||= {}
|
27
|
+
@options[name] = options
|
28
|
+
end
|
29
|
+
|
30
|
+
def types(*type_list)
|
31
|
+
@types = type_list
|
32
|
+
define_method(:types) do
|
33
|
+
type_list
|
34
|
+
end
|
35
|
+
if type_list.length == 1
|
36
|
+
define_method(:type) do
|
37
|
+
type_list.first
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def allows_many_upstreams
|
43
|
+
@max_upstreams = 99
|
44
|
+
end
|
45
|
+
|
46
|
+
def allows_one_upstream
|
47
|
+
@max_upstreams = 1
|
48
|
+
end
|
49
|
+
|
50
|
+
def just_class_name
|
51
|
+
self.to_s.split('::').last
|
52
|
+
end
|
53
|
+
|
54
|
+
def humanized_class_name
|
55
|
+
just_class_name.gsub(/([A-Z])/, ' \1').lstrip
|
56
|
+
end
|
57
|
+
|
58
|
+
def category(category)
|
59
|
+
(@categories ||= [])
|
60
|
+
@categories << Array(category)
|
61
|
+
end
|
62
|
+
|
63
|
+
def reset_categories
|
64
|
+
@categories = []
|
65
|
+
end
|
66
|
+
|
67
|
+
def inherited(upstream)
|
68
|
+
(@options || {}).each do |name, opt|
|
69
|
+
upstream.option name, opt
|
70
|
+
end
|
71
|
+
|
72
|
+
(@categories || []).each do |cat|
|
73
|
+
upstream.category cat
|
74
|
+
end
|
75
|
+
|
76
|
+
case @max_upstreams
|
77
|
+
when 1
|
78
|
+
upstream.allows_one_upstream
|
79
|
+
when 99
|
80
|
+
upstream.allows_many_upstreams
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def to_metadata
|
85
|
+
{
|
86
|
+
preferred_name: @preferred_name || humanized_class_name,
|
87
|
+
operation: just_class_name.snakecase,
|
88
|
+
max_upstreams: @max_upstreams || 0,
|
89
|
+
arguments: @arguments || [],
|
90
|
+
options: @options || {},
|
91
|
+
predominant_types: @types || @predominant_types || [],
|
92
|
+
desc: @desc,
|
93
|
+
categories: @categories || []
|
94
|
+
}
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
data/lib/conceptql/cli.rb
CHANGED
@@ -39,16 +39,18 @@ module ConceptQL
|
|
39
39
|
q = ConceptQL::Query.new(db(options), criteria_from_file(statement_file))
|
40
40
|
puts q.sql
|
41
41
|
puts q.statement.to_yaml
|
42
|
-
pp q.
|
42
|
+
pp q.all
|
43
43
|
end
|
44
44
|
|
45
45
|
desc 'show_graph statement_file', 'Reads the ConceptQL statement from the file and shows the contents as a ConceptQL graph'
|
46
|
+
option :watch_file
|
46
47
|
def show_graph(file)
|
47
48
|
graph_it(criteria_from_file(file))
|
48
49
|
end
|
49
50
|
|
50
51
|
desc 'show_and_tell_file statement_file', 'Reads the ConceptQL statement from the file and shows the contents as a ConceptQL graph, then executes the statement against the DB'
|
51
52
|
option :full
|
53
|
+
option :watch_file
|
52
54
|
def show_and_tell_file(file)
|
53
55
|
show_and_tell(criteria_from_file(file), options)
|
54
56
|
end
|
@@ -60,9 +62,28 @@ module ConceptQL
|
|
60
62
|
system('open /tmp/graph.pdf')
|
61
63
|
end
|
62
64
|
|
65
|
+
desc 'metadata', 'Generates the metadata.js file for the JAM'
|
66
|
+
def metadata
|
67
|
+
File.write('/tmp/metadata.js', "var metadata = #{ConceptQL::Nodifier.new.to_metadata.to_json};")
|
68
|
+
end
|
69
|
+
|
70
|
+
desc 'convert', 'Converts from hash-based syntax to list-based syntax'
|
71
|
+
def convert(file)
|
72
|
+
require 'conceptql/converter'
|
73
|
+
require 'json'
|
74
|
+
begin
|
75
|
+
puts JSON.pretty_generate(ConceptQL::Converter.new.convert(criteria_from_file(file)))
|
76
|
+
rescue
|
77
|
+
puts "Couldn't convert #{file}"
|
78
|
+
puts $!.message
|
79
|
+
puts $!.backtrace.join("\n")
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
63
83
|
private
|
64
84
|
desc 'show_and_tell_db conceptql_id', 'Fetches the ConceptQL from a DB and shows the contents as a ConceptQL graph, then executes the statement against our test database'
|
65
85
|
option :full
|
86
|
+
option :watch_file
|
66
87
|
def show_and_tell_db(conceptql_id)
|
67
88
|
result = fetch_conceptql(conceptql_id, options)
|
68
89
|
puts "Concept: #{result[:label]}"
|
@@ -88,12 +109,11 @@ module ConceptQL
|
|
88
109
|
puts q.statement.to_yaml
|
89
110
|
puts 'JSON'
|
90
111
|
puts JSON.pretty_generate(q.statement)
|
91
|
-
STDIN.gets
|
92
112
|
graph_it(statement, title)
|
93
113
|
STDIN.gets
|
94
|
-
puts q.
|
114
|
+
puts q.sql
|
95
115
|
STDIN.gets
|
96
|
-
results = q.
|
116
|
+
results = q.all
|
97
117
|
if options[:full]
|
98
118
|
pp results
|
99
119
|
else
|
@@ -105,12 +125,18 @@ module ConceptQL
|
|
105
125
|
def graph_it(statement, title = nil)
|
106
126
|
require_relative 'graph'
|
107
127
|
require_relative 'tree'
|
128
|
+
conn = db(options)
|
108
129
|
ConceptQL::Graph.new(statement,
|
109
130
|
dangler: true,
|
110
131
|
title: title,
|
111
|
-
db:
|
132
|
+
db: conn
|
112
133
|
).graph_it('/tmp/graph')
|
113
134
|
system('open /tmp/graph.pdf')
|
135
|
+
if options[:watch_file]
|
136
|
+
require_relative 'debugger'
|
137
|
+
debugger = ConceptQL::Debugger.new(statement, db: conn, watch_ids: File.readlines(options[:watch_file]).map(&:to_i))
|
138
|
+
debugger.capture_results('/tmp/debug.xlsx')
|
139
|
+
end
|
114
140
|
end
|
115
141
|
|
116
142
|
def criteria_from_file(file)
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'facets/array/extract_options'
|
2
|
+
require 'facets/hash/deep_rekey'
|
3
|
+
require 'facets/hash/update_values'
|
4
|
+
|
5
|
+
module ConceptQL
|
6
|
+
class Converter
|
7
|
+
def convert(statement)
|
8
|
+
traverse(statement).to_list_syntax
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
class Operator
|
13
|
+
attr :type, :values, :options
|
14
|
+
def initialize(type, *values)
|
15
|
+
@type, @values = type, values.flatten
|
16
|
+
@options = @values.extract_options!.deep_rekey
|
17
|
+
@values = @values
|
18
|
+
end
|
19
|
+
|
20
|
+
def args
|
21
|
+
values.select { |s| !s.is_a?(Operator) }
|
22
|
+
end
|
23
|
+
|
24
|
+
def upstreams
|
25
|
+
values.select { |s| s.is_a?(Operator) }
|
26
|
+
end
|
27
|
+
|
28
|
+
def converted_options
|
29
|
+
options.update_values do |value|
|
30
|
+
if value.is_a?(Operator)
|
31
|
+
value.to_list_syntax
|
32
|
+
else
|
33
|
+
value
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def to_list_syntax
|
39
|
+
stmt = [type]
|
40
|
+
stmt += args unless args.empty?
|
41
|
+
stmt += upstreams.map(&:to_list_syntax) unless upstreams.empty?
|
42
|
+
stmt << converted_options unless options.empty?
|
43
|
+
stmt
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def traverse(obj)
|
48
|
+
case obj
|
49
|
+
when Hash
|
50
|
+
if obj.keys.length > 1
|
51
|
+
obj = Hash[obj.map { |key, value| [ key, traverse(value) ]}]
|
52
|
+
return obj
|
53
|
+
end
|
54
|
+
type = obj.keys.first
|
55
|
+
values = traverse(obj[type])
|
56
|
+
obj = Operator.new(type, values)
|
57
|
+
obj
|
58
|
+
when Array
|
59
|
+
obj.map { |value| traverse(value) }
|
60
|
+
else
|
61
|
+
obj
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require_relative 'tree'
|
2
|
+
require_relative 'operators/operator'
|
3
|
+
require_relative 'behaviors/debuggable'
|
4
|
+
|
5
|
+
module ConceptQL
|
6
|
+
class Debugger
|
7
|
+
attr :statement, :db, :watch_ids
|
8
|
+
def initialize(statement, opts = {})
|
9
|
+
@statement = statement
|
10
|
+
@db = opts.fetch(:db, nil)
|
11
|
+
@tree = opts.fetch(:tree, Tree.new)
|
12
|
+
ConceptQL::Operators::Operator.send(:include, ConceptQL::Behaviors::Debuggable)
|
13
|
+
@watch_ids = opts.fetch(:watch_ids, [])
|
14
|
+
raise "Please specify one or more person_ids you'd like to debug" unless @watch_ids
|
15
|
+
end
|
16
|
+
|
17
|
+
def capture_results(path)
|
18
|
+
raise "Please specify path for debug file" unless path
|
19
|
+
Dir.mktmpdir do |dir|
|
20
|
+
dir = Pathname.new(dir)
|
21
|
+
operators = tree.root(self)
|
22
|
+
operators.first.reset_operator_number
|
23
|
+
csv_files = operators.map.with_index do |last_operator, index|
|
24
|
+
last_operator.print_results(db, dir, watch_ids)
|
25
|
+
end.flatten
|
26
|
+
system("csv2xlsx #{path} #{csv_files.join(' ')}")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
attr :yaml, :tree, :db
|
32
|
+
|
33
|
+
def build_graph(g)
|
34
|
+
tree.root(self).each.with_index do |last_operator, index|
|
35
|
+
last_operator.graph_it(g, db)
|
36
|
+
if dangler
|
37
|
+
blank_operator = g.add_nodes("_#{index}")
|
38
|
+
blank_operator[:shape] = 'none'
|
39
|
+
blank_operator[:height] = 0
|
40
|
+
blank_operator[:label] = ''
|
41
|
+
blank_operator[:fixedsize] = true
|
42
|
+
last_operator.link_to(g, blank_operator, db)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|