marty 1.0.1 → 1.0.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|