canql 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.hound.yml +10 -0
- data/.rubocop.yml +10 -0
- data/.travis.yml +11 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +21 -0
- data/README.md +76 -0
- data/Rakefile +13 -0
- data/bin/console +11 -0
- data/bin/setup +7 -0
- data/canql.gemspec +39 -0
- data/code_safety.yml +201 -0
- data/lib/canql.rb +5 -0
- data/lib/canql/constants.rb +10 -0
- data/lib/canql/grammars.rb +12 -0
- data/lib/canql/grammars/age.treetop +23 -0
- data/lib/canql/grammars/anomaly.treetop +19 -0
- data/lib/canql/grammars/batch_types.treetop +11 -0
- data/lib/canql/grammars/dates.treetop +39 -0
- data/lib/canql/grammars/e_base_records.treetop +82 -0
- data/lib/canql/grammars/main.treetop +86 -0
- data/lib/canql/grammars/patient.treetop +55 -0
- data/lib/canql/grammars/registry.treetop +124 -0
- data/lib/canql/grammars/test_result.treetop +19 -0
- data/lib/canql/nodes.rb +20 -0
- data/lib/canql/nodes/age.rb +34 -0
- data/lib/canql/nodes/anomaly.rb +23 -0
- data/lib/canql/nodes/batch_types.rb +17 -0
- data/lib/canql/nodes/dates.rb +60 -0
- data/lib/canql/nodes/e_base_records.rb +60 -0
- data/lib/canql/nodes/main.rb +12 -0
- data/lib/canql/nodes/patient.rb +64 -0
- data/lib/canql/nodes/registry.rb +16 -0
- data/lib/canql/nodes/test_result.rb +21 -0
- data/lib/canql/parser.rb +41 -0
- data/lib/canql/treetop/extensions.rb +53 -0
- data/lib/canql/version.rb +6 -0
- metadata +261 -0
data/lib/canql.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'treetop'
|
3
|
+
|
4
|
+
Treetop.load File.expand_path('grammars/age', File.dirname(__FILE__))
|
5
|
+
Treetop.load File.expand_path('grammars/dates', File.dirname(__FILE__))
|
6
|
+
Treetop.load File.expand_path('grammars/anomaly', File.dirname(__FILE__))
|
7
|
+
Treetop.load File.expand_path('grammars/batch_types', File.dirname(__FILE__))
|
8
|
+
Treetop.load File.expand_path('grammars/e_base_records', File.dirname(__FILE__))
|
9
|
+
Treetop.load File.expand_path('grammars/test_result', File.dirname(__FILE__))
|
10
|
+
Treetop.load File.expand_path('grammars/patient', File.dirname(__FILE__))
|
11
|
+
Treetop.load File.expand_path('grammars/registry', File.dirname(__FILE__))
|
12
|
+
Treetop.load File.expand_path('grammars/main', File.dirname(__FILE__))
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Canql
|
2
|
+
grammar Age
|
3
|
+
rule with_birth_date
|
4
|
+
born_keyword fuzzy_date <Nodes::Age::BirthDateNode>
|
5
|
+
end
|
6
|
+
|
7
|
+
rule with_death_date
|
8
|
+
that_who_keyword? died_keyword fuzzy_date <Nodes::Age::DeathDateNode>
|
9
|
+
end
|
10
|
+
|
11
|
+
rule that_who_keyword
|
12
|
+
space ('that' / 'who') word_break
|
13
|
+
end
|
14
|
+
|
15
|
+
rule born_keyword
|
16
|
+
space ('born' / 'delivered') word_break
|
17
|
+
end
|
18
|
+
|
19
|
+
rule died_keyword
|
20
|
+
space 'died' word_break
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Canql
|
2
|
+
grammar Anomaly
|
3
|
+
rule anomalies
|
4
|
+
and_keyword? existance_modifier:anomalies_no_keyword? natal_period:anomalies_natal_period? anomalies_keyword <Nodes::Anomaly::Exists>
|
5
|
+
end
|
6
|
+
|
7
|
+
rule anomalies_no_keyword
|
8
|
+
space ('no' / 'some') word_break
|
9
|
+
end
|
10
|
+
|
11
|
+
rule anomalies_natal_period
|
12
|
+
(prenatal_keyword / postnatal_keyword)
|
13
|
+
end
|
14
|
+
|
15
|
+
rule anomalies_keyword
|
16
|
+
space 'anomalies' word_break
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Canql
|
2
|
+
grammar Dates
|
3
|
+
rule fuzzy_date
|
4
|
+
date:(between_dates / on_dates) word_break <Nodes::FuzzyDateNode>
|
5
|
+
end
|
6
|
+
|
7
|
+
rule on_dates
|
8
|
+
space ('on' / 'in') space date_fragment <Nodes::SpecificDateNode>
|
9
|
+
end
|
10
|
+
|
11
|
+
rule between_dates
|
12
|
+
space 'between' space start:date_fragment space 'and' space finish:date_fragment <Nodes::FragmentedDateRangeNode>
|
13
|
+
end
|
14
|
+
|
15
|
+
rule date_fragment
|
16
|
+
fragment:(daterange / year_quarter / chronic_date) word_break <Nodes::DateFragmentNode>
|
17
|
+
end
|
18
|
+
|
19
|
+
rule daterange
|
20
|
+
day_or_month? day_or_month? year <Nodes::DateRangeNode>
|
21
|
+
end
|
22
|
+
|
23
|
+
rule day_or_month
|
24
|
+
[0-9] 1..2 ('.' / '/')
|
25
|
+
end
|
26
|
+
|
27
|
+
rule year
|
28
|
+
[0-9] 4..4
|
29
|
+
end
|
30
|
+
|
31
|
+
rule year_quarter
|
32
|
+
'q' [1-4] space year <Nodes::YearQuarterNode>
|
33
|
+
end
|
34
|
+
|
35
|
+
rule chronic_date
|
36
|
+
(!(space ('and' / 'at' / 'with' / 'who')) .)+ <Nodes::ChronicDateNode>
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module Canql
|
2
|
+
grammar EBaseRecords
|
3
|
+
rule action_or_ebr
|
4
|
+
and_keyword? action_and_ebr / actions / e_base_records
|
5
|
+
end
|
6
|
+
|
7
|
+
rule action_and_ebr
|
8
|
+
actions and_keyword e_base_records
|
9
|
+
end
|
10
|
+
|
11
|
+
rule e_base_records
|
12
|
+
unprocessed_keyword types:batch_types? records_keyword <Nodes::EBaseRecordsNode>
|
13
|
+
end
|
14
|
+
|
15
|
+
rule batch_types
|
16
|
+
space allowed_types word_break <Nodes::BatchTypesNode>
|
17
|
+
end
|
18
|
+
|
19
|
+
rule allowed_types
|
20
|
+
batch_type types:more_types* <Nodes::AllowedTypesNode>
|
21
|
+
end
|
22
|
+
|
23
|
+
rule more_types
|
24
|
+
','? space? ('or' space)? batch_type <Nodes::MoreTypesNode>
|
25
|
+
end
|
26
|
+
|
27
|
+
rule with_keyword
|
28
|
+
space 'with' word_break
|
29
|
+
end
|
30
|
+
|
31
|
+
rule actions
|
32
|
+
action_type action_keyword action_provider? <Nodes::ActionsNode>
|
33
|
+
end
|
34
|
+
|
35
|
+
rule action_provider
|
36
|
+
space 'at' space provider:(action_provider_code / action_provider_name)
|
37
|
+
end
|
38
|
+
|
39
|
+
rule action_type
|
40
|
+
space accepted_action word_break
|
41
|
+
end
|
42
|
+
|
43
|
+
rule accepted_action
|
44
|
+
'wait' / 'proforma' / 'transfer' / 'notes' / 'child' /
|
45
|
+
'qa' / 'tag' / 'qc' / 'query' /
|
46
|
+
'moreinfo' / 'search' / 'check' / 'gpsearch'
|
47
|
+
end
|
48
|
+
|
49
|
+
rule action_keyword
|
50
|
+
space 'action' word_break
|
51
|
+
end
|
52
|
+
|
53
|
+
rule at_keyword
|
54
|
+
space 'at' word_break
|
55
|
+
end
|
56
|
+
|
57
|
+
rule action_provider_code
|
58
|
+
provider_type space code:(!' ' .)+ <Nodes::ActionProviderCodeNode>
|
59
|
+
end
|
60
|
+
|
61
|
+
rule action_provider_name
|
62
|
+
short_desc:(!(space provider_type) .)+ space provider_type <Nodes::ActionProviderNameNode>
|
63
|
+
end
|
64
|
+
|
65
|
+
# TODO: support cancer network?
|
66
|
+
rule provider_type
|
67
|
+
'hospital'
|
68
|
+
end
|
69
|
+
|
70
|
+
rule unprocessed_keyword
|
71
|
+
space 'unprocessed' word_break
|
72
|
+
end
|
73
|
+
|
74
|
+
rule records_keyword
|
75
|
+
space 'records' word_break
|
76
|
+
end
|
77
|
+
|
78
|
+
rule and_keyword
|
79
|
+
space 'and' word_break
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
grammar Canql
|
2
|
+
include Registry
|
3
|
+
include Patient
|
4
|
+
include Anomaly
|
5
|
+
include TestResult
|
6
|
+
include Dates
|
7
|
+
include EBaseRecords
|
8
|
+
include BatchTypes
|
9
|
+
include Age
|
10
|
+
|
11
|
+
# The root grammar
|
12
|
+
rule query
|
13
|
+
#quantity:record_count? pre:preconditions* cases_keyword post:additional_conditions*
|
14
|
+
quantity:record_count? pre:preconditions* cases_keyword post:additional_conditions* with_clause?
|
15
|
+
end
|
16
|
+
|
17
|
+
rule word_break
|
18
|
+
!(!(' '/',') .)
|
19
|
+
end
|
20
|
+
|
21
|
+
rule space
|
22
|
+
' '+
|
23
|
+
end
|
24
|
+
|
25
|
+
rule comma
|
26
|
+
space? (',' / 'and') space?
|
27
|
+
end
|
28
|
+
|
29
|
+
rule number
|
30
|
+
[0-9]+
|
31
|
+
end
|
32
|
+
|
33
|
+
rule record_count
|
34
|
+
all_keyword
|
35
|
+
/
|
36
|
+
'first' space number <Nodes::RecordCountNode>
|
37
|
+
end
|
38
|
+
|
39
|
+
rule all_keyword
|
40
|
+
'all' word_break
|
41
|
+
end
|
42
|
+
|
43
|
+
rule cases_keyword
|
44
|
+
space subject:('cases' / 'babies') word_break
|
45
|
+
end
|
46
|
+
|
47
|
+
rule preconditions
|
48
|
+
registry / gender / outcome
|
49
|
+
end
|
50
|
+
|
51
|
+
rule additional_conditions
|
52
|
+
and_keyword? (expected / with_birth_date / with_death_date)
|
53
|
+
end
|
54
|
+
|
55
|
+
rule with_clause
|
56
|
+
with_keyword post:with_conditions+
|
57
|
+
end
|
58
|
+
|
59
|
+
rule with_keyword
|
60
|
+
space 'with' word_break
|
61
|
+
end
|
62
|
+
|
63
|
+
rule and_keyword
|
64
|
+
space 'and' word_break
|
65
|
+
end
|
66
|
+
|
67
|
+
rule existance_keyword
|
68
|
+
space ('missing' / ('field' 's'?) / 'populated') word_break
|
69
|
+
end
|
70
|
+
|
71
|
+
rule no_keyword
|
72
|
+
space 'no' word_break
|
73
|
+
end
|
74
|
+
|
75
|
+
rule prenatal_keyword
|
76
|
+
space 'prenatal' word_break
|
77
|
+
end
|
78
|
+
|
79
|
+
rule postnatal_keyword
|
80
|
+
space 'postnatal' word_break
|
81
|
+
end
|
82
|
+
|
83
|
+
rule with_conditions
|
84
|
+
anomalies / test_results / patient_field_existance / mother_conditions / action_or_ebr
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Canql
|
2
|
+
grammar Patient
|
3
|
+
rule gender
|
4
|
+
space gender:('male' / 'female') word_break <Nodes::Patient::GenderNode>
|
5
|
+
end
|
6
|
+
|
7
|
+
rule outcome
|
8
|
+
space outcome:('stillborn' / 'liveborn' / 'miscarried' / 'terminated' / 'registrable' / 'non-registrable' ) word_break <Nodes::Patient::OutcomeNode>
|
9
|
+
end
|
10
|
+
|
11
|
+
rule expected_keyword
|
12
|
+
space ('expected' / 'due') word_break
|
13
|
+
end
|
14
|
+
|
15
|
+
rule expected
|
16
|
+
expected_keyword fuzzy_date <Nodes::Patient::ExpectedDateRangeNode>
|
17
|
+
end
|
18
|
+
|
19
|
+
rule patient_field_existance
|
20
|
+
and_keyword? field_existance_modifier:existance_keyword patient_field_list:patient_field_list <Nodes::Patient::FieldExists>
|
21
|
+
end
|
22
|
+
|
23
|
+
rule patient_fields_keyword
|
24
|
+
space 'field' 's'? word_break
|
25
|
+
end
|
26
|
+
|
27
|
+
rule patient_field_list
|
28
|
+
space patient_field_names (comma patient_field_names)*
|
29
|
+
end
|
30
|
+
|
31
|
+
rule patient_field_names
|
32
|
+
patient_field_name:('date of birth' / 'dob' / 'nhs number' / 'postcode' / 'birth weight' / 'place of delivery' / 'sex' / 'outcome')
|
33
|
+
end
|
34
|
+
|
35
|
+
rule mother_conditions
|
36
|
+
and_keyword? space subject:'mother' word_break mother_additional_conditions mother_with_clause?
|
37
|
+
end
|
38
|
+
|
39
|
+
rule mother_additional_conditions
|
40
|
+
mother_age_conditions*
|
41
|
+
end
|
42
|
+
|
43
|
+
rule mother_age_conditions
|
44
|
+
and_keyword? (with_birth_date / with_death_date)
|
45
|
+
end
|
46
|
+
|
47
|
+
rule mother_with_clause
|
48
|
+
with_keyword? post:mother_with_conditions+
|
49
|
+
end
|
50
|
+
|
51
|
+
rule mother_with_conditions
|
52
|
+
patient_field_existance
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
module Canql
|
2
|
+
grammar Registry
|
3
|
+
rule registry
|
4
|
+
space registry:(registry_code / registry_abbr) <Nodes::RegistryNode>
|
5
|
+
end
|
6
|
+
|
7
|
+
rule registry_code
|
8
|
+
[0-9] 2..2 <Nodes::RegistryCodeNode>
|
9
|
+
end
|
10
|
+
|
11
|
+
rule registry_abbr
|
12
|
+
(england / east_mids / thames / east / yorkshire / north_east / north_west /
|
13
|
+
west_mids / south_west / wessex / london / limbo)
|
14
|
+
end
|
15
|
+
|
16
|
+
rule thames
|
17
|
+
('thames valley' / 'thames')
|
18
|
+
{
|
19
|
+
def to_registrycode
|
20
|
+
'68'
|
21
|
+
end
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
rule east_mids
|
26
|
+
('east mids' / 'east midlands and south yorkshire' / 'east midlands')
|
27
|
+
{
|
28
|
+
def to_registrycode
|
29
|
+
'72'
|
30
|
+
end
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
34
|
+
rule yorkshire
|
35
|
+
'yorkshire'
|
36
|
+
{
|
37
|
+
def to_registrycode
|
38
|
+
'93'
|
39
|
+
end
|
40
|
+
}
|
41
|
+
end
|
42
|
+
|
43
|
+
rule north_east
|
44
|
+
'north east'
|
45
|
+
{
|
46
|
+
def to_registrycode
|
47
|
+
'73'
|
48
|
+
end
|
49
|
+
}
|
50
|
+
end
|
51
|
+
|
52
|
+
rule north_west
|
53
|
+
'north west'
|
54
|
+
{
|
55
|
+
def to_registrycode
|
56
|
+
'94'
|
57
|
+
end
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
61
|
+
rule west_mids
|
62
|
+
('west mids' / 'west midlands')
|
63
|
+
{
|
64
|
+
def to_registrycode
|
65
|
+
'99'
|
66
|
+
end
|
67
|
+
}
|
68
|
+
end
|
69
|
+
|
70
|
+
rule south_west
|
71
|
+
'south west'
|
72
|
+
{
|
73
|
+
def to_registrycode
|
74
|
+
'84'
|
75
|
+
end
|
76
|
+
}
|
77
|
+
end
|
78
|
+
|
79
|
+
rule wessex
|
80
|
+
'wessex'
|
81
|
+
{
|
82
|
+
def to_registrycode
|
83
|
+
'70'
|
84
|
+
end
|
85
|
+
}
|
86
|
+
end
|
87
|
+
|
88
|
+
rule london
|
89
|
+
('london and south east' / 'london')
|
90
|
+
{
|
91
|
+
def to_registrycode
|
92
|
+
'95'
|
93
|
+
end
|
94
|
+
}
|
95
|
+
end
|
96
|
+
|
97
|
+
rule east
|
98
|
+
('east of england' / 'east')
|
99
|
+
{
|
100
|
+
def to_registrycode
|
101
|
+
'96'
|
102
|
+
end
|
103
|
+
}
|
104
|
+
end
|
105
|
+
|
106
|
+
rule limbo
|
107
|
+
'limbo'
|
108
|
+
{
|
109
|
+
def to_registrycode
|
110
|
+
'01'
|
111
|
+
end
|
112
|
+
}
|
113
|
+
end
|
114
|
+
|
115
|
+
rule england
|
116
|
+
'england'
|
117
|
+
{
|
118
|
+
def to_registrycode
|
119
|
+
'00'
|
120
|
+
end
|
121
|
+
}
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|