nuva 0.3.0 → 0.3.1
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 +7 -0
- data/lib/nuva/queries.rb +96 -83
- data/lib/nuva/repositories/valence_repository.rb +1 -1
- data/lib/nuva/repository.rb +11 -14
- data/lib/nuva/version.rb +1 -1
- data/lib/nuva.rb +89 -74
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6005455d2bcaf93b115e51352c8d22dda90954c086f0ed5d378f9bbafcca2cf9
|
4
|
+
data.tar.gz: 7430a09df08aab2786ea0433a51ebc86ca77a2718b26532a7591bed2edb660a3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c5852e5006e7de76aed2a716c8559398eba7eaf67df19ae4bc17b449675b89fee3f4ce0201c3861a80f1de36a3d6fc4d77db237ab6754e7c0ee1a7520cb8c600
|
7
|
+
data.tar.gz: 1a67a955a8dc79d3219cefdbb7432ce4ad1312356a77e8a13a437a35228739e099bbc11b8dd2462ee6ae157b0349cab88f80e4b1f6e11eaa719ae42d0703e556
|
data/Changelog.md
CHANGED
@@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
7
7
|
|
8
|
+
## [0.3.1] - 2025-01-17
|
9
|
+
|
10
|
+
### Changed
|
11
|
+
|
12
|
+
- Add 'Query' suffix all query classes
|
13
|
+
- Inherit from common Query class with sensible implementation of `inspect` method
|
14
|
+
|
8
15
|
## [0.3.0] - 2025-01-17
|
9
16
|
|
10
17
|
### Added
|
data/lib/nuva/queries.rb
CHANGED
@@ -1,18 +1,27 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "fuzzy_match"
|
4
4
|
|
5
5
|
module Nuva
|
6
6
|
module Queries
|
7
|
-
class
|
7
|
+
class Query
|
8
|
+
def inspect
|
9
|
+
"#<#{self.class.name}>"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class ValencesByVaccineQuery < Query
|
8
14
|
def initialize(repositories)
|
9
15
|
hash = Hash.new { |h, k| h[k] = [] }
|
10
|
-
@valences_by_vaccine_id =
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
+
@valences_by_vaccine_id =
|
17
|
+
repositories[:valences]
|
18
|
+
.all
|
19
|
+
.reduce(hash) do |acc, valence|
|
20
|
+
valence.vaccine_ids.each do |vaccine_id|
|
21
|
+
acc[vaccine_id] << valence
|
22
|
+
end
|
23
|
+
acc
|
24
|
+
end
|
16
25
|
end
|
17
26
|
|
18
27
|
def call(vaccine)
|
@@ -20,15 +29,18 @@ module Nuva
|
|
20
29
|
end
|
21
30
|
end
|
22
31
|
|
23
|
-
class
|
32
|
+
class VaccinesByValenceQuery < Query
|
24
33
|
def initialize(repositories)
|
25
34
|
hash = Hash.new { |h, k| h[k] = [] }
|
26
|
-
@vaccines_by_valence_id =
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
35
|
+
@vaccines_by_valence_id =
|
36
|
+
repositories[:vaccines]
|
37
|
+
.all
|
38
|
+
.reduce(hash) do |acc, vaccine|
|
39
|
+
vaccine.valence_ids.each do |valence_id|
|
40
|
+
acc[valence_id] << vaccine
|
41
|
+
end
|
42
|
+
acc
|
43
|
+
end
|
32
44
|
end
|
33
45
|
|
34
46
|
def call(valence)
|
@@ -36,17 +48,20 @@ module Nuva
|
|
36
48
|
end
|
37
49
|
end
|
38
50
|
|
39
|
-
class
|
51
|
+
class VaccinesByDiseaseQuery < Query
|
40
52
|
def initialize(repositories)
|
41
53
|
hash = Hash.new { |h, k| h[k] = [] }
|
42
|
-
@vaccines_by_disease_id =
|
43
|
-
|
44
|
-
|
45
|
-
|
54
|
+
@vaccines_by_disease_id =
|
55
|
+
repositories[:valences]
|
56
|
+
.all
|
57
|
+
.reduce(hash) do |acc, valence|
|
58
|
+
valence.disease_ids.each do |disease_id|
|
59
|
+
valence.vaccine_ids.each do |vaccine_id|
|
60
|
+
acc[disease_id] << repositories[:vaccines].find(vaccine_id)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
acc
|
46
64
|
end
|
47
|
-
end
|
48
|
-
acc
|
49
|
-
end
|
50
65
|
end
|
51
66
|
|
52
67
|
def call(disease)
|
@@ -54,15 +69,18 @@ module Nuva
|
|
54
69
|
end
|
55
70
|
end
|
56
71
|
|
57
|
-
class
|
72
|
+
class ValencesByDiseaseQuery < Query
|
58
73
|
def initialize(repositories)
|
59
74
|
hash = Hash.new { |h, k| h[k] = [] }
|
60
|
-
@valences_by_disease_id =
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
75
|
+
@valences_by_disease_id =
|
76
|
+
repositories[:valences]
|
77
|
+
.all
|
78
|
+
.reduce(hash) do |acc, valence|
|
79
|
+
valence.disease_ids.each do |disease_id|
|
80
|
+
acc[disease_id] << valence
|
81
|
+
end
|
82
|
+
acc
|
83
|
+
end
|
66
84
|
end
|
67
85
|
|
68
86
|
def call(disease)
|
@@ -70,17 +88,20 @@ module Nuva
|
|
70
88
|
end
|
71
89
|
end
|
72
90
|
|
73
|
-
class
|
91
|
+
class DiseasesByVaccineQuery < Query
|
74
92
|
def initialize(repositories)
|
75
93
|
hash = Hash.new { |h, k| h[k] = [] }
|
76
|
-
@diseases_by_vaccine_id =
|
77
|
-
|
78
|
-
|
79
|
-
|
94
|
+
@diseases_by_vaccine_id =
|
95
|
+
repositories[:valences]
|
96
|
+
.all
|
97
|
+
.reduce(hash) do |acc, valence|
|
98
|
+
valence.vaccine_ids.each do |vaccine_id|
|
99
|
+
valence.disease_ids.each do |disease_id|
|
100
|
+
acc[vaccine_id] << repositories[:diseases].find(disease_id)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
acc
|
80
104
|
end
|
81
|
-
end
|
82
|
-
acc
|
83
|
-
end
|
84
105
|
end
|
85
106
|
|
86
107
|
def call(vaccine)
|
@@ -88,15 +109,18 @@ module Nuva
|
|
88
109
|
end
|
89
110
|
end
|
90
111
|
|
91
|
-
class
|
112
|
+
class DiseasesByValenceQuery < Query
|
92
113
|
def initialize(repositories)
|
93
114
|
hash = Hash.new { |h, k| h[k] = [] }
|
94
|
-
@diseases_by_valence_id =
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
115
|
+
@diseases_by_valence_id =
|
116
|
+
repositories[:diseases]
|
117
|
+
.all
|
118
|
+
.reduce(hash) do |acc, disease|
|
119
|
+
disease.valence_ids.each do |valence_id|
|
120
|
+
acc[valence_id] << disease
|
121
|
+
end
|
122
|
+
acc
|
123
|
+
end
|
100
124
|
end
|
101
125
|
|
102
126
|
def call(valence)
|
@@ -104,11 +128,10 @@ module Nuva
|
|
104
128
|
end
|
105
129
|
end
|
106
130
|
|
107
|
-
class
|
131
|
+
class VaccineFuzzySearchQuery < Query
|
108
132
|
def initialize(repositories)
|
109
|
-
@engine =
|
110
|
-
v.name
|
111
|
-
})
|
133
|
+
@engine =
|
134
|
+
FuzzyMatch.new(repositories.vaccines.all, read: ->(v) { v.name })
|
112
135
|
end
|
113
136
|
|
114
137
|
def call(pattern)
|
@@ -116,28 +139,19 @@ module Nuva
|
|
116
139
|
end
|
117
140
|
end
|
118
141
|
|
119
|
-
|
120
|
-
# lookupEquivalentVaccines(vaccine: Vaccine): Vaccine[];
|
121
|
-
# lookupSpecializedVaccines(vaccine: Vaccine): Vaccine[];
|
122
|
-
# lookupGeneralizedVaccines(vaccine: Vaccine): Vaccine[];
|
123
|
-
# allNomenclatures(): string[];
|
124
|
-
# allCodeByNomenclature(): {
|
125
|
-
# [nomenclature: string]: Code[];
|
126
|
-
# };
|
127
|
-
|
128
|
-
class LookupVaccineByCode
|
142
|
+
class LookupVaccineByCodeQuery < Query
|
129
143
|
def initialize(repositories)
|
130
144
|
@vaccines = repositories.vaccines
|
131
145
|
end
|
132
146
|
|
133
147
|
def call(code)
|
134
148
|
@vaccines.all.find do |vac|
|
135
|
-
"NUVA-#{vac.code}" == code || vac.codes.any?
|
149
|
+
"NUVA-#{vac.code}" == code || vac.codes.any? { |x| x.value == code }
|
136
150
|
end
|
137
151
|
end
|
138
152
|
end
|
139
153
|
|
140
|
-
class
|
154
|
+
class LookupEquivalentVaccinesQuery < Query
|
141
155
|
def initialize(repositories)
|
142
156
|
@vaccines = repositories.vaccines
|
143
157
|
end
|
@@ -145,12 +159,13 @@ module Nuva
|
|
145
159
|
def call(vaccine)
|
146
160
|
vids = vaccine.valence_ids.sort
|
147
161
|
@vaccines.all.filter do |v|
|
148
|
-
v.valence_ids.length == vids.length && v.id != vaccine.id &&
|
162
|
+
v.valence_ids.length == vids.length && v.id != vaccine.id &&
|
163
|
+
vids == v.valence_ids.sort
|
149
164
|
end
|
150
165
|
end
|
151
166
|
end
|
152
167
|
|
153
|
-
class
|
168
|
+
class LookupGeneralizedVaccinesQuery < Query
|
154
169
|
def initialize(repositories, valencesByVaccine)
|
155
170
|
@vaccines = repositories.vaccines
|
156
171
|
@valences = repositories.valences
|
@@ -159,16 +174,19 @@ module Nuva
|
|
159
174
|
|
160
175
|
def call(vaccine)
|
161
176
|
targetValences = @valencesByVaccine.(vaccine)
|
162
|
-
list =
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
177
|
+
list =
|
178
|
+
@vaccines.all.filter do |candidate|
|
179
|
+
next if candidate.id == vaccine.id || !candidate.generic
|
180
|
+
|
181
|
+
@valencesByVaccine
|
182
|
+
.(candidate)
|
183
|
+
.all? do |candidateValence|
|
184
|
+
targetValences.any? do |targetValence|
|
185
|
+
parent_of?(candidateValence, targetValence)
|
186
|
+
end
|
187
|
+
end
|
169
188
|
end
|
170
|
-
|
171
|
-
list.sort_by do |v| -@valencesByVaccine.(v).length end
|
189
|
+
list.sort_by { |v| -@valencesByVaccine.(v).length }
|
172
190
|
end
|
173
191
|
|
174
192
|
private def child_of?(valence, parent)
|
@@ -176,7 +194,7 @@ module Nuva
|
|
176
194
|
return true if valence.id == parent.id
|
177
195
|
valence = @valences.find(valence.parent_id)
|
178
196
|
end
|
179
|
-
|
197
|
+
|
180
198
|
false
|
181
199
|
end
|
182
200
|
|
@@ -185,19 +203,17 @@ module Nuva
|
|
185
203
|
end
|
186
204
|
end
|
187
205
|
|
188
|
-
class
|
206
|
+
class AllNomenclaturesQuery < Query
|
189
207
|
def initialize(repositories)
|
190
208
|
@vaccines = repositories.vaccines
|
191
209
|
end
|
192
210
|
|
193
211
|
def call
|
194
|
-
(@vaccines.all.flat_map
|
195
|
-
v.codes.map(&:nomenclature)
|
196
|
-
end).uniq
|
212
|
+
(@vaccines.all.flat_map { |v| v.codes.map(&:nomenclature) }).uniq
|
197
213
|
end
|
198
214
|
end
|
199
215
|
|
200
|
-
class
|
216
|
+
class AllCodeByNomenclatureQuery < Query
|
201
217
|
def initialize(repositories)
|
202
218
|
@vaccines = repositories.vaccines
|
203
219
|
end
|
@@ -206,16 +222,13 @@ module Nuva
|
|
206
222
|
@vaccines
|
207
223
|
.all
|
208
224
|
.flat_map(&:codes)
|
209
|
-
.reduce(Hash.new { |hash, key| hash[key] = [] })
|
210
|
-
|hash, code|
|
211
|
-
|
225
|
+
.reduce(Hash.new { |hash, key| hash[key] = [] }) do |hash, code|
|
212
226
|
hash[code.nomenclature] << code.value
|
213
227
|
hash
|
214
|
-
|
228
|
+
end
|
215
229
|
.map { |key, value| [key, value.uniq] }
|
216
230
|
.to_h
|
217
231
|
end
|
218
232
|
end
|
219
|
-
|
220
233
|
end
|
221
234
|
end
|
data/lib/nuva/repository.rb
CHANGED
@@ -2,24 +2,21 @@
|
|
2
2
|
|
3
3
|
module Nuva
|
4
4
|
class Repository
|
5
|
-
attr_reader :
|
5
|
+
attr_reader :all
|
6
6
|
|
7
7
|
def initialize(data)
|
8
|
-
@
|
9
|
-
|
10
|
-
@
|
11
|
-
|
12
|
-
|
13
|
-
|
8
|
+
@count = data.count
|
9
|
+
@all = data
|
10
|
+
@index = {}
|
11
|
+
data.each do |item|
|
12
|
+
@index[item.code] = item
|
13
|
+
@index[item.id.to_sym] = item
|
14
|
+
@index[item.id.to_s] = item
|
15
|
+
end
|
14
16
|
end
|
15
17
|
|
16
18
|
def find(id_or_code)
|
17
|
-
@
|
18
|
-
@data_by_string_id[id_or_code]
|
19
|
-
end
|
20
|
-
|
21
|
-
def all
|
22
|
-
@data_by_symbol_id.values
|
19
|
+
@index[id_or_code]
|
23
20
|
end
|
24
21
|
|
25
22
|
def by_ids(ids)
|
@@ -27,7 +24,7 @@ module Nuva
|
|
27
24
|
end
|
28
25
|
|
29
26
|
def inspect
|
30
|
-
"#<#{self.class.name} count=#{@
|
27
|
+
"#<#{self.class.name} count=#{@count}>"
|
31
28
|
end
|
32
29
|
end
|
33
30
|
end
|
data/lib/nuva/version.rb
CHANGED
data/lib/nuva.rb
CHANGED
@@ -1,80 +1,95 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative
|
4
|
-
require_relative
|
5
|
-
require_relative
|
6
|
-
require_relative
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
3
|
+
require_relative "nuva/version"
|
4
|
+
require_relative "nuva/NuvaDatabase_pb"
|
5
|
+
require_relative "nuva/repository"
|
6
|
+
require_relative "nuva/queries"
|
7
|
+
require "net/http"
|
8
|
+
require "json"
|
9
|
+
require "ostruct"
|
10
10
|
|
11
11
|
module Nuva
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
req = ::Net::HTTP::Get.new latest_version_uri
|
53
|
-
|
54
|
-
res = http.request req
|
55
|
-
res.value
|
56
|
-
|
57
|
-
manifest = JSON.parse(res.body)
|
58
|
-
|
59
|
-
dump_hash = manifest['dump_hash']
|
60
|
-
|
61
|
-
# Fetch latest database
|
62
|
-
dump_uri = latest_version_uri.dup
|
63
|
-
dump_uri.path = "/proto/#{dump_hash}_#{lang}.db"
|
64
|
-
|
65
|
-
req = ::Net::HTTP::Get.new dump_uri
|
66
|
-
|
67
|
-
res = http.request req
|
68
|
-
res.value
|
69
|
-
|
70
|
-
# The return value of the block is returned by the start method
|
71
|
-
::Nuva::Nuva.new(::Nuva::NuvaDatabase.decode(res.body))
|
72
|
-
end
|
73
|
-
|
74
|
-
end
|
75
|
-
|
76
|
-
def self.load_from_file(path)
|
77
|
-
Nuva.new(NuvaDatabase.decode(File.read(path)))
|
78
|
-
end
|
12
|
+
class Nuva
|
13
|
+
attr_reader :repositories
|
14
|
+
attr_reader :queries
|
15
|
+
|
16
|
+
def initialize(db)
|
17
|
+
@db = db
|
18
|
+
|
19
|
+
@repositories = OpenStruct.new
|
20
|
+
@repositories.vaccines = VaccineRepository.new db.vaccines
|
21
|
+
@repositories.valences = ValenceRepository.new db.valences
|
22
|
+
@repositories.diseases = DiseaseRepository.new db.diseases
|
23
|
+
@repositories.freeze
|
24
|
+
|
25
|
+
@queries = OpenStruct.new
|
26
|
+
@queries.valences_by_vaccine =
|
27
|
+
::Nuva::Queries::ValencesByVaccineQuery.new @repositories
|
28
|
+
@queries.vaccines_by_valence =
|
29
|
+
::Nuva::Queries::VaccinesByValenceQuery.new @repositories
|
30
|
+
@queries.vaccines_by_disease =
|
31
|
+
::Nuva::Queries::VaccinesByDiseaseQuery.new @repositories
|
32
|
+
@queries.valences_by_disease =
|
33
|
+
::Nuva::Queries::ValencesByDiseaseQuery.new @repositories
|
34
|
+
@queries.diseases_by_vaccine =
|
35
|
+
::Nuva::Queries::DiseasesByVaccineQuery.new @repositories
|
36
|
+
@queries.diseases_by_valence =
|
37
|
+
::Nuva::Queries::DiseasesByValenceQuery.new @repositories
|
38
|
+
@queries.vaccine_fuzzy_search =
|
39
|
+
::Nuva::Queries::VaccineFuzzySearchQuery.new @repositories
|
40
|
+
@queries.lookup_vaccine_by_code =
|
41
|
+
::Nuva::Queries::LookupVaccineByCodeQuery.new @repositories
|
42
|
+
@queries.lookup_equivalent_vaccines =
|
43
|
+
::Nuva::Queries::LookupEquivalentVaccinesQuery.new @repositories
|
44
|
+
@queries.lookup_generalized_vaccines =
|
45
|
+
::Nuva::Queries::LookupGeneralizedVaccinesQuery.new @repositories,
|
46
|
+
@queries.valences_by_vaccine
|
47
|
+
@queries.all_nomenclatures =
|
48
|
+
::Nuva::Queries::AllNomenclaturesQuery.new @repositories
|
49
|
+
@queries.all_code_by_nomenclature =
|
50
|
+
::Nuva::Queries::AllCodeByNomenclatureQuery.new @repositories
|
51
|
+
@queries.freeze
|
79
52
|
end
|
53
|
+
|
54
|
+
def version
|
55
|
+
@db.version
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.load(lang = "en")
|
59
|
+
latest_version_uri =
|
60
|
+
URI "https://cdnnuva.mesvaccins.net/versions/last.json"
|
61
|
+
|
62
|
+
::Net::HTTP.start(
|
63
|
+
latest_version_uri.host,
|
64
|
+
latest_version_uri.port,
|
65
|
+
use_ssl: latest_version_uri.scheme == "https"
|
66
|
+
) do |http|
|
67
|
+
# Fetch version manifest
|
68
|
+
req = ::Net::HTTP::Get.new latest_version_uri
|
69
|
+
|
70
|
+
res = http.request req
|
71
|
+
res.value
|
72
|
+
|
73
|
+
manifest = JSON.parse(res.body)
|
74
|
+
|
75
|
+
dump_hash = manifest["dump_hash"]
|
76
|
+
|
77
|
+
# Fetch latest database
|
78
|
+
dump_uri = latest_version_uri.dup
|
79
|
+
dump_uri.path = "/proto/#{dump_hash}_#{lang}.db"
|
80
|
+
|
81
|
+
req = ::Net::HTTP::Get.new dump_uri
|
82
|
+
|
83
|
+
res = http.request req
|
84
|
+
res.value
|
85
|
+
|
86
|
+
# The return value of the block is returned by the start method
|
87
|
+
::Nuva::Nuva.new(::Nuva::NuvaDatabase.decode(res.body))
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def self.load_from_file(path)
|
92
|
+
Nuva.new(NuvaDatabase.decode(File.read(path)))
|
93
|
+
end
|
94
|
+
end
|
80
95
|
end
|