marty 2.0.1 → 2.0.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 31ab53bcb7bcc26bfa4bd1d400c5e0c7861558d3
4
- data.tar.gz: c12dae6177787b1cd2eefb4416c11b15155a4395
3
+ metadata.gz: '08f9abbd9c473713331bb0ade7453ac85f1c4842'
4
+ data.tar.gz: d0251f02426640781822b048f6203f0597f73227
5
5
  SHA512:
6
- metadata.gz: 6c435cd40922422b864e5dc5ed4d20536ca8a50317b917a4b53b299a9d949ef67594ceb8707c38c822efd3024264e7a1832f3707ed8d2ae039957848681cf627
7
- data.tar.gz: 17a9348a816387d216a59739eac52b9cca47790ec8dd5cb469eaee93c660c83a29d40f8b9afac1ccc422d4ea6245386948732c5a87632fc612793b5a0677d4c0
6
+ metadata.gz: 2cab552bb2a885d177007686a476e57a28a72ab02af0ce904b0e81c0dde0dd63ed0ce773399000ea3283ee618023909259618e5e1e95e6547372ca31cefb2077
7
+ data.tar.gz: f39020a718bcb428a4c3171c6e21c0973b6b5bb3f8efb02bbc7237f4f386606e5c321cadaaea77ed375f39f2b07dfc239f8b55ad849d6be08591a2408c1626ac
@@ -54,17 +54,22 @@ module Mcfly::Model
54
54
 
55
55
  def base_mcfly_lookup(meth, name, options = {}, &block)
56
56
 
57
- sig = options[:sig]
57
+ priv = options[:private]
58
+ sig = priv ? -1 : options[:sig]
59
+
60
+ # add an extra argument to the sig to receive the openstruct conversion
61
+ # options hash (unless private)
58
62
  newsig = sig.is_a?(Array) ? [sig[0], sig[1]+1] :
59
63
  sig == -1 ? sig : [sig, sig+1]
60
64
  options[:sig] = newsig
61
- asig = options[:asig] || newsig[1]-1
62
65
 
63
66
  send(meth, name, options) do |ts, *pargs|
64
67
  raise "time cannot be nil" if ts.nil?
65
68
 
66
- args, opts = pargs.last.is_a?(Hash) && pargs.length == asig ?
67
- [pargs[0..-2], pargs.last] :
69
+ # get the options hash if method is not private and last arg is a hash
70
+ # and pargs len = max sig (-1 because ts is separated in the arg list)
71
+ args, opts = !priv && pargs.last.is_a?(Hash) &&
72
+ pargs.length == newsig[1]-1 ? [pargs[0..-2], pargs.last] :
68
73
  [pargs, {}]
69
74
 
70
75
  ts = Mcfly.normalize_infinity(ts)
@@ -73,18 +78,19 @@ module Mcfly::Model
73
78
  "#{table_name}.created_dt < ?", ts, ts).scoping do
74
79
  block.call(ts, *args)
75
80
  end
81
+ next q if priv
82
+
76
83
  fa = get_final_attrs(opts)
77
84
  opts += {"fa"=>fa}
78
-
79
- q = q.select(*fa) if fa.present? &&
80
- q.respond_to?(:select) && !q.is_a?(Array) &&
81
- !q.is_a?(Hash)
85
+ q = q.select(*fa) if fa.present? && q.is_a?(ActiveRecord::Relation)
82
86
 
83
87
  case
84
88
  when opts["no_convert"] == true
85
89
  q
86
90
  when q.is_a?(ActiveRecord::Relation)
87
- q.map{|ar| make_openstruct(ar, opts)}
91
+ # shouldn't happen - lookups that are mode nil should be private
92
+ # raise "#{self}.#{name} can't convert ActiveRecord::Relation to OpenStruct"
93
+ q
88
94
  when q.is_a?(ActiveRecord::Base)
89
95
  make_openstruct(q, opts)
90
96
  else
@@ -133,11 +139,8 @@ module Mcfly::Model
133
139
  raise "bad attrs" unless Array === attrs
134
140
  end
135
141
 
136
- actual_sig = attrs.length + 1
137
142
  fn = cache ? :cached_delorean_fn : :delorean_fn
138
- sig = options[:private] ? -1 : actual_sig
139
-
140
- base_mcfly_lookup(fn, name, {sig: sig, asig: actual_sig}) do
143
+ base_mcfly_lookup(fn, name, options + {sig: attrs.length+1}) do
141
144
  |t, *attr_list|
142
145
 
143
146
  attr_list_ids = attr_list.each_with_index.map {|x, i|
data/lib/marty/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Marty
2
- VERSION = "2.0.1"
2
+ VERSION = "2.0.2"
3
3
  end
@@ -25,5 +25,72 @@ module Gemini
25
25
  rec
26
26
  }
27
27
  end
28
+
29
+ gen_mcfly_lookup :lookup, {
30
+ entity: true,
31
+ note_rate: false
32
+ }
33
+ gen_mcfly_lookup :lookup_p, {
34
+ entity: true,
35
+ note_rate: false
36
+ }, private: true
37
+ gen_mcfly_lookup :clookup, {
38
+ entity: true,
39
+ note_rate: false
40
+ }, cache: true
41
+ gen_mcfly_lookup :clookup_p, {
42
+ entity: true,
43
+ note_rate: false
44
+ }, cache: true, private: true
45
+ gen_mcfly_lookup :lookupn, {
46
+ entity: true,
47
+ note_rate: false
48
+ }, mode: nil
49
+ gen_mcfly_lookup :lookupn_p, {
50
+ entity: true,
51
+ note_rate: false
52
+ }, private: true, mode: nil
53
+ gen_mcfly_lookup :clookupn, {
54
+ entity: true,
55
+ note_rate: false
56
+ }, cache: true, mode: nil
57
+ gen_mcfly_lookup :clookupn_p, {
58
+ entity: true,
59
+ note_rate: false
60
+ }, cache: true, private: true, mode: nil
61
+
62
+ mcfly_lookup :a_func, sig: 3 do
63
+ |pt, e_id, bc_id|
64
+ where(entity_id: e_id, bud_category_id: bc_id).
65
+ order(:settlement_mm)
66
+ end
67
+
68
+ mcfly_lookup :b_func, sig: [3, 4] do
69
+ |pt, e_id, bc_id, mm = nil|
70
+ q = where(entity_id: e_id, bud_category_id: bc_id)
71
+ q = q.where(settlement_mm: mm) if mm
72
+ q.order(:settlement_mm).first
73
+ end
74
+
75
+ mcfly_lookup :a_func_p, sig: 3, private: true do
76
+ |pt, e_id, bc_id|
77
+ where(entity_id: e_id, bud_category_id: bc_id).
78
+ order(:settlement_mm)
79
+ end
80
+
81
+ mcfly_lookup :b_func_p, sig: [3, 4], private: true do
82
+ |pt, e_id, bc_id, mm = nil|
83
+ q = where(entity_id: e_id, bud_category_id: bc_id)
84
+ q = q.where(settlement_mm: mm) if mm
85
+ q.order(:settlement_mm)
86
+ end
87
+
88
+ cached_mcfly_lookup :ca_func, sig: 3 do
89
+ |pt, e_id, bc_id|
90
+ where(entity_id: e_id, bud_category_id: bc_id).
91
+ order(:settlement_mm)
92
+ end
93
+
94
+
28
95
  end
29
96
  end
@@ -74,6 +74,10 @@ A:
74
74
  EOF
75
75
 
76
76
  describe 'DeloreanQuery' do
77
+ before(:all) do
78
+ @clean_file = "/tmp/clean_#{Process.pid}.psql"
79
+ save_clean_db(@clean_file)
80
+ end
77
81
  before(:each) do
78
82
  marty_whodunnit
79
83
  Marty::DataImporter.do_import_summary(Gemini::BudCategory, bud_cats)
@@ -86,7 +90,10 @@ EOF
86
90
 
87
91
  @engine = Marty::ScriptSet.new.get_engine("A")
88
92
  end
89
-
93
+ after(:all) do
94
+ restore_clean_db(@clean_file)
95
+ Marty::ScriptSet.clear_cache
96
+ end
90
97
  it "perfroms join+count" do
91
98
  res = @engine.evaluate("A", "c", {})
92
99
 
@@ -0,0 +1,255 @@
1
+ require "spec_helper"
2
+
3
+ module Marty
4
+
5
+ entities =<<EOF
6
+ name
7
+ PLS
8
+ EOF
9
+ bud_cats =<<EOF
10
+ name
11
+ Conv Fixed 30
12
+ Conv Fixed 20
13
+ EOF
14
+
15
+ fannie_bup =<<EOF
16
+ entity bud_category note_rate buy_up buy_down settlement_mm settlement_yy
17
+ Conv Fixed 30 2.250 4.42000 7.24000 12 2012
18
+ Conv Fixed 30 2.375 4.42000 7.24000 12 2012
19
+ Conv Fixed 30 2.500 4.41300 7.22800 12 2012
20
+ Conv Fixed 30 2.625 4.37500 7.16200 12 2012
21
+ Conv Fixed 30 2.750 4.32900 7.09300 12 2012
22
+ Conv Fixed 20 2.875 4.24800 6.95900 12 2012
23
+ Conv Fixed 20 2.875 4.24800 6.95900 11 2012
24
+ PLS Conv Fixed 30 2.250 5.42000 8.24000 12 2012
25
+ PLS Conv Fixed 30 2.375 5.42000 8.24000 12 2012
26
+ PLS Conv Fixed 30 2.500 5.41300 8.22800 12 2012
27
+ PLS Conv Fixed 30 2.625 5.37500 8.16200 12 2012
28
+ PLS Conv Fixed 30 2.750 5.32900 8.09300 12 2012
29
+ PLS Conv Fixed 20 2.875 5.24800 7.95900 12 2012
30
+ PLS Conv Fixed 20 2.875 5.24800 7.95900 11 2012
31
+ EOF
32
+
33
+ script =<<EOF
34
+ A:
35
+ pt =?
36
+ entity =?
37
+ note_rate =?
38
+
39
+ extra = {"include_attrs": ["settlement_mm", "settlement_yy"],
40
+ "link_attrs": {"entity": "name",
41
+ "bud_category": "name"}}
42
+ ex2 = {"include_attrs": ["settlement_mm", "settlement_yy", "entity_id",
43
+ "bud_category_id"]}
44
+
45
+ lookup = Gemini::FannieBup.lookup( pt, entity, note_rate)
46
+ lookup_extra = Gemini::FannieBup.lookup( pt, entity, note_rate, extra)
47
+
48
+ clookup = Gemini::FannieBup.clookup( pt, entity, note_rate)
49
+
50
+ lookupn = Gemini::FannieBup.lookupn( pt, entity, note_rate)
51
+ lookupn_extra = Gemini::FannieBup.lookupn( pt, entity, note_rate, ex2)
52
+
53
+ clookupn = Gemini::FannieBup.clookupn(pt, entity, note_rate)
54
+
55
+ a_func = Gemini::FannieBup.a_func('infinity', 1, 2)
56
+ a_func_extra = Gemini::FannieBup.a_func('infinity', 1, 2, ex2)
57
+ b_func = Gemini::FannieBup.b_func('infinity',1, 2, 12)
58
+ b_func_extra = Gemini::FannieBup.b_func('infinity',1, 2, 12, extra)
59
+ ca_func = Gemini::FannieBup.ca_func('infinity',1, 2, ex2)
60
+
61
+ EOF
62
+ errscript =<<EOF
63
+ Err:
64
+ pt =?
65
+ entity =?
66
+ note_rate =?
67
+ result = Gemini::FannieBup.%s(pt, entity, note_rate)
68
+ EOF
69
+ errscript2 =<<EOF
70
+ Err:
71
+ pt =?
72
+ e_id =?
73
+ bc_id =?
74
+ result = Gemini::FannieBup.%s(pt, e_id, bc_id)
75
+ EOF
76
+ errscript3 =<<EOF
77
+ Err:
78
+ pt =?
79
+ e_id =?
80
+ bc_id =?
81
+ mm =?
82
+ result = Gemini::FannieBup.%s(pt, e_id, bc_id, mm)
83
+ EOF
84
+
85
+ describe 'McflyModel' do
86
+ before(:all) do
87
+ @clean_file = "/tmp/clean_#{Process.pid}.psql"
88
+ save_clean_db(@clean_file)
89
+ marty_whodunnit
90
+ dt = Date.today
91
+ Marty::DataImporter.do_import_summary(Gemini::Entity, entities)
92
+ Marty::DataImporter.do_import_summary(Gemini::BudCategory, bud_cats)
93
+ Marty::DataImporter.do_import_summary(Gemini::FannieBup, fannie_bup)
94
+ Marty::Script.load_script_bodies(
95
+ {
96
+ "AA" => script,
97
+ }, dt)
98
+ @errs = ['E1', 'lookup_p',
99
+ 'E2', 'clookup_p',
100
+ 'E3', 'lookupn_p',
101
+ 'E4', 'clookupn_p']
102
+
103
+ @errs.in_groups_of(2) do |name, fn|
104
+ Marty::Script.load_script_bodies(
105
+ {
106
+ name => (errscript % fn),
107
+ }, Date.today)
108
+ end
109
+
110
+ Marty::Script.load_script_bodies({'E5'=>(errscript2 % 'a_func_p')}, dt)
111
+ Marty::Script.load_script_bodies({'E6'=>(errscript3 % 'b_func_p')}, dt)
112
+
113
+ @engine = Marty::ScriptSet.new.get_engine("AA")
114
+ end
115
+ after(:all) do
116
+ restore_clean_db(@clean_file)
117
+ Marty::ScriptSet.clear_cache
118
+ end
119
+ let(:params) {{"pt" =>'infinity',
120
+ "entity" => Gemini::Entity.all.first,
121
+ "note_rate" => 2.875}}
122
+ it "lookup mode default" do
123
+ a1 = @engine.evaluate("A", "lookup", params)
124
+ a2 = @engine.evaluate("A", "clookup", params)
125
+ expect(a1).to eq(a2) # cache/non return same
126
+ expect(a1.class).to eq(OpenStruct) # mode default so return OS
127
+ expect(a2.class).to eq(OpenStruct)
128
+
129
+ # check that keys are non mcfly non uniqueness
130
+ expect(a1.to_h.keys.to_set).to eq(Set[:buy_up, :buy_down])
131
+ end
132
+
133
+ it "lookup non generated" do
134
+ # a1-a3 will be AR Relations
135
+ # b1-b2 will be OpenStructs because the b fns return #first
136
+ a1 = @engine.evaluate("A", "a_func", {})
137
+ a2 = @engine.evaluate("A", "ca_func", {})
138
+ a3 = @engine.evaluate("A", "a_func_extra", {})
139
+ b1 = @engine.evaluate("A", "b_func", {})
140
+ b2 = @engine.evaluate("A", "b_func_extra", {})
141
+
142
+ # all return relations
143
+ expect(ActiveRecord::Relation === a1).to be_truthy
144
+ expect(ActiveRecord::Relation === a2).to be_truthy
145
+ expect(ActiveRecord::Relation === a3).to be_truthy
146
+ expect(ActiveRecord::Base === a1.first).to be_truthy
147
+ expect(ActiveRecord::Base === a2.first).to be_truthy
148
+ expect(ActiveRecord::Base === a3.first).to be_truthy
149
+
150
+ expect(a1.to_a.count).to eq(2)
151
+ expect(a2.to_a.count).to eq(2)
152
+ expect(a3.to_a.count).to eq(2)
153
+
154
+ # a1 lookup did not include extra attrs
155
+ expect(a1.first.attributes.keys.to_set).to eq(Set["id", "buy_up", "buy_down"])
156
+
157
+ # a2 and a3 did
158
+ s = Set["id", "entity_id", "bud_category_id", "buy_up", "buy_down",
159
+ "settlement_mm", "settlement_yy"]
160
+ expect(a2.first.attributes.keys.to_set).to eq(s)
161
+ expect(a3.first.attributes.keys.to_set).to eq(s)
162
+
163
+ # a1 is AR but still missing the FK entity_id so will raise
164
+ expect{a1.first.entity}.to raise_error(/missing attribute: entity_id/)
165
+
166
+ # a3 included those so can access them
167
+ expect(a3.first.entity.name).to eq('PLS')
168
+ expect(a3.first.bud_category.name).to eq('Conv Fixed 20')
169
+
170
+ expect(b1.class).to eq(OpenStruct)
171
+ expect(b2.class).to eq(OpenStruct)
172
+
173
+ # make sure b1-b2 have correct keys and extra stuff
174
+ expect(b1.to_h.keys.to_set).to eq(Set[:buy_up, :buy_down])
175
+ expect(b2.to_h.keys.to_set).to eq(
176
+ Set[:buy_up, :buy_down, :settlement_mm, :settlement_yy,
177
+ :entity, :bud_category])
178
+ expect(b2.entity.name).to eq('PLS')
179
+ expect(b2.bud_category.name).to eq('Conv Fixed 20')
180
+ end
181
+ it "lookup extra values" do
182
+ a2 = @engine.evaluate("A", "lookup_extra", params)
183
+ expect(a2.class).to eq(OpenStruct)
184
+
185
+ # check that extra values are there
186
+ expect(a2.to_h.keys.to_set).to eq(Set[:buy_up, :buy_down, :settlement_mm,
187
+ :settlement_yy, :entity,
188
+ :bud_category])
189
+ # check that linked values are there
190
+ expect(a2.entity.name).to eq("PLS")
191
+ expect(a2.bud_category.name).to eq("Conv Fixed 20")
192
+ end
193
+ it "lookup mode nil extra values" do
194
+ all = @engine.evaluate("A", "lookupn_extra", params)
195
+
196
+ # mode nil always returns AR
197
+ expect(ActiveRecord::Relation === all).to be_truthy
198
+
199
+ # check keys returned
200
+ all.each do |a2|
201
+ expect(a2.attributes.keys.to_set).to eq(
202
+ Set["id", "buy_up", "buy_down", "settlement_mm",
203
+ "settlement_yy", "entity_id", "bud_category_id"])
204
+ if a2.entity_id
205
+ expect(a2.entity.name).to eq("PLS")
206
+ expect(ActiveRecord::Base === a2.entity).to be_truthy
207
+ expect(a2.bud_category.name).to eq("Conv Fixed 20")
208
+ expect(ActiveRecord::Base === a2.bud_category).to be_truthy
209
+ end
210
+ end
211
+ end
212
+ it "lookup mode nil" do
213
+ # make sure ARs are returned
214
+ a1 = @engine.evaluate("A", "lookupn", params)
215
+ a2 = @engine.evaluate("A", "clookupn", params)
216
+ expect(a1).to eq(a2)
217
+ expect(ActiveRecord::Relation === a1).to be_truthy
218
+ expect(a1.to_a.count).to eq(4)
219
+ end
220
+ it "private methods can't be called by delorean" do
221
+ # generated methods
222
+ aggregate_failures "errors" do
223
+ @errs.in_groups_of(2) do |name, fn|
224
+ err = /Too many args to #{fn}/
225
+ expect{Marty::ScriptSet.new.get_engine(name)}.to raise_error(
226
+ Delorean::BadCallError, err)
227
+ end
228
+ end
229
+
230
+ # non-generated
231
+ aggregate_failures "errors" do
232
+ ['E5', 'a_func_p', 'E6', 'b_func_p'].in_groups_of(2) do |scr, fn|
233
+ err = /Too many args to #{fn}/
234
+ expect{Marty::ScriptSet.new.get_engine(scr)}.to raise_error(
235
+ Delorean::BadCallError, err)
236
+ end
237
+ end
238
+ end
239
+ it "caching times" do
240
+ ts = DateTime.now
241
+ x=Benchmark.measure { 10000.times {
242
+ Gemini::FannieBup.a_func(ts,
243
+ 1, 2)
244
+ }
245
+ }
246
+ y=Benchmark.measure { 10000.times {
247
+ Gemini::FannieBup.ca_func(ts,
248
+ 1, 2)
249
+ }
250
+ }
251
+ # x time should be 30x or more than y time
252
+ expect(x.real / y.real).to be > 30
253
+ end
254
+ end
255
+ end
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: 2.0.1
4
+ version: 2.0.2
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: 2018-04-09 00:00:00.000000000 Z
17
+ date: 2018-04-11 00:00:00.000000000 Z
18
18
  dependencies:
19
19
  - !ruby/object:Gem::Dependency
20
20
  name: pg
@@ -1631,6 +1631,7 @@ files:
1631
1631
  - spec/lib/delorean_query_spec.rb
1632
1632
  - spec/lib/json_schema_spec.rb
1633
1633
  - spec/lib/logger_spec.rb
1634
+ - spec/lib/mcfly_model_spec.rb
1634
1635
  - spec/lib/migrations/vw_marty_postings.sql.expected
1635
1636
  - spec/lib/migrations_spec.rb
1636
1637
  - spec/lib/xl_spec.rb