conceptql 0.4.0 → 0.5.0

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.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +64 -0
  3. data/config/vocabularies.csv +87 -87
  4. data/doc/spec.md +1951 -0
  5. data/lib/conceptql/behaviors/utilizable.rb +0 -2
  6. data/lib/conceptql/cli.rb +1 -1
  7. data/lib/conceptql/data_model/base.rb +1 -167
  8. data/lib/conceptql/data_model.rb +20 -4
  9. data/lib/conceptql/database.rb +2 -0
  10. data/lib/conceptql/lexicon/lexicon_strategy.rb +23 -3
  11. data/lib/conceptql/lexicon.rb +9 -1
  12. data/lib/conceptql/operators/co_reported.rb +4 -31
  13. data/lib/conceptql/operators/hospice.rb +1 -2
  14. data/lib/conceptql/operators/hospitalization.rb +1 -2
  15. data/lib/conceptql/operators/information_periods.rb +1 -3
  16. data/lib/conceptql/operators/one_in_two_out.rb +1 -2
  17. data/lib/conceptql/operators/operator.rb +3 -11
  18. data/lib/conceptql/operators/provenance.rb +1 -2
  19. data/lib/conceptql/operators/race.rb +2 -6
  20. data/lib/conceptql/operators/read.rb +1 -100
  21. data/lib/conceptql/operators/snf.rb +1 -2
  22. data/lib/conceptql/operators/vocabulary.rb +15 -2
  23. data/lib/conceptql/paths.rb +6 -0
  24. data/lib/conceptql/query.rb +5 -2
  25. data/lib/conceptql/rdbms/duckdb.rb +0 -4
  26. data/lib/conceptql/rdbms/generic.rb +0 -4
  27. data/lib/conceptql/rdbms/postgres.rb +0 -4
  28. data/lib/conceptql/rdbms/spark.rb +0 -4
  29. data/lib/conceptql/utils.rb +0 -43
  30. data/lib/conceptql/version.rb +1 -1
  31. data/lib/conceptql/vocabularies/entry.rb +0 -20
  32. data/lib/conceptql/vocabularies/vocabulary_class_factory.rb +2 -15
  33. metadata +16 -13
  34. data/lib/conceptql/data_model/omopv4_plus.rb +0 -12
  35. data/lib/conceptql/query_modifiers/omopv4_plus/admission_date_query_modifier.rb +0 -45
  36. data/lib/conceptql/query_modifiers/omopv4_plus/drug_query_modifier.rb +0 -80
  37. data/lib/conceptql/query_modifiers/omopv4_plus/pos_query_modifier.rb +0 -47
  38. data/lib/conceptql/query_modifiers/omopv4_plus/provenance_query_modifier.rb +0 -45
  39. data/lib/conceptql/query_modifiers/omopv4_plus/provider_query_modifier.rb +0 -26
  40. data/lib/conceptql/sql_formatters/formatter.rb +0 -25
  41. data/lib/conceptql/sql_formatters.rb +0 -22
  42. data/lib/conceptql/vocabularies/behaviors/costish.rb +0 -24
  43. data/lib/conceptql/vocabularies/behaviors/omopish.rb +0 -32
  44. data/schemas/omopv4_plus.yml +0 -729
  45. data/schemas/omopv4_plus_more_ignorables.tsv +0 -13
@@ -5,8 +5,7 @@ require_relative "operator"
5
5
  module ConceptQL
6
6
  module Operators
7
7
  class Snf < Operator
8
- # GDM only: omopv4_plus has no provenance vocabularies (conceptql-myp).
9
- register __FILE__, :gdm, :gdm_wide
8
+ register __FILE__
10
9
  include ConceptQL::Behaviors::Utilizable
11
10
 
12
11
  desc "Selects admission records of type 'SNF'"
@@ -38,10 +38,23 @@ module ConceptQL
38
38
  args -= bad_arguments
39
39
 
40
40
  missing_args = args - dm.known_codes(db, vocabulary_id, args)
41
+ add_warning("unknown code(s)", *missing_args) unless missing_args.empty?
41
42
 
42
- return if missing_args.empty?
43
+ warn_about_reused_codes(db, args - missing_args)
44
+ end
43
45
 
44
- add_warning("unknown code(s)", *missing_args)
46
+ # A code that the vocabulary reused for a new meaning selects records of
47
+ # both meanings: DRG 410 selects chemotherapy stays before 2007-10-01 and
48
+ # biliary tract procedures after it (conceptql-ttk). Each item names the
49
+ # code and all of its names, so the user sees the problem without a
50
+ # vocabulary lookup.
51
+ def warn_about_reused_codes(db, codes)
52
+ meanings = dm.code_meanings(db, vocabulary_id, codes)
53
+ reused = codes.filter_map do |code|
54
+ names = meanings[code.downcase]
55
+ "#{code}: #{names.join(' | ')}" if names
56
+ end
57
+ add_warning("code(s) with more than one meaning", *reused) unless reused.empty?
45
58
  end
46
59
 
47
60
  def describe_codes(db, codes)
@@ -37,5 +37,11 @@ module ConceptQL
37
37
  def race_file
38
38
  ConceptQL.config_dir / "race.yml"
39
39
  end
40
+
41
+ # The ConceptQL specification, shipped in the gem for applications that
42
+ # serve it to readers (the Jigsaw diagram editor serves it over MCP).
43
+ def spec_path
44
+ root / "doc" / "spec.md"
45
+ end
40
46
  end
41
47
  end
@@ -4,7 +4,7 @@ require "json"
4
4
  require "forwardable"
5
5
  require_relative "scope"
6
6
  require_relative "nodifier"
7
- require_relative "sql_formatters"
7
+ require "sequel/sqlformat"
8
8
 
9
9
  module ConceptQL
10
10
  class Query
@@ -208,8 +208,11 @@ module ConceptQL
208
208
  end
209
209
  end
210
210
 
211
+ # Formats inside the Ruby process with the sequel-sqlformat gem (the Rust
212
+ # sqlformat crate). It changes only whitespace and keyword case, and it never
213
+ # fails on unknown syntax, so DuckDB and Spark SQL format too.
211
214
  def format(sql)
212
- SqlFormatters.format(sql, rdbms)
215
+ Sequel::SQLFormat.format(sql, dialect: Sequel::SQLFormat.dialect_for(cdb.database_type), indent: 2, uppercase: true)
213
216
  end
214
217
  end
215
218
  end
@@ -12,10 +12,6 @@ module ConceptQL
12
12
  Sequel.function(:datediff, "day", to, from)
13
13
  end
14
14
 
15
- def preferred_formatter
16
- SqlFormatters::PG_FORMAT
17
- end
18
-
19
15
  # DuckDB accepts WITH ... AS MATERIALIZED since v0.8.0.
20
16
  def supports_materialized?
21
17
  true
@@ -59,10 +59,6 @@ module ConceptQL
59
59
  end
60
60
  end
61
61
 
62
- def preferred_formatter
63
- SqlFormatters::SQL_FORMATTER
64
- end
65
-
66
62
  # Returns from - to in days, NOT to - from, so datediff(later, earlier)
67
63
  # is positive. Every adapter keeps this order. This default emits
68
64
  # Spark's datediff(endDate, startDate), which returns endDate - startDate,
@@ -14,10 +14,6 @@ module ConceptQL
14
14
  db.vacuum_table(table_name, analyze: true) if analyze_temp_tables?
15
15
  end
16
16
 
17
- def preferred_formatter
18
- SqlFormatters::POSTGRES
19
- end
20
-
21
17
  # DISTINCT ON is Postgres-only. The other adapters inherit
22
18
  # Generic#primary_concepts, which uses ROW_NUMBER() instead.
23
19
  def primary_concepts(db, all_primary_ids)
@@ -13,10 +13,6 @@ module ConceptQL
13
13
  def null_safe_equal(lhs, rhs)
14
14
  Sequel.lit("(? <=> ?)", lhs, rhs)
15
15
  end
16
-
17
- def preferred_formatter
18
- SqlFormatters::PG_FORMAT
19
- end
20
16
  end
21
17
  end
22
18
  end
@@ -4,8 +4,6 @@ require "active_support/core_ext/array/conversions"
4
4
  require "active_support/core_ext/object/blank"
5
5
  require "active_support/core_ext/string/inflections"
6
6
  require "json"
7
- require "open3"
8
- require "timeout"
9
7
 
10
8
  module ConceptQL
11
9
  module Utils
@@ -31,47 +29,6 @@ module ConceptQL
31
29
  end
32
30
  end
33
31
 
34
- def timed_capture(*commands)
35
- # Heavily adapted from:
36
- # https://gist.github.com/lpar/1032297#gistcomment-1738285
37
- opts = extract_opts!(commands)
38
- timeout = opts.fetch(:timeout)
39
-
40
- stdin, stdout, stderr, wait_thread = Open3.popen3(*commands)
41
- wait_thread[:timed_out] = false
42
- stdin.puts opts[:stdin_data] if opts[:stdin_data]
43
- stdin.close
44
-
45
- # Purposefully NOT using Timeout.rb because in general it is a dangerous API!
46
- # http://blog.headius.com/2008/02/rubys-threadraise-threadkill-timeoutrb.html
47
- Thread.new do
48
- sleep timeout
49
- if wait_thread.alive?
50
- begin
51
- wait_thread[:timed_out] = true
52
- # please note: we are assuming the command will create ONE process (not handling subprocs / proc groups)
53
- command = "kill -9 #{wait_thread.pid}"
54
- system(command)
55
- rescue(Errno::ESRCH)
56
- # Do nothing!
57
- end
58
- end
59
- end
60
-
61
- if (es = wait_thread.value.exitstatus) && !es.zero?
62
- raise stderr.read
63
- end
64
-
65
- out = stdout.read
66
- stdout.close
67
-
68
- if wait_thread[:timed_out]
69
- raise Timeout::Error, "Command #{commands} failed to complete after #{timeout} seconds"
70
- end
71
-
72
- out
73
- end
74
-
75
32
  def extract_opts!(arr)
76
33
  return {} unless arr.last.is_a?(Hash)
77
34
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ConceptQL
4
- VERSION = "0.4.0"
4
+ VERSION = "0.5.0"
5
5
  end
@@ -9,7 +9,6 @@ module ConceptQL
9
9
 
10
10
  METHODS = %i[
11
11
  id
12
- omopv4_vocabulary_id
13
12
  omopv5_vocabulary_id
14
13
  domain
15
14
  vocabulary_short_name
@@ -28,11 +27,6 @@ module ConceptQL
28
27
  predominant_domains
29
28
  ]
30
29
 
31
- COST_RELATED_VOCABS = [
32
- "Revenue Code",
33
- "DRG"
34
- ].freeze
35
-
36
30
  def initialize(hash)
37
31
  @hash = hash
38
32
  @hash[:omopv5_vocabulary_id] ||= @hash[:id]
@@ -54,12 +48,6 @@ module ConceptQL
54
48
  self.class.new(hash.merge(other_entry.hash))
55
49
  end
56
50
 
57
- def belongs_in_omopv4_plus?
58
- @belongs_in_omopv4_plus ||= (!from_lexicon? || from_csv?) \
59
- && has_domain? \
60
- && visible?
61
- end
62
-
63
51
  def to_hash
64
52
  METADATA_METHODS.to_h do |meth|
65
53
  [ meth, send(meth) ]
@@ -114,10 +102,6 @@ module ConceptQL
114
102
  hash[:domain] =~ /drug_exposure/i
115
103
  end
116
104
 
117
- def is_costish?
118
- belongs_in_omopv4_plus? && COST_RELATED_VOCABS.include?(omopv5_vocabulary_id)
119
- end
120
-
121
105
  def visible?
122
106
  !hidden?
123
107
  end
@@ -126,10 +110,6 @@ module ConceptQL
126
110
  omopv5_vocabulary_id || id
127
111
  end
128
112
 
129
- def omopv4_id
130
- omopv4_vocabulary_id
131
- end
132
-
133
113
  def get_klasses
134
114
  VocabularyClassFactory.new(self).get_klasses
135
115
  end
@@ -3,8 +3,6 @@
3
3
  require_relative "../behaviors/drugish"
4
4
  require_relative "../behaviors/labish"
5
5
  require_relative "behaviors/gdmish"
6
- require_relative "behaviors/omopish"
7
- require_relative "behaviors/costish"
8
6
  require_relative "../operators/vocabulary"
9
7
 
10
8
  module ConceptQL
@@ -19,9 +17,8 @@ module ConceptQL
19
17
  def get_klasses
20
18
  {
21
19
  gdm: get_gdm_klass,
22
- gdm_wide: get_gdm_klass,
23
- omopv4_plus: get_omopv4_plus_klass
24
- }.compact
20
+ gdm_wide: get_gdm_klass
21
+ }
25
22
  end
26
23
 
27
24
  def get_gdm_klass
@@ -30,16 +27,6 @@ module ConceptQL
30
27
  end
31
28
  end
32
29
 
33
- def get_omopv4_plus_klass
34
- return nil unless entry.belongs_in_omopv4_plus?
35
-
36
- get_klass do
37
- include Behaviors::Omopish
38
-
39
- include Behaviors::Costish if entry.is_costish?
40
- end
41
- end
42
-
43
30
  def get_klass(&block)
44
31
  ventry = entry
45
32
  Class.new(ConceptQL::Operators::Vocabulary) do |klass|
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: conceptql
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Duryea
@@ -79,6 +79,20 @@ dependencies:
79
79
  - - "~>"
80
80
  - !ruby/object:Gem::Version
81
81
  version: '5.66'
82
+ - !ruby/object:Gem::Dependency
83
+ name: sequel-sqlformat
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '0.1'
89
+ type: :runtime
90
+ prerelease: false
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '0.1'
82
96
  - !ruby/object:Gem::Dependency
83
97
  name: sequelizer
84
98
  requirement: !ruby/object:Gem::Requirement
@@ -314,6 +328,7 @@ files:
314
328
  - config/provenance.yml
315
329
  - config/race.yml
316
330
  - config/vocabularies.csv
331
+ - doc/spec.md
317
332
  - lib/conceptql.rb
318
333
  - lib/conceptql/behaviors/code_lister.rb
319
334
  - lib/conceptql/behaviors/drugish.rb
@@ -330,7 +345,6 @@ files:
330
345
  - lib/conceptql/data_model/base.rb
331
346
  - lib/conceptql/data_model/gdm.rb
332
347
  - lib/conceptql/data_model/gdm_wide.rb
333
- - lib/conceptql/data_model/omopv4_plus.rb
334
348
  - lib/conceptql/database.rb
335
349
  - lib/conceptql/date_adjuster.rb
336
350
  - lib/conceptql/diagram.rb
@@ -404,11 +418,6 @@ files:
404
418
  - lib/conceptql/query_modifiers/gdm_wide/lab_query_modifier.rb
405
419
  - lib/conceptql/query_modifiers/gdm_wide/pos_query_modifier.rb
406
420
  - lib/conceptql/query_modifiers/gdm_wide/provenance_query_modifier.rb
407
- - lib/conceptql/query_modifiers/omopv4_plus/admission_date_query_modifier.rb
408
- - lib/conceptql/query_modifiers/omopv4_plus/drug_query_modifier.rb
409
- - lib/conceptql/query_modifiers/omopv4_plus/pos_query_modifier.rb
410
- - lib/conceptql/query_modifiers/omopv4_plus/provenance_query_modifier.rb
411
- - lib/conceptql/query_modifiers/omopv4_plus/provider_query_modifier.rb
412
421
  - lib/conceptql/query_modifiers/query_modifier.rb
413
422
  - lib/conceptql/rdbms.rb
414
423
  - lib/conceptql/rdbms/duckdb.rb
@@ -416,15 +425,11 @@ files:
416
425
  - lib/conceptql/rdbms/postgres.rb
417
426
  - lib/conceptql/rdbms/spark.rb
418
427
  - lib/conceptql/scope.rb
419
- - lib/conceptql/sql_formatters.rb
420
- - lib/conceptql/sql_formatters/formatter.rb
421
428
  - lib/conceptql/utils.rb
422
429
  - lib/conceptql/utils_cli.rb
423
430
  - lib/conceptql/version.rb
424
431
  - lib/conceptql/visitors/metadata_extractor.rb
425
- - lib/conceptql/vocabularies/behaviors/costish.rb
426
432
  - lib/conceptql/vocabularies/behaviors/gdmish.rb
427
- - lib/conceptql/vocabularies/behaviors/omopish.rb
428
433
  - lib/conceptql/vocabularies/dynamic_vocabularies.rb
429
434
  - lib/conceptql/vocabularies/entry.rb
430
435
  - lib/conceptql/vocabularies/vocabulary_class_factory.rb
@@ -437,8 +442,6 @@ files:
437
442
  - schemas/gdm.yml
438
443
  - schemas/gdm_wide.yml
439
444
  - schemas/ohdsi_vocabs.yml
440
- - schemas/omopv4_plus.yml
441
- - schemas/omopv4_plus_more_ignorables.tsv
442
445
  homepage: https://github.com/outcomesinsights/conceptql
443
446
  licenses:
444
447
  - MIT
@@ -1,12 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "base"
4
- module ConceptQL
5
- module DataModel
6
- class Omopv4Plus < Base
7
- def base
8
- :omop
9
- end
10
- end
11
- end
12
- end
@@ -1,45 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "../query_modifier"
4
-
5
- module ConceptQL
6
- module QueryModifiers
7
- module Omopv4Plus
8
- class AdmissionDateQueryModifier < QueryModifier
9
- def self.provided_columns
10
- %i[
11
- admission_date
12
- discharge_date
13
- ]
14
- end
15
-
16
- def self.has_required_columns?(cols)
17
- cols.map(&:to_s).any? { |col| col =~ /start_date/i }
18
- end
19
-
20
- def modified_query
21
- cols = dm.table_cols(source_table).map(&:to_s)
22
- return query unless cols.any? { |col| col =~ /start_date/i }
23
-
24
- start_col = cols.find { |col| col =~ /start_date/i }.to_sym
25
- end_col = cols.find { |col| col =~ /end_date/i }.to_sym
26
-
27
- query.from_self(alias: :t)
28
- .select_all(:t)
29
- .select_append(Sequel[:t][start_col].as(:admission_date))
30
- .select_append(Sequel.function(:coalesce, Sequel[:t][end_col],
31
- Sequel[:t][start_col]).as(:discharge_date))
32
- .from_self
33
- end
34
-
35
- private
36
-
37
- def domain
38
- op.domain
39
- rescue StandardError
40
- nil
41
- end
42
- end
43
- end
44
- end
45
- end
@@ -1,80 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "../query_modifier"
4
-
5
- module ConceptQL
6
- module QueryModifiers
7
- module Omopv4Plus
8
- class DrugQueryModifier < QueryModifier
9
- attr_reader :db
10
-
11
- def self.provided_columns
12
- %i[
13
- drug_name
14
- drug_amount
15
- drug_amount_units
16
- drug_quantity
17
- drug_days_supply
18
- ]
19
- end
20
-
21
- def self.has_required_columns?(cols)
22
- needed = [ :drug_concept_id ]
23
- found = needed & cols
24
- needed == found
25
- end
26
-
27
- def initialize(*args)
28
- super
29
- @db = query.db
30
- end
31
-
32
- def modified_query
33
- return query unless dm.table_cols(source_table).include?(:drug_concept_id)
34
-
35
- query.db
36
- drug_concept_ids = query.select(:drug_concept_id).distinct
37
- query.from_self(alias: :de)
38
- .left_join(micro_table(drug_concept_ids).as(:mt), drug_concept_id: :drug_concept_id)
39
- .select_all(:de)
40
- .select_append(Sequel[:de][:quantity].as(:drug_quantity))
41
- .select_append(Sequel[:de][:days_supply].as(:drug_days_supply))
42
- .select_append(Sequel[:mt][:amount_value].as(:drug_amount))
43
- .select_append(Sequel[:mt][:amount_unit].as(:drug_amount_units))
44
- .select_append(Sequel[:mt][:drug_name].as(:drug_name))
45
- .from_self
46
- end
47
-
48
- private
49
-
50
- def micro_table(drug_concept_ids)
51
- # TODO: Does drug_strength only have RXNORM concept_ids?
52
- # TODO: What is vocabulary for units? Can we shrink concept table to just that vocab before joining?
53
- collapsed_strengths = db[:drug_strength]
54
- .where(drug_concept_id: drug_concept_ids)
55
- .select_group(:drug_concept_id)
56
- .select_append(
57
- Sequel.function(:min, :amount_value).as(:amount_value),
58
- Sequel.function(:min, :amount_unit).as(:amount_unit),
59
- Sequel.function(:count, 1).as(:dcount)
60
- )
61
-
62
- value_case = Sequel.case({ 1 => :amount_value }, nil, :dcount).as(:amount_value)
63
- unit_case = Sequel.case({ 1 => :amount_unit }, nil, :dcount).as(:amount_unit)
64
-
65
- collapsed_strengths = collapsed_strengths.from_self.select(:drug_concept_id, value_case, unit_case)
66
-
67
- db.from(Sequel[:concept].as(:dc))
68
- .left_join(collapsed_strengths, { drug_concept_id: :concept_id }, { table_alias: :ds })
69
- .where(Sequel[:dc][:concept_id] => drug_concept_ids)
70
- .select(
71
- Sequel[:dc][:concept_id].as(:drug_concept_id),
72
- Sequel[:dc][:concept_name].as(:drug_name),
73
- Sequel[:ds][:amount_value].as(:amount_value),
74
- Sequel[:ds][:amount_unit].as(:amount_unit)
75
- )
76
- end
77
- end
78
- end
79
- end
80
- end
@@ -1,47 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "../query_modifier"
4
-
5
- module ConceptQL
6
- module QueryModifiers
7
- module Omopv4Plus
8
- class PoSQueryModifier < QueryModifier
9
- attr_reader :join_id, :table, :source_column, :column
10
-
11
- def self.provided_columns
12
- [ :visit_source_concept_id ]
13
- end
14
-
15
- def self.has_required_columns?(cols)
16
- needed = [ :visit_occurrence_id ]
17
- found = needed & cols
18
- needed == found
19
- end
20
-
21
- def initialize(*args)
22
- super
23
- @column = :visit_source_concept_id
24
- @join_id = :visit_occurrence_id
25
- @table = :visit_occurrence
26
- @source_column = :visit_source_concept_id
27
- end
28
-
29
- def modified_query
30
- return query unless dm.table_cols(source_table).include?(join_id)
31
- return query if dm.table_cols(source_table).include?(column)
32
-
33
- left_alias = "tab1".to_sym
34
- right_alias = "tab2".to_sym
35
-
36
- extra_table = query.db.from(table).select(Sequel.as(source_column, column), join_id)
37
- ds = query.from_self(alias: left_alias)
38
- ds.left_join(extra_table.as(right_alias),
39
- Sequel.qualify(left_alias, join_id) => Sequel.qualify(right_alias, join_id))
40
- .select_all(left_alias)
41
- .select_append(Sequel.qualify(right_alias, column).as(column))
42
- .from_self
43
- end
44
- end
45
- end
46
- end
47
- end
@@ -1,45 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "../query_modifier"
4
-
5
- module ConceptQL
6
- module QueryModifiers
7
- module Omopv4Plus
8
- class ProvenanceQueryModifier < QueryModifier
9
- RELATED_COLUMNS = %w[
10
- condition_type_concept_id
11
- procedure_type_concept_id
12
- death_type_concept_id
13
- observation_type_concept_id
14
- drug_type_concept_id
15
- ].sort.map(&:to_sym)
16
-
17
- attr_reader :db
18
-
19
- def self.provided_columns
20
- %i[
21
- file_provenance_type
22
- code_provenance_type
23
- ]
24
- end
25
-
26
- def self.has_required_columns?(cols)
27
- !(RELATED_COLUMNS & cols).empty?
28
- end
29
-
30
- def initialize(*args)
31
- super
32
- @db = query.db
33
- end
34
-
35
- def modified_query
36
- return query unless self.class.has_required_columns?(dm.table_cols(source_table))
37
-
38
- query.select_append(Sequel[dm.file_provenance_type_column(query, source_table)].as(:file_provenance_type),
39
- Sequel[dm.code_provenance_type_column(query,
40
- source_table)].as(:code_provenance_type)).from_self
41
- end
42
- end
43
- end
44
- end
45
- end
@@ -1,26 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "../query_modifier"
4
-
5
- module ConceptQL
6
- module QueryModifiers
7
- module Omopv4Plus
8
- class ProviderQueryModifier < QueryModifier
9
- def self.provided_columns
10
- [ :provider_id ]
11
- end
12
-
13
- def self.has_required_columns?(cols)
14
- cols.find { |col| col.to_s =~ /provider_id/ }
15
- end
16
-
17
- def modified_query
18
- col = self.class.has_required_columns?(dm.table_cols(source_table))
19
- return query if col.nil? || col.to_sym == :provider_id
20
-
21
- query.select_append(Sequel[col].as(:provider_id)).from_self
22
- end
23
- end
24
- end
25
- end
26
- end
@@ -1,25 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module ConceptQL
4
- module SqlFormatters
5
- # An external SQL formatter, given as a command array that reads SQL on
6
- # stdin, e.g. Formatter.new(%w[sql-formatter -l postgresql]).
7
- class Formatter
8
- attr_reader :command
9
-
10
- def initialize(command)
11
- @command = command
12
- end
13
-
14
- def available?
15
- system("which", command.first, out: File::NULL, err: File::NULL)
16
- end
17
-
18
- def format(sql)
19
- ConceptQL::Utils.timed_capture(*command, stdin_data: sql, timeout: 10)
20
- rescue Timeout::Error
21
- sql
22
- end
23
- end
24
- end
25
- end
@@ -1,22 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "sql_formatters/formatter"
4
-
5
- module ConceptQL
6
- module SqlFormatters
7
- SQL_FORMATTER = %w[sql-formatter].freeze
8
- POSTGRES = %w[sql-formatter -l postgresql].freeze
9
- SQLFORMAT = %w[sqlformat --reindent --use_space_around_operators --identifiers lower --keywords upper -].freeze
10
- PG_FORMAT = %w[pg_format].freeze
11
-
12
- # Formats with the rdbms's preferred formatter, else the first of the
13
- # fallbacks that is installed, else returns the SQL untouched.
14
- def self.format(sql, rdbms)
15
- formatter = [ rdbms.preferred_formatter, SQL_FORMATTER, SQLFORMAT, PG_FORMAT ]
16
- .compact
17
- .map { |command| Formatter.new(command) }
18
- .detect(&:available?)
19
- formatter ? formatter.format(sql) : sql
20
- end
21
- end
22
- end