marty 1.0.1 → 1.0.3
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/app/components/marty/auth_app.rb +2 -0
- data/app/components/marty/promise_view.rb +1 -1
- data/app/components/marty/simple_app/client/simple_app.js +1 -1
- data/app/models/marty/data_grid.rb +62 -71
- data/lib/marty/version.rb +1 -1
- data/spec/models/data_grid_spec.rb +78 -21
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bebe74227eb431e5b56683fb41cdf571d65ad9ae
|
4
|
+
data.tar.gz: 52e50bf586ade69e69501f408ba8795d5296a108
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6f047a2e07c4c2808c7385e7558e9c1243710e62385f317a7ab472175f78e22fb4fd74119d3d30b5cb2117d0ee3e7b834f6077e1ab463b9df887dae4f28c6632
|
7
|
+
data.tar.gz: 68b1e9630134ac55a561a3e9b4df22ac4e7dc0fd6bbc43fcb032ec505c4e98c70c4a521c368d317267a5687569ab851eff8b4861ca53a273afda14f89e1d153d
|
@@ -147,13 +147,11 @@ class Marty::DataGrid < Marty::Base
|
|
147
147
|
data_type.constantize rescue nil
|
148
148
|
end
|
149
149
|
|
150
|
-
def
|
151
|
-
|
152
|
-
|
153
|
-
(dir_infos("v") + dir_infos("h")).each do
|
154
|
-
|inf|
|
150
|
+
def query_grid_dir(h, infos)
|
151
|
+
return [0] if infos.empty?
|
155
152
|
|
156
|
-
|
153
|
+
sqla = infos.map do |inf|
|
154
|
+
type, attr = inf["type"], inf["attr"]
|
157
155
|
|
158
156
|
next unless h.has_key?(attr)
|
159
157
|
|
@@ -161,6 +159,8 @@ class Marty::DataGrid < Marty::Base
|
|
161
159
|
|
162
160
|
ix_class = INDEX_MAP[type] || INDEX_MAP["string"]
|
163
161
|
|
162
|
+
q = "key IS NULL"
|
163
|
+
|
164
164
|
unless v.nil?
|
165
165
|
q = case type
|
166
166
|
when "boolean"
|
@@ -169,7 +169,7 @@ class Marty::DataGrid < Marty::Base
|
|
169
169
|
"key @> ?"
|
170
170
|
else # "string", "integer", AR klass
|
171
171
|
"key @> ARRAY[?]"
|
172
|
-
end
|
172
|
+
end + " OR #{q}"
|
173
173
|
|
174
174
|
# FIXME: very hacky -- need to cast numrange/intrange values or
|
175
175
|
# we get errors from PG.
|
@@ -185,34 +185,35 @@ class Marty::DataGrid < Marty::Base
|
|
185
185
|
else # AR class
|
186
186
|
v.to_s
|
187
187
|
end
|
188
|
-
|
189
|
-
ixa = ix_class.
|
190
|
-
where(data_grid_id: group_id,
|
191
|
-
created_dt: created_dt,
|
192
|
-
attr: inf["attr"],
|
193
|
-
).
|
194
|
-
where(q, v).uniq.pluck(:index)
|
195
188
|
end
|
196
189
|
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
190
|
+
# FIXME: could potentially order results by key NULLS LAST.
|
191
|
+
# This would prefer more specific rather than wild card
|
192
|
+
# solutions. However, would need to figure out how to preserve
|
193
|
+
# ordering on subsequent INTERSECT operations.
|
194
|
+
ixq = ix_class.
|
195
|
+
select(:index).
|
196
|
+
distinct.
|
197
|
+
where(data_grid_id: group_id,
|
198
|
+
created_dt: created_dt,
|
199
|
+
attr: inf["attr"],
|
200
|
+
).
|
201
|
+
where(q, v).to_sql
|
202
|
+
end.compact
|
205
203
|
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
204
|
+
sql = sqla.join(" INTERSECT ")
|
205
|
+
|
206
|
+
self.class.connection.execute(sql).to_a.map { |h| h["index"].to_i }
|
207
|
+
end
|
208
|
+
|
209
|
+
def lookup_grid_distinct(pt, h, return_grid_data=false, distinct=true)
|
210
|
+
isets = ["h", "v"].each_with_object({}) do |dir, isets|
|
211
|
+
infos = dir_infos(dir)
|
210
212
|
|
211
|
-
|
212
|
-
isets[dir] = Set[0] if !isets[dir] && dir_infos(dir).empty?
|
213
|
+
isets[dir] = query_grid_dir(h, infos)
|
213
214
|
|
214
215
|
unless isets[dir] or return_grid_data
|
215
|
-
attrs =
|
216
|
+
attrs = infos.map { |inf| inf["attr"] }
|
216
217
|
|
217
218
|
raise "#{dir} attrs not provided: %s" % attrs.join(',')
|
218
219
|
end
|
@@ -221,7 +222,8 @@ class Marty::DataGrid < Marty::Base
|
|
221
222
|
distinct && isets[dir] && isets[dir].count > 1
|
222
223
|
end
|
223
224
|
|
224
|
-
|
225
|
+
# deterministic result: pick min index when there's a choice
|
226
|
+
vi, hi = isets["v"].min, isets["h"].min if isets["v"] && isets["h"]
|
225
227
|
|
226
228
|
raise "DataGrid lookup failed #{name}" unless (vi && hi) or lenient or
|
227
229
|
return_grid_data
|
@@ -343,29 +345,22 @@ class Marty::DataGrid < Marty::Base
|
|
343
345
|
meta_rows = dt_row.empty? ? [] : [dt_row]
|
344
346
|
|
345
347
|
meta_rows += metadata.map { |inf|
|
346
|
-
[
|
347
|
-
inf["attr"],
|
348
|
-
inf["type"],
|
349
|
-
inf["dir"],
|
350
|
-
inf["rs_keep"] || "",
|
351
|
-
]
|
348
|
+
[inf["attr"], inf["type"], inf["dir"], inf["rs_keep"] || ""]
|
352
349
|
}
|
353
350
|
|
354
351
|
v_infos, h_infos = dir_infos("v"), dir_infos("h")
|
355
352
|
|
356
|
-
h_key_rows = h_infos.map
|
357
|
-
|inf|
|
358
|
-
|
353
|
+
h_key_rows = h_infos.map { |inf|
|
359
354
|
[nil]*v_infos.count + self.class.export_keys(inf)
|
360
|
-
|
355
|
+
}
|
361
356
|
|
362
357
|
transposed_v_keys = v_infos.empty? ? [[]] :
|
363
358
|
v_infos.map {|inf| self.class.export_keys(inf)}.transpose
|
364
359
|
|
365
|
-
data_rows = transposed_v_keys.each_with_index.map
|
366
|
-
|keys, i|
|
360
|
+
data_rows = transposed_v_keys.each_with_index.map { |keys, i|
|
367
361
|
keys + (self.data[i] || [])
|
368
|
-
|
362
|
+
}
|
363
|
+
|
369
364
|
[meta_rows, h_key_rows, data_rows]
|
370
365
|
end
|
371
366
|
|
@@ -460,8 +455,12 @@ class Marty::DataGrid < Marty::Base
|
|
460
455
|
raise "must have a blank row separating metadata" unless
|
461
456
|
blank_index
|
462
457
|
|
463
|
-
|
464
|
-
|
458
|
+
raise "can't import grid with trailing blank column" if
|
459
|
+
rows.map { |r| r.last.nil? }.all?
|
460
|
+
|
461
|
+
raise "last row can't be blank" if rows[-1].all?(&:nil?)
|
462
|
+
|
463
|
+
data_type, lenient = nil, false
|
465
464
|
|
466
465
|
# check if there's a data_type definition
|
467
466
|
dt, *x = rows[0]
|
@@ -661,10 +660,10 @@ class Marty::DataGrid < Marty::Base
|
|
661
660
|
|
662
661
|
def opposite_sign(op) # toggle sign and inclusivity
|
663
662
|
{
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
663
|
+
:< => :>=,
|
664
|
+
:<= => :>,
|
665
|
+
:> => :<=,
|
666
|
+
:>= => :<,
|
668
667
|
}[op]
|
669
668
|
end
|
670
669
|
|
@@ -682,35 +681,35 @@ class Marty::DataGrid < Marty::Base
|
|
682
681
|
lhv, rhv = orig_lhv || -Float::INFINITY, orig_rhv || Float::INFINITY
|
683
682
|
|
684
683
|
case op
|
685
|
-
when
|
684
|
+
when :>=, :>
|
686
685
|
next if value > rhv
|
687
686
|
|
688
687
|
if value == rhv
|
689
|
-
if rhop ==
|
688
|
+
if rhop == :<= && op == :>=
|
690
689
|
rewrite_a.push(
|
691
|
-
[index, rewrite_range(lhop, orig_lhv, orig_rhv,
|
690
|
+
[index, rewrite_range(lhop, orig_lhv, orig_rhv, :<)])
|
692
691
|
end
|
693
692
|
elsif value > lhv
|
694
693
|
rewrite_a.push(
|
695
694
|
[index, rewrite_range(lhop, orig_lhv, value, opposite_sign(op))])
|
696
|
-
elsif value == lhv && lhop ==
|
697
|
-
rewrite_a.push([index, rewrite_range(
|
695
|
+
elsif value == lhv && lhop == :>= && op == :>
|
696
|
+
rewrite_a.push([index, rewrite_range(:>=, value, value, :<=)])
|
698
697
|
elsif value <= lhv
|
699
698
|
prune_a.push(index)
|
700
699
|
end
|
701
|
-
when
|
700
|
+
when :<=, :<
|
702
701
|
next if value < lhv
|
703
702
|
|
704
703
|
if value == lhv
|
705
|
-
if lhop ==
|
704
|
+
if lhop == :>= && op == :<=
|
706
705
|
rewrite_a.push(
|
707
|
-
[index, rewrite_range(
|
706
|
+
[index, rewrite_range(:>, orig_lhv, orig_rhv, rhop)])
|
708
707
|
end
|
709
708
|
elsif value < rhv
|
710
709
|
rewrite_a.push(
|
711
710
|
[index, rewrite_range(opposite_sign(op), value, orig_rhv, rhop)])
|
712
|
-
elsif value == rhv && rhop ==
|
713
|
-
rewrite_a.push([index, rewrite_range(
|
711
|
+
elsif value == rhv && rhop == :<= && op == :<
|
712
|
+
rewrite_a.push([index, rewrite_range(:>=, value, value, :<=)])
|
714
713
|
elsif value >= rhv
|
715
714
|
prune_a.push(index)
|
716
715
|
end
|
@@ -753,18 +752,18 @@ class Marty::DataGrid < Marty::Base
|
|
753
752
|
lhv = lhs.blank? ? nil : lhs.to_f
|
754
753
|
rhv = rhs.blank? ? nil : rhs.to_f
|
755
754
|
|
756
|
-
[lboundary == '(' ?
|
755
|
+
[lboundary == '(' ? :> : :>=, lhv, rhv, rboundary == ')' ? :< : :<=]
|
757
756
|
end
|
758
757
|
|
759
758
|
def rewrite_range(lb, lhv, rhv, rb)
|
760
|
-
lboundary = lb ==
|
759
|
+
lboundary = lb == :> ? '(' : '['
|
761
760
|
|
762
761
|
# even though numranges are float type, we don't want to output ".0"
|
763
762
|
# for integer values. So for values like that we convert to int
|
764
763
|
# first before conversion to string
|
765
764
|
lvalue = (lhv.to_i == lhv ? lhv.to_i : lhv).to_s
|
766
765
|
rvalue = (rhv.to_i == rhv ? rhv.to_i : rhv).to_s
|
767
|
-
rboundary = rb ==
|
766
|
+
rboundary = rb == :< ? ')' : ']'
|
768
767
|
lboundary + lvalue + ',' + rvalue + rboundary
|
769
768
|
end
|
770
769
|
|
@@ -774,16 +773,8 @@ class Marty::DataGrid < Marty::Base
|
|
774
773
|
|
775
774
|
opstr, ident = match[1..2]
|
776
775
|
|
777
|
-
orig_op = {
|
778
|
-
'<' => :lt,
|
779
|
-
'>' => :gt,
|
780
|
-
'<=' => :le,
|
781
|
-
'>=' => :ge,
|
782
|
-
'' => :inc,
|
783
|
-
}[opstr]
|
784
|
-
|
785
776
|
# data grid value is expressed as what to keep
|
786
777
|
# we convert to the opposite (what to prune)
|
787
|
-
[opposite_sign(
|
778
|
+
[opposite_sign(opstr.to_sym), ident]
|
788
779
|
end
|
789
780
|
end
|
data/lib/marty/version.rb
CHANGED
@@ -127,6 +127,25 @@ n\tnumrange\tv
|
|
127
127
|
true\t1\t<10\t<10.0\tY
|
128
128
|
\t2\t\t\tM
|
129
129
|
false\t\t>10\t\tN
|
130
|
+
EOS
|
131
|
+
|
132
|
+
Gg = <<EOS
|
133
|
+
lenient
|
134
|
+
i1\tinteger\tv
|
135
|
+
i2\tinteger\tv
|
136
|
+
|
137
|
+
\t1\t1
|
138
|
+
2\t1\t21
|
139
|
+
2\t\t20
|
140
|
+
EOS
|
141
|
+
|
142
|
+
Gh = <<EOS
|
143
|
+
lenient
|
144
|
+
property_state\tstring\tv
|
145
|
+
county_name\tstring\tv
|
146
|
+
|
147
|
+
NY\t\t10
|
148
|
+
\tR\t8
|
130
149
|
EOS
|
131
150
|
|
132
151
|
before(:each) do
|
@@ -140,6 +159,20 @@ EOS
|
|
140
159
|
[res["result"], res["name"]]
|
141
160
|
end
|
142
161
|
|
162
|
+
describe "imports" do
|
163
|
+
it "should not allow imports with trailing blank columns" do
|
164
|
+
expect {
|
165
|
+
dg_from_import("G1", G1.gsub("\n", "\t\n"))
|
166
|
+
}.to raise_error(RuntimeError)
|
167
|
+
end
|
168
|
+
|
169
|
+
it "should not allow imports with last blank row" do
|
170
|
+
expect {
|
171
|
+
dg_from_import("Gh", Gh+"\t\t\n")
|
172
|
+
}.to raise_error(RuntimeError)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
143
176
|
describe "validations" do
|
144
177
|
it "a basic data grid should load ok" do
|
145
178
|
dg_from_import("G1", G1)
|
@@ -223,7 +256,7 @@ EOS
|
|
223
256
|
|
224
257
|
before(:each) do
|
225
258
|
["G1", "G2", "G3", "G4", "G5", "G6", "G7", "G8", "Ga", "Gb",
|
226
|
-
"Gc", "Gd", "Ge", "Gf"].each { |g|
|
259
|
+
"Gc", "Gd", "Ge", "Gf", "Gg", "Gh"].each { |g|
|
227
260
|
dg_from_import(g, "Marty::DataGridSpec::#{g}".constantize)
|
228
261
|
}
|
229
262
|
end
|
@@ -232,32 +265,27 @@ EOS
|
|
232
265
|
let(:dg) { Marty::DataGrid.lookup(pt, "Gf") }
|
233
266
|
|
234
267
|
it 'true returns Y' do
|
235
|
-
res = Marty::DataGrid.
|
236
|
-
lookup_grid(pt, dg, {"b"=>true}, true)
|
268
|
+
res = Marty::DataGrid.lookup_grid(pt, dg, {"b"=>true}, false)
|
237
269
|
expect(res).to eq('Y')
|
238
270
|
end
|
239
271
|
|
240
272
|
it '13 returns N' do
|
241
|
-
res = Marty::DataGrid.
|
242
|
-
lookup_grid(pt, dg, {"i"=>13}, true)
|
273
|
+
res = Marty::DataGrid.lookup_grid(pt, dg, {"i"=>13}, true)
|
243
274
|
expect(res).to eq('N')
|
244
275
|
end
|
245
276
|
|
246
277
|
it '13 & numrange 0 returns nil' do
|
247
|
-
res = Marty::DataGrid.
|
248
|
-
|
249
|
-
expect(res).to be_nil
|
278
|
+
res = Marty::DataGrid.lookup_grid(pt, dg, {"i"=>13, "n"=>0}, true)
|
279
|
+
expect(res).to eq('N')
|
250
280
|
end
|
251
281
|
|
252
282
|
it '13 & int4range 15 returns N' do
|
253
|
-
res = Marty::DataGrid.
|
254
|
-
lookup_grid(pt, dg, {"i"=>13, "i4"=>15}, true)
|
283
|
+
res = Marty::DataGrid.lookup_grid(pt, dg, {"i"=>13, "i4"=>15}, true)
|
255
284
|
expect(res).to eq('N')
|
256
285
|
end
|
257
286
|
|
258
287
|
it '13 & int4range 1 returns nil' do
|
259
|
-
res = Marty::DataGrid.
|
260
|
-
lookup_grid(pt, dg, {"i"=>13, "i4"=>1}, true)
|
288
|
+
res = Marty::DataGrid.lookup_grid(pt, dg, {"i"=>13, "i4"=>1}, true)
|
261
289
|
expect(res).to be_nil
|
262
290
|
end
|
263
291
|
|
@@ -268,12 +296,38 @@ EOS
|
|
268
296
|
end
|
269
297
|
|
270
298
|
it '13, numrange 15 returns N' do
|
271
|
-
res = Marty::DataGrid.
|
272
|
-
lookup_grid(pt, dg, {"i"=>13, "n"=>15}, true)
|
299
|
+
res = Marty::DataGrid.lookup_grid(pt, dg, {"i"=>13, "n"=>15}, true)
|
273
300
|
expect(res).to eq('N')
|
274
301
|
end
|
275
302
|
end
|
276
303
|
|
304
|
+
it "should handle ambiguous lookups" do
|
305
|
+
dg = Marty::DataGrid.lookup(pt, "Gh")
|
306
|
+
|
307
|
+
h1 = {
|
308
|
+
"property_state" => "NY",
|
309
|
+
"county_name" => "R",
|
310
|
+
}
|
311
|
+
|
312
|
+
res = Marty::DataGrid.lookup_grid(pt, dg, h1, false)
|
313
|
+
expect(res).to eq(10)
|
314
|
+
end
|
315
|
+
|
316
|
+
it "should handle ambiguous lookups (2)" do
|
317
|
+
dg = Marty::DataGrid.lookup(pt, "Gg")
|
318
|
+
res = Marty::DataGrid.
|
319
|
+
lookup_grid(pt, dg, {"i1"=>2, "i2"=>1}, false)
|
320
|
+
expect(res).to eq(1)
|
321
|
+
|
322
|
+
res = Marty::DataGrid.
|
323
|
+
lookup_grid(pt, dg, {"i1"=>3, "i2"=>1}, false)
|
324
|
+
expect(res).to eq(1)
|
325
|
+
|
326
|
+
res = Marty::DataGrid.
|
327
|
+
lookup_grid(pt, dg, {"i1"=>2, "i2"=>3}, false)
|
328
|
+
expect(res).to eq(20)
|
329
|
+
end
|
330
|
+
|
277
331
|
it "should handle non-distinct lookups" do
|
278
332
|
dg = Marty::DataGrid.lookup(pt, "Ge")
|
279
333
|
res = Marty::DataGrid.lookup_grid(pt, dg, {"ltv"=>500}, false)
|
@@ -372,11 +426,12 @@ EOS
|
|
372
426
|
it "should handle matches which also have a wildcard match" do
|
373
427
|
dg_from_import("G9", G9)
|
374
428
|
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
429
|
+
expect {
|
430
|
+
res = lookup_grid_helper('infinity',
|
431
|
+
"G9",
|
432
|
+
{"state" => "CA", "ltv" => 81},
|
433
|
+
)
|
434
|
+
}.to raise_error(RuntimeError)
|
380
435
|
|
381
436
|
res = lookup_grid_helper('infinity',
|
382
437
|
"G9",
|
@@ -449,7 +504,8 @@ EOS
|
|
449
504
|
end
|
450
505
|
|
451
506
|
it "should handle DataGrid typed data grids" do
|
452
|
-
expect(Marty::DataGrid.lookup('infinity', "G8").data_type).
|
507
|
+
expect(Marty::DataGrid.lookup('infinity', "G8").data_type).
|
508
|
+
to eq "Marty::DataGrid"
|
453
509
|
g1 = Marty::DataGrid.lookup('infinity', "G1")
|
454
510
|
|
455
511
|
res = lookup_grid_helper('infinity',
|
@@ -461,7 +517,8 @@ EOS
|
|
461
517
|
end
|
462
518
|
|
463
519
|
it "should handle multi DataGrid lookups" do
|
464
|
-
expect(Marty::DataGrid.lookup('infinity', "G8").data_type).
|
520
|
+
expect(Marty::DataGrid.lookup('infinity', "G8").data_type).
|
521
|
+
to eq "Marty::DataGrid"
|
465
522
|
g1 = Marty::DataGrid.lookup('infinity', "G1")
|
466
523
|
|
467
524
|
h = {
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: marty
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Arman Bostani
|
@@ -14,7 +14,7 @@ authors:
|
|
14
14
|
autorequire:
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
|
-
date: 2016-
|
17
|
+
date: 2016-07-14 00:00:00.000000000 Z
|
18
18
|
dependencies:
|
19
19
|
- !ruby/object:Gem::Dependency
|
20
20
|
name: pg
|