mcfly 0.0.4 → 0.0.5

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.
data/README.md CHANGED
@@ -89,9 +89,14 @@ TODO: discuss using `current_user` method in `ApplicationController`. Also, sett
89
89
 
90
90
  TODO
91
91
 
92
- ## Limitations
92
+ ## Limitations/Requirements
93
93
 
94
- Currently, Mcfly only works with PostgreSQL databases.
94
+ Currently, Mcfly only works with PostgreSQL databases. The following
95
+ line must be added to the `postgresql.conf` file. Mcfly uses the
96
+ PostgreSQL session variable `mcfly.whodunnit` to store the current
97
+ user id.
98
+
99
+ custom_variable_classes = 'mcfly'
95
100
 
96
101
  ## History
97
102
 
data/lib/mcfly.rb CHANGED
@@ -12,6 +12,9 @@ module Mcfly
12
12
  # with models directly.
13
13
  def self.whodunnit=(value)
14
14
  mcfly_store[:whodunnit] = value
15
+
16
+ sval = value.try(:id) || -1
17
+ ActiveRecord::Base.connection.execute("SET mcfly.whodunnit = #{sval};")
15
18
  end
16
19
 
17
20
  def self.whodunnit
@@ -2,12 +2,18 @@ CREATE OR REPLACE FUNCTION "%{table}_delete" ()
2
2
  RETURNS TRIGGER
3
3
  AS $$
4
4
 
5
+ DECLARE
6
+ whodunnit int;
7
+
5
8
  BEGIN
6
9
  IF OLD.obsoleted_dt <> 'infinity' THEN
7
10
  RAISE EXCEPTION 'can not delete old row version';
8
11
  END IF;
9
12
 
10
- UPDATE "%{table}" SET "obsoleted_dt" = 'now()' WHERE id = OLD.id;
13
+ SHOW mcfly.whodunnit INTO whodunnit;
14
+
15
+ UPDATE "%{table}"
16
+ SET "obsoleted_dt" = 'now()', "o_user_id" = whodunnit WHERE id = OLD.id;
11
17
 
12
18
  RETURN NULL; -- the row is not actually deleted
13
19
  END;
@@ -32,11 +32,14 @@ module McFly
32
32
  # obsoleted_dt.
33
33
 
34
34
  send :include, InstanceMethods
35
- after_initialize :record_init
35
+ before_validation :record_validation
36
+
36
37
  # FIXME: :created_dt should also be readonly. However, we set
37
38
  # it for debugging purposes. Should consider making this
38
- # readonly once we're in production.
39
- attr_readonly :group_id, :obsoleted_dt, :user_id
39
+ # readonly once we're in production. Also, :user_id should be
40
+ # read-only. We should only set whodunnit and let PostgreSQL
41
+ # set it.
42
+ attr_readonly :group_id, :obsoleted_dt, :o_user_id #, :user_id
40
43
  end
41
44
 
42
45
  def mcfly_lookup(name, options = {}, &block)
@@ -78,11 +81,12 @@ module McFly
78
81
  end
79
82
 
80
83
  module InstanceMethods
81
- def record_init
82
- # Set obsoleted_dt to non NIL to ensure constraints are properly
83
- # constructed
84
- self.obsoleted_dt = 'infinity' unless self.obsoleted_dt
85
- self.user_id ||= Mcfly.whodunnit.try(:id)
84
+ def record_validation
85
+ if self.changed?
86
+ self.user_id = Mcfly.whodunnit.try(:id)
87
+ self.obsoleted_dt ||= 'infinity'
88
+ end
89
+
86
90
  end
87
91
  end
88
92
 
@@ -25,3 +25,8 @@ $$ LANGUAGE plpgsql;
25
25
  DROP TRIGGER IF EXISTS %{table}_insert ON %{table};
26
26
  CREATE TRIGGER "%{table}_insert" BEFORE INSERT ON "%{table}" FOR EACH ROW
27
27
  EXECUTE PROCEDURE "%{table}_insert"();
28
+
29
+ -- Add constraint to make sure o_user_id is set iff obsoleted_dt is
30
+ -- not infinity (i.e. object is obsoleted).
31
+ ALTER TABLE "%{table}" ADD CONSTRAINT check_o_user
32
+ CHECK ((obsoleted_dt = 'Infinity') = (o_user_id IS NULL));
@@ -14,6 +14,7 @@ class McFlyMigration < ActiveRecord::Migration
14
14
  t.timestamp :created_dt, null: false
15
15
  t.timestamp :obsoleted_dt, null: false
16
16
  t.references :user, null: false
17
+ t.references :o_user
17
18
  block.call(t)
18
19
  }
19
20
 
@@ -13,6 +13,7 @@ BEGIN
13
13
  -- ignored. This is used by DELETE.
14
14
  IF NEW.obsoleted_dt <> 'infinity' THEN
15
15
  OLD.obsoleted_dt = NEW.obsoleted_dt;
16
+ OLD.o_user_id = NEW.o_user_id;
16
17
  return OLD;
17
18
  END IF;
18
19
 
@@ -5,6 +5,7 @@ DECLARE
5
5
  rec "%{table}";
6
6
  new_id INT4;
7
7
  now timestamp;
8
+ whodunnit int;
8
9
 
9
10
  BEGIN
10
11
  IF OLD.obsoleted_dt <> 'infinity' THEN
@@ -15,6 +16,7 @@ BEGIN
15
16
  -- obsoleted. We return the OLD row so that other field updates are
16
17
  -- ignored. This is used by DELETE.
17
18
  IF NEW.obsoleted_dt <> 'infinity' THEN
19
+ OLD.o_user_id = NEW.o_user_id;
18
20
  OLD.obsoleted_dt = NEW.obsoleted_dt;
19
21
  return OLD;
20
22
  END IF;
@@ -31,7 +33,8 @@ BEGIN
31
33
 
32
34
  rec.id = new_id;
33
35
  rec.group_id = NEW.id;
34
-
36
+ rec.o_user_id = NEW.user_id;
37
+
35
38
  -- FIXME: The following IF/ELSE handles cases where created_dt is
36
39
  -- sent in on update. This is only useful for debugging. Consider
37
40
  -- removing the surronding IF (and ELSE part) for production
data/lib/mcfly/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Mcfly
2
- VERSION = "0.0.4"
2
+ VERSION = "0.0.5"
3
3
  end
@@ -18,6 +18,7 @@ ActiveRecord::Schema.define(:version => 2) do
18
18
  t.datetime "created_dt", :null => false
19
19
  t.datetime "obsoleted_dt", :null => false
20
20
  t.integer "user_id", :null => false
21
+ t.integer "o_user_id"
21
22
  t.integer "security_instrument_id", :null => false
22
23
  t.decimal "coupon", :null => false
23
24
  t.integer "settlement_mm", :null => false
@@ -30,6 +31,7 @@ ActiveRecord::Schema.define(:version => 2) do
30
31
  t.datetime "created_dt", :null => false
31
32
  t.datetime "obsoleted_dt", :null => false
32
33
  t.integer "user_id", :null => false
34
+ t.integer "o_user_id"
33
35
  t.string "name", :null => false
34
36
  t.string "settlement_class", :limit => 1, :null => false
35
37
  end
data/spec/model_spec.rb CHANGED
@@ -182,7 +182,7 @@ describe "Mcfly" do
182
182
 
183
183
  it "should be able to delete objects" do
184
184
  si = SecurityInstrument.find_by_name("FN Fix-30 Cash")
185
- dt = DateTime.now
185
+ dt = '2010-01-01 08:00 PST8PDT'
186
186
 
187
187
  mp = MarketPrice.lookup_si(dt, si)
188
188
  mp.obsoleted_dt.should == Float::INFINITY
@@ -203,4 +203,37 @@ describe "Mcfly" do
203
203
  }.should raise_error(ActiveRecord::StatementInvalid)
204
204
  end
205
205
 
206
+ it "whodunnit should set user/o_user on CRUD" do
207
+ Mcfly.whodunnit = TestUser.new(20)
208
+
209
+ si = SecurityInstrument.find_by_name("FN Fix-30 Cash")
210
+ dt = '2010-01-01 08:00 PST8PDT'
211
+
212
+ sleep 1.seconds
213
+
214
+ mp = MarketPrice.lookup_si(dt, si)
215
+ mp.user_id.should == 10
216
+
217
+ mp.price = 123
218
+ mp.save!
219
+
220
+ # old version should still have original creator user
221
+ mp = MarketPrice.lookup_si(dt, si)
222
+ mp.user_id.should == 10
223
+ mp.o_user_id.should == 20
224
+
225
+ # new version should have new creator
226
+ mp = MarketPrice.lookup_si('infinity', si)
227
+ mp.user_id.should == 20
228
+ mp.o_user_id.should == nil
229
+
230
+ rid = mp.id
231
+
232
+ Mcfly.whodunnit = TestUser.new(30)
233
+
234
+ mp.delete
235
+ mp = MarketPrice.find(rid)
236
+ mp.o_user_id.should == 30
237
+ end
238
+
206
239
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mcfly
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-06-05 00:00:00.000000000 Z
12
+ date: 2013-06-07 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -148,7 +148,6 @@ files:
148
148
  - spec/dummy/db/schema.rb
149
149
  - spec/dummy/lib/assets/.gitkeep
150
150
  - spec/dummy/log/.gitkeep
151
- - spec/dummy/log/development.log
152
151
  - spec/dummy/public/404.html
153
152
  - spec/dummy/public/422.html
154
153
  - spec/dummy/public/500.html