inat-get 0.9.0.8 → 0.9.0.10
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/.yardopts +12 -0
- data/.yardpreamble.rb +15 -0
- data/coverage-badge.svg +6 -0
- data/lib/inat-get/app/maintenance.rb +2 -2
- data/lib/inat-get/data/dsl/dataset.rb +40 -5
- data/lib/inat-get/data/dsl/dsl.rb +11 -0
- data/lib/inat-get/data/dsl/list.rb +22 -3
- data/lib/inat-get/data/models/base.rb +2 -0
- data/lib/inat-get/data/models/place.rb +1 -1
- data/lib/inat-get/data/models/project.rb +1 -1
- data/lib/inat-get/data/updaters/base.rb +22 -3
- data/lib/inat-get/info.rb +1 -1
- data/share/inat-get/db/migrations/002_nullable_slug.rb +13 -0
- metadata +5 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 375524ed9be224c8d856b640812d33d449cc0306c7e3ae6f1366b720aa8f5156
|
|
4
|
+
data.tar.gz: d1917c1ef4b018535912c464ce491ac620068389f5c6f7107c24a0a5def577be
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b7800a7d299c507d2db2931e5cf7e617bdac8dac27b02b3461363b7487f4dfa5ed62f94fb15d4dd910a8bdeb01a470f1b1f6d345069cf618d8f7f151af414e17
|
|
7
|
+
data.tar.gz: 4b66a9790d97d26197d412f042e253fa2ccd4ed9fddfe4c0251127eafc13b8b9cefa0edd87a254fb42980d6c46543cfbe80a190ed878147cafb96db487c46d4d
|
data/.yardopts
ADDED
data/.yardpreamble.rb
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
ENV['SEQUEL_MIGRATIONS_DIR'] = './share/inat-get/db/migrations/'
|
|
2
|
+
|
|
3
|
+
module WF
|
|
4
|
+
|
|
5
|
+
def warn message, category = nil, **kwargs
|
|
6
|
+
case message
|
|
7
|
+
when /literal string will be frozen in the future/, /character class has duplicated range/, /yardpreamble/
|
|
8
|
+
# do nothing
|
|
9
|
+
else
|
|
10
|
+
super message
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
end
|
|
15
|
+
Warning.extend WF
|
data/coverage-badge.svg
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<?xml version="1.0"?><svg xmlns="http://www.w3.org/2000/svg" width="100" height="20">
|
|
2
|
+
<rect width="100" height="20" fill="#555"/>
|
|
3
|
+
<rect x="63" width="37" height="20" fill="red"/>
|
|
4
|
+
<text x="8" y="14" fill="#fff" font-family="Verdana" font-size="11">coverage</text>
|
|
5
|
+
<text x="66" y="14" fill="#fff" font-family="Verdana" font-size="11">68%</text>
|
|
6
|
+
</svg>
|
|
@@ -69,7 +69,7 @@ module INatGet::App::Maintenance
|
|
|
69
69
|
end
|
|
70
70
|
|
|
71
71
|
def db_update config
|
|
72
|
-
|
|
72
|
+
run_migrations config
|
|
73
73
|
exit Errno::NOERROR::Errno
|
|
74
74
|
end
|
|
75
75
|
|
|
@@ -79,7 +79,7 @@ module INatGet::App::Maintenance
|
|
|
79
79
|
$stderr.puts "❌ \e[1mVersion must be an integer\e[0m"
|
|
80
80
|
exit Errno::ECANCELED::Errno
|
|
81
81
|
end
|
|
82
|
-
|
|
82
|
+
run_migrations config, target: target
|
|
83
83
|
exit Errno::NOERROR::Errno
|
|
84
84
|
end
|
|
85
85
|
|
|
@@ -85,7 +85,20 @@ class INatGet::Data::DSL::Dataset
|
|
|
85
85
|
def % field
|
|
86
86
|
# field = field.to_sym
|
|
87
87
|
values = get_field_values field
|
|
88
|
+
total = if values.respond_to?(:count)
|
|
89
|
+
values.count
|
|
90
|
+
else
|
|
91
|
+
values.size
|
|
92
|
+
end
|
|
93
|
+
Thread::current[:total] ||= 0
|
|
94
|
+
Thread::current[:total] += total
|
|
95
|
+
console.update status: "grouping by #{ field }...", total: Thread::current[:total]
|
|
96
|
+
current = 0
|
|
97
|
+
Thread::current[:current] ||= 0
|
|
88
98
|
dss = values.map do |value|
|
|
99
|
+
current += 1
|
|
100
|
+
Thread::current[:current] += 1
|
|
101
|
+
console.update status: "grouping by #{ field }...", current: Thread::current[:current]
|
|
89
102
|
if value.is_a?(INatGet::Data::Model::Taxon)
|
|
90
103
|
query = Q(self.condition.model, :taxon => value )
|
|
91
104
|
else
|
|
@@ -94,6 +107,12 @@ class INatGet::Data::DSL::Dataset
|
|
|
94
107
|
INatGet::Data::DSL::Dataset::new(value, self.condition & query, self.updated?)
|
|
95
108
|
end
|
|
96
109
|
INatGet::Data::DSL::List::new(*dss)
|
|
110
|
+
ensure
|
|
111
|
+
if current < total
|
|
112
|
+
Thread::current[:total] -= total - current
|
|
113
|
+
console.update total: Thread::current[:total]
|
|
114
|
+
end
|
|
115
|
+
console.update status: 'grouped'
|
|
97
116
|
end
|
|
98
117
|
|
|
99
118
|
# @return [Dataset]
|
|
@@ -112,13 +131,29 @@ class INatGet::Data::DSL::Dataset
|
|
|
112
131
|
# @yield Block
|
|
113
132
|
# @yieldparam [Sequel::Model] obj
|
|
114
133
|
# @return [void]
|
|
115
|
-
def each
|
|
134
|
+
def each
|
|
116
135
|
return to_enum(__method__) unless block_given?
|
|
117
136
|
connect!
|
|
137
|
+
total = @dataset.count
|
|
138
|
+
Thread::current[:total] ||= 0
|
|
139
|
+
Thread::current[:total] += total
|
|
140
|
+
console.update status: 'processing...', total: Thread::current[:total]
|
|
141
|
+
current = 0
|
|
142
|
+
Thread::current[:current] ||= 0
|
|
118
143
|
@dataset.each do |item|
|
|
119
144
|
check_shutdown!
|
|
120
|
-
|
|
145
|
+
current += 1
|
|
146
|
+
Thread::current[:current] += 1
|
|
147
|
+
console.update status: 'processing...', current: Thread::current[:current]
|
|
148
|
+
yield item
|
|
149
|
+
end
|
|
150
|
+
ensure
|
|
151
|
+
# Цикл может быть прерван досрочно, тогда нам нужно уменьшить total, чтобы результат сходился
|
|
152
|
+
if current < total
|
|
153
|
+
Thread::current[:total] -= total - current
|
|
154
|
+
console.update total: Thread::current[:total]
|
|
121
155
|
end
|
|
156
|
+
console.update status: 'processed'
|
|
122
157
|
end
|
|
123
158
|
|
|
124
159
|
# @return [Integer]
|
|
@@ -171,7 +206,7 @@ class INatGet::Data::DSL::Dataset
|
|
|
171
206
|
ranks = INatGet::Data::Enum::Rank::select { |r| r.level == field.level }
|
|
172
207
|
subquery = taxon_id_at_ranks(*ranks)
|
|
173
208
|
ids = query.distinct.select_map(subquery.as(:taxon_at_rank)).compact
|
|
174
|
-
INatGet::Data::Model::Taxon.where(id: ids)
|
|
209
|
+
INatGet::Data::Model::Taxon.where(id: ids)
|
|
175
210
|
elsif model.associations.include?(field)
|
|
176
211
|
reflection = model.association_reflection(field)
|
|
177
212
|
target = reflection.associated_class
|
|
@@ -179,14 +214,14 @@ class INatGet::Data::DSL::Dataset
|
|
|
179
214
|
case reflection[:type]
|
|
180
215
|
when :many_to_one
|
|
181
216
|
ids = query.distinct.select_map(reflection[:key])
|
|
182
|
-
target.where(id: ids)
|
|
217
|
+
target.where(id: ids)
|
|
183
218
|
when :one_to_many, :many_to_many
|
|
184
219
|
# Для всех типов "много" используем ассоциативный датасет
|
|
185
220
|
# association_join делает join на основе метаданных связи
|
|
186
221
|
ids = query.association_join(field)
|
|
187
222
|
.distinct
|
|
188
223
|
.select_map(reflection.qualified_right_key)
|
|
189
|
-
target.where(id: ids)
|
|
224
|
+
target.where(id: ids)
|
|
190
225
|
end
|
|
191
226
|
else
|
|
192
227
|
# field может быть как символом :column, так и Sequel.function(:month, :created_at)
|
|
@@ -41,6 +41,17 @@ module INatGet::Data::DSL
|
|
|
41
41
|
true
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
+
# @private
|
|
45
|
+
class DummyConsole
|
|
46
|
+
def update(**kwargs)
|
|
47
|
+
# do nothing
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def console
|
|
52
|
+
@console ||= Thread::current[:console] || DummyConsole::new
|
|
53
|
+
end
|
|
54
|
+
|
|
44
55
|
# @endgroup
|
|
45
56
|
|
|
46
57
|
# @group Date Utils
|
|
@@ -48,6 +48,7 @@ class INatGet::Data::DSL::List
|
|
|
48
48
|
|
|
49
49
|
# @return [self]
|
|
50
50
|
def add! other
|
|
51
|
+
other = [ other ] if other.is_a?(INatGet::Data::DSL::Dataset)
|
|
51
52
|
other.each do |ds|
|
|
52
53
|
if @datasets.has_key?(ds.key)
|
|
53
54
|
@datasets[ds.key] += ds
|
|
@@ -135,12 +136,30 @@ class INatGet::Data::DSL::List
|
|
|
135
136
|
# @yieldparam [Dataset] ds
|
|
136
137
|
def each
|
|
137
138
|
return to_enum(__method__) unless block_given?
|
|
138
|
-
if @sorter
|
|
139
|
-
@datasets.values.sort_by(&@sorter)
|
|
139
|
+
sorted = if @sorter
|
|
140
|
+
@datasets.values.sort_by(&@sorter)
|
|
140
141
|
else
|
|
141
|
-
@datasets.
|
|
142
|
+
@datasets.values
|
|
143
|
+
end
|
|
144
|
+
total = sorted.size
|
|
145
|
+
Thread::current[:total] ||= 0
|
|
146
|
+
Thread::current[:total] += total
|
|
147
|
+
console.update status: 'listing...', total: Thread::current[:total]
|
|
148
|
+
current = 0
|
|
149
|
+
Thread::current[:current] ||= 0
|
|
150
|
+
sorted.each do |ds|
|
|
151
|
+
current += 1
|
|
152
|
+
Thread::current[:current] += 1
|
|
153
|
+
console.update status: 'listing...', current: Thread::current[:current]
|
|
154
|
+
yield ds
|
|
142
155
|
end
|
|
143
156
|
self
|
|
157
|
+
ensure
|
|
158
|
+
if current < total
|
|
159
|
+
Thread::current[:total] -= total - current
|
|
160
|
+
console.update total: Thread::current[:total]
|
|
161
|
+
end
|
|
162
|
+
console.update status: 'listed'
|
|
144
163
|
end
|
|
145
164
|
|
|
146
165
|
# @return [Integer]
|
|
@@ -23,7 +23,7 @@ class INatGet::Data::Model::Place < INatGet::Data::Model
|
|
|
23
23
|
def <=> other
|
|
24
24
|
return nil unless other.is_a?(INatGet::Data::Model::Place)
|
|
25
25
|
return 0 if self.id == other.id
|
|
26
|
-
self.slug <=> other.slug
|
|
26
|
+
(self.display_name || self.name || self.slug) <=> (other.display_name || other.name || other.slug)
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
end
|
|
@@ -96,7 +96,7 @@ class INatGet::Data::Model::Project < INatGet::Data::Model
|
|
|
96
96
|
def <=> other
|
|
97
97
|
return nil unless other.is_a?(INatGet::Data::Model::Project)
|
|
98
98
|
return 0 if self.id == other.id
|
|
99
|
-
self.slug <=> other.slug
|
|
99
|
+
(self.title || self.slug) <=> (other.title || other.slug)
|
|
100
100
|
end
|
|
101
101
|
|
|
102
102
|
end
|
|
@@ -83,11 +83,30 @@ class INatGet::Data::Updater
|
|
|
83
83
|
# @private
|
|
84
84
|
def update_by_ids! *ids
|
|
85
85
|
return [] if ids.empty?
|
|
86
|
-
interval = parse_duration(@config.dig(:caching, :refs, self.manager
|
|
86
|
+
interval = parse_duration(@config.dig(:caching, :refs, self.manager&.endpoint) || @config.dig(:caching, :refs, :default))
|
|
87
87
|
if interval
|
|
88
88
|
point = (Time::now.to_time - interval).to_time
|
|
89
|
-
|
|
90
|
-
|
|
89
|
+
ints = uuids = slugs = []
|
|
90
|
+
if self.manager&.uuid? || self.manager&.sid
|
|
91
|
+
ints, other = ids.compact.partition { |i| i.is_a?(Integer) }
|
|
92
|
+
if !self.manager&.uuid?
|
|
93
|
+
slugs = other
|
|
94
|
+
elsif !self.manager&.sid
|
|
95
|
+
uuids = other
|
|
96
|
+
else
|
|
97
|
+
uuids, slugs = other.partition { |i| i.is_a?(String) && i =~ INatGet::Data::Helper::UUID_PATTERN }
|
|
98
|
+
end
|
|
99
|
+
else
|
|
100
|
+
ints = ids
|
|
101
|
+
end
|
|
102
|
+
condition = { id: ints }
|
|
103
|
+
# condition = Sequel.|(condition, { id: ints }) unless ints.empty?
|
|
104
|
+
condition = Sequel.|(condition, { uuid: uuids }) unless uuids.empty?
|
|
105
|
+
condition = Sequel.|(condition, { self.manager&.sid => slugs }) unless slugs.empty?
|
|
106
|
+
condition = Sequel.&(condition, { cached: (point .. ) })
|
|
107
|
+
fresh = self.model.where(condition).select_map(:id)
|
|
108
|
+
fresh += self.model.where(condition).select_map(:uuid) unless uuids.empty?
|
|
109
|
+
fresh += self.model.where(condition).select_map(self.manager&.sid) unless slugs.empty?
|
|
91
110
|
ids -= fresh
|
|
92
111
|
end
|
|
93
112
|
ids.each_slice(self.slice_size) do |slice|
|
data/lib/inat-get/info.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: inat-get
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.9.0.
|
|
4
|
+
version: 0.9.0.10
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ivan Shikhalev
|
|
@@ -240,9 +240,12 @@ executables:
|
|
|
240
240
|
extensions: []
|
|
241
241
|
extra_rdoc_files: []
|
|
242
242
|
files:
|
|
243
|
+
- ".yardopts"
|
|
244
|
+
- ".yardpreamble.rb"
|
|
243
245
|
- LICENSE
|
|
244
246
|
- README.md
|
|
245
247
|
- bin/inat-get
|
|
248
|
+
- coverage-badge.svg
|
|
246
249
|
- lib/inat-get.rb
|
|
247
250
|
- lib/inat-get/app.rb
|
|
248
251
|
- lib/inat-get/app/application.rb
|
|
@@ -373,6 +376,7 @@ files:
|
|
|
373
376
|
- lib/inat-get/utils/json.rb
|
|
374
377
|
- lib/inat-get/utils/simple_singular.rb
|
|
375
378
|
- share/inat-get/db/migrations/001_start_database.rb
|
|
379
|
+
- share/inat-get/db/migrations/002_nullable_slug.rb
|
|
376
380
|
- share/inat-get/demo/01_user_stat.rb
|
|
377
381
|
- share/inat-get/demo/02_underfound.rb
|
|
378
382
|
- share/inat-get/demo/03_newcomers.rb
|