switch_point 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d4e8e6fce7bc9a152422f2b1ede1df15b39791c6
4
- data.tar.gz: 785d1e66b759b372edb68201454238bd62879ef1
3
+ metadata.gz: d745412c8403805b7d7221bd0873e96156fbf117
4
+ data.tar.gz: a3ebbfe8088491a63e86525f6e10e045c4c7b90e
5
5
  SHA512:
6
- metadata.gz: 83d13eaf42dcc9e266c1bc3e703b04798ca0bb17473591a819e36c09eb40a294e3a4c57b42970428a9b09f159ac3a20a443d2f158ced0a5f309cd894ebe6d769
7
- data.tar.gz: e5c054d22e52bcb1f37ba3d46fb6487b1a462b53f7b443fd9f389195bdd0ed668bd5a3b9df13006a0b2104047febe8b87b02b46e59e8e5ea1342d2f4bbd86741
6
+ metadata.gz: 0288d5f1aee3e3a1bbe3e7816f728628f795f0903fa0ce32b1b96bfe54284b4fcd20260f3dbdd2b8fbdb93fee24779b6921f0fce30d13a5b5232b7e92402fb12
7
+ data.tar.gz: d58730ca9ec1cae341942d644600d87b523cadf64b3ce3d78ee65791ebb3c4c9f487843b524f9ec194b18a857ca7220a53dd05a72a18b6d193268eec36052dff
@@ -1,3 +1,8 @@
1
+ ## 0.4.0 (2014-06-17)
2
+ - auto_writable is disabled by default
3
+ - To restore the previous behavior, set `config.auto_writable = true`.
4
+ - Add shorthand methods `SwitchPoint.with_readonly`, `SwitchPoint.with_writable`
5
+
1
6
  ## 0.3.1 (2014-06-04)
2
7
  - Support defaulting to writable ActiveRecord::Base connection
3
8
  - When `:writable` key is omitted, ActiveRecord::Base is used for the writable connection.
data/README.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # SwitchPoint
2
+ [![Gem Version](https://badge.fury.io/rb/switch_point.svg)](http://badge.fury.io/rb/switch_point)
2
3
  [![Build Status](https://travis-ci.org/eagletmt/switch_point.svg?branch=master)](https://travis-ci.org/eagletmt/switch_point)
4
+ [![Coverage Status](https://coveralls.io/repos/eagletmt/switch_point/badge.png?branch=master)](https://coveralls.io/r/eagletmt/switch_point?branch=master)
5
+ [![Code Climate](https://codeclimate.com/github/eagletmt/switch_point.png)](https://codeclimate.com/github/eagletmt/switch_point)
3
6
 
4
7
  Switching database connection between readonly one and writable one.
5
8
 
@@ -21,6 +24,40 @@ Or install it yourself as:
21
24
 
22
25
  See [spec/models](spec/models.rb).
23
26
 
27
+ ### auto_writable
28
+ `auto_writable` is disabled by default.
29
+
30
+ When `auto_writable` is enabled, destructive queries is sent to writable connection even in readonly mode.
31
+ But it does NOT work well on transactions.
32
+
33
+ Suppose `after_save` callback is set to User model. When `User.create` is called, it proceeds as follows.
34
+
35
+ 1. BEGIN TRANSACTION is sent to READONLY connection.
36
+ 2. switch_point switches the connection to WRITABLE.
37
+ 3. CREATE statement is sent to WRITABLE connection.
38
+ 4. switch_point reset the connection to READONLY.
39
+ 5. after_save callback is called.
40
+ - At this point, the connection is READONLY and in a transaction.
41
+ 6. COMMIT TRANSACTION is sent to READONLY connection.
42
+
43
+ ## Internals
44
+ There's a proxy which holds two connections: readonly one and writable one.
45
+ A proxy has a thread-local state indicating the current mode: readonly or writable.
46
+
47
+ Each ActiveRecord model refers to a proxy.
48
+ `ActiveRecord::Base.connection` is hooked and delegated to the referred proxy.
49
+
50
+ When the writable connection is requested to execute destructive query, the readonly connection clears its query cache.
51
+
52
+ ![switch_point](http://gyazo.wanko.cc/switch_point.svg)
53
+
54
+ ### Special case: ActiveRecord::Base.connection
55
+ Basically, each connection managed by a proxy isn't shared between proxies.
56
+ But there's one exception: ActiveRecord::Base.
57
+
58
+ If `:writable` key is omitted (e.g., Nanika1 model in spec/models), it uses `ActiveRecord::Base.connection` as writable one.
59
+ When `ActiveRecord::Base.connection` is requested to execute destructive query, all readonly connections managed by a proxy which uses `ActiveRecord::Base.connection` as a writable connection clear query cache.
60
+
24
61
  ## Contributing
25
62
 
26
63
  1. Fork it ( https://github.com/eagletmt/switch_point/fork )
@@ -0,0 +1,2 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <svg contentScriptType="text/ecmascript" xmlns:xlink="http://www.w3.org/1999/xlink" zoomAndPan="magnify" contentStyleType="text/css" viewBox="74.0 85.0 534.0 434.1035" xmlns:cacoo="http://cacoo.com/" preserveAspectRatio="xMidYMin meet" xmlns="http://www.w3.org/2000/svg" version="1.1"><defs><marker refX="14.0" refY="7.0" markerUnits="userSpaceOnUse" orient="auto" id="id4" markerHeight="14.0" viewBox="0 0 14.0 14.0" preserveAspectRatio="xMidYMid meet" markerWidth="14.0" overflow="visible"><path fill="none" d="M0 0 L14.0 7.0 L0 14.0" stroke-width="2.0" stroke-linejoin="round" stroke-linecap="round" stroke="#e33933"/></marker><marker refX="14.0" refY="7.0" markerUnits="userSpaceOnUse" orient="auto" id="id5" markerHeight="14.0" viewBox="0 0 14.0 14.0" preserveAspectRatio="xMidYMid meet" markerWidth="14.0" overflow="visible"><path fill="none" d="M0 0 L14.0 7.0 L0 14.0" stroke-width="2.0" stroke-linejoin="round" stroke-linecap="round" stroke="#e33933"/></marker><marker refX="14.0" refY="7.0" markerUnits="userSpaceOnUse" orient="auto" id="id6" markerHeight="14.0" viewBox="0 0 14.0 14.0" preserveAspectRatio="xMidYMid meet" markerWidth="14.0" overflow="visible"><path fill="none" d="M0 0 L14.0 7.0 L0 14.0" stroke-width="2.0" stroke-linejoin="round" stroke-linecap="round" stroke="#97d077"/></marker><marker refX="14.0" refY="7.0" markerUnits="userSpaceOnUse" orient="auto" id="id7" markerHeight="14.0" viewBox="0 0 14.0 14.0" preserveAspectRatio="xMidYMid meet" markerWidth="14.0" overflow="visible"><path fill="none" d="M0 0 L14.0 7.0 L0 14.0" stroke-width="2.0" stroke-linejoin="round" stroke-linecap="round" stroke="#97d077"/></marker><marker refX="14.0" refY="7.0" markerUnits="userSpaceOnUse" orient="auto" id="id15" markerHeight="14.0" viewBox="0 0 14.0 14.0" preserveAspectRatio="xMidYMid meet" markerWidth="14.0" overflow="visible"><path fill="none" d="M0 0 L14.0 7.0 L0 14.0" stroke-width="2.0" stroke-linejoin="round" stroke-linecap="round" stroke="#000000"/></marker><marker refX="14.0" refY="7.0" markerUnits="userSpaceOnUse" orient="auto" id="id16" markerHeight="14.0" viewBox="0 0 14.0 14.0" preserveAspectRatio="xMidYMid meet" markerWidth="14.0" overflow="visible"><path fill="none" d="M0 0 L14.0 7.0 L0 14.0" stroke-width="2.0" stroke-linejoin="round" stroke-linecap="round" stroke="#000000"/></marker><marker refX="14.0" refY="7.0" markerUnits="userSpaceOnUse" orient="auto" id="id17" markerHeight="14.0" viewBox="0 0 14.0 14.0" preserveAspectRatio="xMidYMid meet" markerWidth="14.0" overflow="visible"><path fill="none" d="M0 0 L14.0 7.0 L0 14.0" stroke-width="2.0" stroke-linejoin="round" stroke-linecap="round" stroke="#000000"/></marker><marker refX="14.0" refY="7.0" markerUnits="userSpaceOnUse" orient="auto" id="id26" markerHeight="14.0" viewBox="0 0 14.0 14.0" preserveAspectRatio="xMidYMid meet" markerWidth="14.0" overflow="visible"><path fill="none" d="M0 0 L14.0 7.0 L0 14.0" stroke-width="2.0" stroke-linejoin="round" stroke-linecap="round" stroke="#000000"/></marker><marker refX="14.0" refY="7.0" markerUnits="userSpaceOnUse" orient="auto" id="id27" markerHeight="14.0" viewBox="0 0 14.0 14.0" preserveAspectRatio="xMidYMid meet" markerWidth="14.0" overflow="visible"><path fill="none" d="M0 0 L14.0 7.0 L0 14.0" stroke-width="2.0" stroke-linejoin="round" stroke-linecap="round" stroke="#e33933"/></marker><marker refX="14.0" refY="7.0" markerUnits="userSpaceOnUse" orient="auto" id="id28" markerHeight="14.0" viewBox="0 0 14.0 14.0" preserveAspectRatio="xMidYMid meet" markerWidth="14.0" overflow="visible"><path fill="none" d="M0 0 L14.0 7.0 L0 14.0" stroke-width="2.0" stroke-linejoin="round" stroke-linecap="round" stroke="#74c14a"/></marker></defs><g><g transform="translate(529.0 140.8965)"><path fill="#ffffff" fill-opacity="1.0" d="M0.0 6.0 L64.00000000000006 6.0 L64.00000000000006 52.5 Q64.00000000000006 54.98528137423857 54.62741699796954 56.742640687119284 Q45.25483399593911 58.5 32.00000000000002 58.5 Q18.745166004060973 58.5 9.372583002030485 56.742640687119284 Q0.0 54.98528137423857 0.0 52.5 L0.0 6.0z" stroke-width="1.0" stroke-linejoin="round" stroke="#000000"/><path fill="#ffffff" fill-opacity="1.0" d="M64.00000000000006 6.0 Q64.00000000000006 8.485281374238571 54.62741699796954 10.242640687119284 Q45.25483399593911 11.999999999999998 32.00000000000003 12.0 Q18.745166004060973 12.0 9.372583002030488 10.242640687119286 Q0.0 8.485281374238571 0.0 6.000000000000001 Q0.0 3.5147186257614313 9.372583002030485 1.7573593128807152 Q18.745166004060973 8.881784197001252E-16 32.00000000000002 0.0 Q45.25483399593911 -8.881784197001252E-16 54.62741699796954 1.7573593128807143 Q64.00000000000006 3.5147186257614287 64.00000000000006 6.0z" stroke-width="1.0" stroke-linejoin="round" stroke="#000000"/><g transform="translate(0.0 12.0)"><clipPath id="id0"><path d="M0 0 L64.0 0 L64.0 46.5 L0 46.5z"/></clipPath><text font-size="12" clip-path="url(#id0)" text-decoration="none" fill="#000000" font-family="Arial,Arial" font-style="normal" font-weight="normal"><tspan x="18.0" xml:space="preserve" y="19.25" textLength="28.0">main</tspan><tspan x="11.0" xml:space="preserve" y="36.25" textLength="41.0">master</tspan></text></g></g><g transform="translate(529.0 376.8965)"><path fill="#ffffff" fill-opacity="1.0" d="M0.0 6.0 L63.99999999999992 6.0 L63.99999999999992 52.5 Q63.99999999999992 54.98528137423857 54.62741699796942 56.742640687119284 Q45.25483399593904 58.5 31.999999999999932 58.5 Q18.745166004060934 58.5 9.372583002030463 56.742640687119284 Q0.0 54.98528137423857 0.0 52.5 L0.0 6.0z" stroke-width="1.0" stroke-linejoin="round" stroke="#000000"/><path fill="#ffffff" fill-opacity="1.0" d="M63.99999999999992 6.0 Q63.99999999999992 8.485281374238571 54.62741699796942 10.242640687119284 Q45.25483399593904 11.999999999999998 31.99999999999996 12.0 Q18.74516600406094 12.0 9.37258300203047 10.242640687119286 Q0.0 8.485281374238571 0.0 6.000000000000001 Q0.0 3.5147186257614313 9.372583002030463 1.7573593128807152 Q18.745166004060934 8.881784197001252E-16 31.999999999999932 0.0 Q45.25483399593904 -8.881784197001252E-16 54.62741699796942 1.7573593128807143 Q63.99999999999992 3.5147186257614287 63.99999999999992 6.0z" stroke-width="1.0" stroke-linejoin="round" stroke="#000000"/><g transform="translate(0.0 12.0)"><clipPath id="id1"><path d="M0 0 L64.0 0 L64.0 46.5 L0 46.5z"/></clipPath><text font-size="12" clip-path="url(#id1)" text-decoration="none" fill="#000000" font-family="Arial,Arial" font-style="normal" font-weight="normal"><tspan x="9.0" xml:space="preserve" y="19.25" textLength="46.0">commet</tspan><tspan x="11.0" xml:space="preserve" y="36.25" textLength="41.0">master</tspan></text></g></g><g transform="translate(293.5289580126552 170.1465)"><path fill="#ffffff" fill-opacity="1.0" d="M51.74956447969533 68.4248898947933 L0.424969148024419 34.35350099488455 L51.74956447969533 0.28211209497580036 L103.07415981136624 34.35350099488455 L51.74956447969533 68.4248898947933 L51.74956447969533 68.4248898947933z" stroke-width="1.0" stroke-linejoin="round" stroke="#000000"/><g transform="translate(20.199307221852635 21.163783014064215)"><clipPath id="id2"><path d="M0 0 L62.58726465655704 0 L62.58726465655704 26.463928188151897 L0 26.463928188151897z"/></clipPath><text font-size="12" clip-path="url(#id2)" text-decoration="none" fill="#000000" font-family="Arial,Arial" font-style="normal" font-weight="normal"><tspan x="17.0" xml:space="preserve" y="17.73196409407595" textLength="28.0">main</tspan></text></g></g><g transform="translate(293.5289580126552 406.1465)"><path fill="#ffffff" fill-opacity="1.0" d="M51.381583974689526 68.70699999999998 L7.148564543362447E-16 34.35349999999998 L51.381583974689526 -5.911707234851347E-15 L102.76316794937905 34.35349999999998 L51.381583974689526 68.70699999999998 L51.381583974689526 68.70699999999998z" stroke-width="1.0" stroke-linejoin="round" stroke="#000000"/><g transform="translate(19.79629465597243 21.054571154298447)"><clipPath id="id3"><path d="M0 0 L62.65675888753867 0 L62.65675888753867 26.683049513549793 L0 26.683049513549793z"/></clipPath><text font-size="12" clip-path="url(#id3)" text-decoration="none" fill="#000000" font-family="Arial,Arial" font-style="normal" font-weight="normal"><tspan x="5.0" xml:space="preserve" y="17.841524756774895" textLength="53.0">comment</tspan></text></g></g><path fill="none" marker-end="url(#id4)" d="M370.94082015818594 187.46430654493017 L529.0 170.1465" stroke-width="2.0" stroke-linejoin="round" stroke="#e33933"/><path fill="none" marker-end="url(#id5)" d="M370.6013339746895 423.32325 L529.0 406.1465" stroke-width="2.0" stroke-linejoin="round" stroke="#e33933"/><path fill="none" marker-end="url(#id6)" d="M370.6013339746895 457.67674999999997 L529.0 474.8535" stroke-width="2.0" stroke-linejoin="round" stroke="#97d077"/><path fill="none" marker-end="url(#id7)" d="M370.94082015818594 221.53569544483895 L529.0 233.75752170027454" stroke-width="2.0" stroke-linejoin="round" stroke="#97d077"/><g transform="translate(389.0 160.1465)"><clipPath id="id8"><path d="M0 0 L58.0 0 L58.0 20.0 L0 20.0z"/></clipPath><text font-size="12" clip-path="url(#id8)" text-decoration="none" fill="#000000" font-family="Arial,Arial" font-style="normal" font-weight="normal"><tspan x="2.0" xml:space="preserve" y="15.0" textLength="50.0">writable</tspan></text></g><g transform="translate(389.0 225.3535)"><clipPath id="id9"><path d="M0 0 L58.0 0 L58.0 27.0 L0 27.0z"/></clipPath><text font-size="12" clip-path="url(#id9)" text-decoration="none" fill="#000000" font-family="Arial,Arial" font-style="normal" font-weight="normal"><tspan x="2.0" xml:space="preserve" y="15.0" textLength="51.0">readonly</tspan></text></g><g transform="translate(389.0 396.1465)"><clipPath id="id10"><path d="M0 0 L58.0 0 L58.0 20.0 L0 20.0z"/></clipPath><text font-size="12" clip-path="url(#id10)" text-decoration="none" fill="#000000" font-family="Arial,Arial" font-style="normal" font-weight="normal"><tspan x="2.0" xml:space="preserve" y="15.0" textLength="50.0">writable</tspan></text></g><g transform="translate(389.0 461.3535)"><clipPath id="id11"><path d="M0 0 L58.0 0 L58.0 27.0 L0 27.0z"/></clipPath><text font-size="12" clip-path="url(#id11)" text-decoration="none" fill="#000000" font-family="Arial,Arial" font-style="normal" font-weight="normal"><tspan x="2.0" xml:space="preserve" y="15.0" textLength="51.0">readonly</tspan></text></g><g transform="translate(116.5 213.8535)"><path fill="#ffffff" fill-opacity="1.0" d="M115.00000000000001 25.0 Q115.00000000000001 35.354843 98.15939999999996 42.67725 Q81.31799499999998 50.0 57.50000000000001 50.0 Q33.68292499999999 50.0 16.841465489999997 42.677624 Q0.0 35.35525 0.0 25.0 Q0.0 14.64475 16.841463189999995 7.3223763 Q33.68292499999999 0.0 57.50000000000001 0.0 Q81.31840209999994 0.0 98.15939999999996 7.3223753 Q115.00000000000001 14.644578 115.00000000000001 25.0 L115.00000000000001 25.0z" stroke-width="1.0" stroke-linejoin="round" stroke="#000000"/><g transform="translate(15.920599842071528 7.961000442504883)"><clipPath id="id12"><path d="M0 0 L83.16799964904784 0 L83.16799964904784 33.847999572753906 L0 33.847999572753906z"/></clipPath><text font-size="12" clip-path="url(#id12)" text-decoration="none" fill="#000000" font-family="Arial,Arial" font-style="normal" font-weight="normal"><tspan x="14.0" xml:space="preserve" y="21.423999786376953" textLength="54.0">Publisher</tspan></text></g></g><g transform="translate(116.5 145.1465)"><path fill="#ffffff" fill-opacity="1.0" d="M115.00000000000001 25.0 Q115.00000000000001 35.354843 98.15939999999996 42.67725 Q81.31799499999998 50.0 57.50000000000001 50.0 Q33.68292499999999 50.0 16.841465489999997 42.677624 Q0.0 35.35525 0.0 25.0 Q0.0 14.64475 16.841463189999995 7.3223763 Q33.68292499999999 0.0 57.50000000000001 0.0 Q81.31840209999994 0.0 98.15939999999996 7.3223753 Q115.00000000000001 14.644578 115.00000000000001 25.0 L115.00000000000001 25.0z" stroke-width="1.0" stroke-linejoin="round" stroke="#000000"/><g transform="translate(15.920599842071528 7.961000442504883)"><clipPath id="id13"><path d="M0 0 L83.16799964904784 0 L83.16799964904784 33.847999572753906 L0 33.847999572753906z"/></clipPath><text font-size="12" clip-path="url(#id13)" text-decoration="none" fill="#000000" font-family="Arial,Arial" font-style="normal" font-weight="normal"><tspan x="27.0" xml:space="preserve" y="21.423999786376953" textLength="28.0">Book</tspan></text></g></g><g transform="translate(116.5 415.5)"><path fill="#ffffff" fill-opacity="1.0" d="M115.00000000000001 25.0 Q115.00000000000001 35.354843 98.15939999999996 42.67725 Q81.31799499999998 50.0 57.50000000000001 50.0 Q33.68292499999999 50.0 16.841465489999997 42.677624 Q0.0 35.35525 0.0 25.0 Q0.0 14.64475 16.841463189999995 7.3223763 Q33.68292499999999 0.0 57.50000000000001 0.0 Q81.31840209999994 0.0 98.15939999999996 7.3223753 Q115.00000000000001 14.644578 115.00000000000001 25.0 L115.00000000000001 25.0z" stroke-width="1.0" stroke-linejoin="round" stroke="#000000"/><g transform="translate(14.920599842071528 7.961000442504883)"><clipPath id="id14"><path d="M0 0 L83.16799964904784 0 L83.16799964904784 33.847999572753906 L0 33.847999572753906z"/></clipPath><text font-size="12" clip-path="url(#id14)" text-decoration="none" fill="#000000" font-family="Arial,Arial" font-style="normal" font-weight="normal"><tspan x="14.0" xml:space="preserve" y="21.423999786376953" textLength="55.0">Comment</tspan></text></g></g><path fill="none" stroke-linejoin="round" stroke-dasharray="6.0 2.0" d="M231.5 170.1465 L319.61622482651507 187.46430654493017" stroke="#000000" stroke-width="2.0" marker-end="url(#id15)"/><path fill="none" stroke-linejoin="round" stroke-dasharray="6.0 2.0" d="M231.5 238.8535 L319.61622482651507 221.53569544483895" stroke="#000000" stroke-width="2.0" marker-end="url(#id16)"/><path fill="none" stroke-linejoin="round" stroke-dasharray="6.0 2.0" d="M231.5 440.5 L293.5289580126552 440.5" stroke="#000000" stroke-width="2.0" marker-end="url(#id17)"/><g transform="translate(89.0 100.0)"><clipPath id="id18"><path d="M0 0 L176.0 0 L176.0 20.0 L0 20.0z"/></clipPath><text font-size="12" clip-path="url(#id18)" text-decoration="none" fill="#000000" font-family="Arial,Arial" font-style="normal" font-weight="bold"><tspan x="2.0" xml:space="preserve" y="15.0" textLength="169.0">Model &lt; ActiveRecord::Base</tspan></text></g><g transform="translate(322.91054198734474 100.0)"><clipPath id="id19"><path d="M0 0 L44.0 0 L44.0 20.0 L0 20.0z"/></clipPath><text font-size="12" clip-path="url(#id19)" text-decoration="none" fill="#000000" font-family="Arial,Arial" font-style="normal" font-weight="bold"><tspan x="2.0" xml:space="preserve" y="15.0" textLength="35.0">Proxy</tspan></text></g><g transform="translate(116.5 299.1465)"><path fill="#ffffff" fill-opacity="1.0" d="M115.00000000000001 25.0 Q115.00000000000001 35.354843 98.15940000000002 42.67725 Q81.31799500000004 50.0 57.50000000000001 50.0 Q33.68292500000001 50.0 16.84146549 42.677624 Q0.0 35.35525 0.0 25.0 Q0.0 14.64475 16.84146319000001 7.3223763 Q33.68292500000001 0.0 57.50000000000001 0.0 Q81.31840210000003 0.0 98.15940000000002 7.3223753 Q115.00000000000001 14.644578 115.00000000000001 25.0 L115.00000000000001 25.0z" stroke-width="1.0" stroke-linejoin="round" stroke="#000000"/><g transform="translate(14.92059984207154 7.961000442504883)"><clipPath id="id20"><path d="M0 0 L83.16799964904786 0 L83.16799964904786 33.847999572753906 L0 33.847999572753906z"/></clipPath><text font-size="12" clip-path="url(#id20)" text-decoration="none" fill="#000000" font-family="Arial,Arial" font-style="normal" font-weight="normal"><tspan x="18.0" xml:space="preserve" y="21.423999786376953" textLength="46.0">BigData</tspan></text></g></g><g transform="translate(293.95090530472953 290.0751120949758)"><path fill="#ffffff" fill-opacity="1.0" d="M50.95963817063662 68.14277779981754 L-1.5432100042289676E-14 34.071388899908776 L50.95963817063662 1.3489209749195652E-14 L101.91927634127326 34.071388899908776 L50.95963817063662 68.14277779981754 L50.95963817063662 68.14277779981754z" stroke-width="1.0" stroke-linejoin="round" stroke="#000000"/><g transform="translate(19.633727393157077 20.881670919088414)"><clipPath id="id21"><path d="M0 0 L62.14222129521437 0 L62.14222129521437 26.463928188151918 L0 26.463928188151918z"/></clipPath><text font-size="12" clip-path="url(#id21)" text-decoration="none" fill="#000000" font-family="Arial,Arial" font-style="normal" font-weight="normal"><tspan x="10.0" xml:space="preserve" y="17.73196409407596" textLength="41.0">special</tspan></text></g></g><g transform="translate(529.0 294.89650099488455)"><path fill="#ffffff" fill-opacity="1.0" d="M0.0 6.0 L63.99999999999999 6.0 L63.99999999999999 52.5 Q63.99999999999999 54.98528137423857 54.6274169979695 56.742640687119284 Q45.254833995939045 58.5 31.999999999999975 58.5 Q18.74516600406095 58.5 9.37258300203047 56.742640687119284 Q0.0 54.98528137423857 0.0 52.5 L0.0 6.0z" stroke-width="1.0" stroke-linejoin="round" stroke="#000000"/><path fill="#ffffff" fill-opacity="1.0" d="M63.99999999999999 6.0 Q63.99999999999999 8.485281374238571 54.6274169979695 10.242640687119284 Q45.254833995939045 11.999999999999998 31.999999999999996 12.0 Q18.745166004060952 12.0 9.37258300203048 10.242640687119286 Q0.0 8.485281374238571 0.0 6.000000000000001 Q0.0 3.5147186257614313 9.37258300203047 1.7573593128807152 Q18.74516600406095 8.881784197001252E-16 31.999999999999975 0.0 Q45.254833995939045 -8.881784197001252E-16 54.6274169979695 1.7573593128807143 Q63.99999999999999 3.5147186257614287 63.99999999999999 6.0z" stroke-width="1.0" stroke-linejoin="round" stroke="#000000"/><g transform="translate(0.0 12.0)"><clipPath id="id22"><path d="M0 0 L64.0 0 L64.0 46.5 L0 46.5z"/></clipPath><text font-size="12" clip-path="url(#id22)" text-decoration="none" fill="#000000" font-family="Arial,Arial" font-style="normal" font-weight="normal"><tspan x="18.0" xml:space="preserve" y="10.75" textLength="28.0">main</tspan><tspan x="11.0" xml:space="preserve" y="27.75" textLength="41.0">special</tspan><tspan x="16.0" xml:space="preserve" y="44.75" textLength="31.0">slave</tspan></text></g></g><g transform="translate(529.0 209.6035)"><path fill="#ffffff" fill-opacity="1.0" d="M0.0 6.0 L64.00000000000006 6.0 L64.00000000000006 52.5 Q64.00000000000006 54.98528137423857 54.62741699796954 56.742640687119284 Q45.25483399593911 58.5 32.00000000000002 58.5 Q18.745166004060973 58.5 9.372583002030485 56.742640687119284 Q0.0 54.98528137423857 0.0 52.5 L0.0 6.0z" stroke-width="1.0" stroke-linejoin="round" stroke="#000000"/><path fill="#ffffff" fill-opacity="1.0" d="M64.00000000000006 6.0 Q64.00000000000006 8.485281374238571 54.62741699796954 10.242640687119284 Q45.25483399593911 11.999999999999998 32.00000000000003 12.0 Q18.745166004060973 12.0 9.372583002030488 10.242640687119286 Q0.0 8.485281374238571 0.0 6.000000000000001 Q0.0 3.5147186257614313 9.372583002030485 1.7573593128807152 Q18.745166004060973 8.881784197001252E-16 32.00000000000002 0.0 Q45.25483399593911 -8.881784197001252E-16 54.62741699796954 1.7573593128807143 Q64.00000000000006 3.5147186257614287 64.00000000000006 6.0z" stroke-width="1.0" stroke-linejoin="round" stroke="#000000"/><g transform="translate(0.0 12.0)"><clipPath id="id23"><path d="M0 0 L64.0 0 L64.0 46.5 L0 46.5z"/></clipPath><text font-size="12" clip-path="url(#id23)" text-decoration="none" fill="#000000" font-family="Arial,Arial" font-style="normal" font-weight="normal"><tspan x="18.0" xml:space="preserve" y="19.25" textLength="28.0">main</tspan><tspan x="16.0" xml:space="preserve" y="36.25" textLength="31.0">slave</tspan></text></g></g><g transform="translate(529.0 445.6035)"><path fill="#ffffff" fill-opacity="1.0" d="M0.0 6.0 L64.00000000000006 6.0 L64.00000000000006 52.5 Q64.00000000000006 54.98528137423857 54.62741699796954 56.742640687119284 Q45.25483399593911 58.5 32.00000000000002 58.5 Q18.745166004060973 58.5 9.372583002030485 56.742640687119284 Q0.0 54.98528137423857 0.0 52.5 L0.0 6.0z" stroke-width="1.0" stroke-linejoin="round" stroke="#000000"/><path fill="#ffffff" fill-opacity="1.0" d="M64.00000000000006 6.0 Q64.00000000000006 8.485281374238571 54.62741699796954 10.242640687119284 Q45.25483399593911 11.999999999999998 32.00000000000003 12.0 Q18.745166004060973 12.0 9.372583002030488 10.242640687119286 Q0.0 8.485281374238571 0.0 6.000000000000001 Q0.0 3.5147186257614313 9.372583002030485 1.7573593128807152 Q18.745166004060973 8.881784197001252E-16 32.00000000000002 0.0 Q45.25483399593911 -8.881784197001252E-16 54.62741699796954 1.7573593128807143 Q64.00000000000006 3.5147186257614287 64.00000000000006 6.0z" stroke-width="1.0" stroke-linejoin="round" stroke="#000000"/><g transform="translate(0.0 12.0)"><clipPath id="id24"><path d="M0 0 L64.0 0 L64.0 46.5 L0 46.5z"/></clipPath><text font-size="12" clip-path="url(#id24)" text-decoration="none" fill="#000000" font-family="Arial,Arial" font-style="normal" font-weight="normal"><tspan x="5.0" xml:space="preserve" y="19.25" textLength="53.0">comment</tspan><tspan x="16.0" xml:space="preserve" y="36.25" textLength="31.0">slave</tspan></text></g></g><g transform="translate(529.0 100.0)"><clipPath id="id25"><path d="M0 0 L64.0 0 L64.0 20.0 L0 20.0z"/></clipPath><text font-size="12" clip-path="url(#id25)" text-decoration="none" fill="#000000" font-family="Arial,Arial" font-style="normal" font-weight="bold"><tspan x="2.0" xml:space="preserve" y="15.0" textLength="55.0">Database</tspan></text></g><path fill="none" stroke-linejoin="round" stroke-dasharray="6.0 2.0" d="M231.5 324.1465 L293.95090530472953 324.14650099488455" stroke="#000000" stroke-width="2.0" marker-end="url(#id26)"/><path fill="none" marker-end="url(#id27)" d="M370.3903625606845 307.1108065449302 L529.0 184.77149999999997" stroke-width="2.0" stroke-linejoin="round" stroke="#e33933"/><path fill="none" marker-end="url(#id28)" d="M370.3903625606845 341.18219544483895 L529.0 324.14650099488455" stroke-width="2.0" stroke-linejoin="round" stroke="#74c14a"/><g transform="translate(389.0 344.7178898947933)"><clipPath id="id29"><path d="M0 0 L58.0 0 L58.0 27.0 L0 27.0z"/></clipPath><text font-size="12" clip-path="url(#id29)" text-decoration="none" fill="#000000" font-family="Arial,Arial" font-style="normal" font-weight="normal"><tspan x="2.0" xml:space="preserve" y="15.0" textLength="51.0">readonly</tspan></text></g><g transform="translate(395.87018164600283 280.0751120949758)"><clipPath id="id30"><path d="M0 0 L58.0 0 L58.0 20.0 L0 20.0z"/></clipPath><text font-size="12" clip-path="url(#id30)" text-decoration="none" fill="#000000" font-family="Arial,Arial" font-style="normal" font-weight="normal"><tspan x="2.0" xml:space="preserve" y="15.0" textLength="50.0">writable</tspan></text></g></g></svg>
@@ -31,6 +31,22 @@ module SwitchPoint
31
31
  def writable!(name)
32
32
  ProxyRepository.checkout(name).writable!
33
33
  end
34
+
35
+ def with_readonly(*names, &block)
36
+ with_connection(:readonly, *names, &block)
37
+ end
38
+
39
+ def with_writable(*names, &block)
40
+ with_connection(:writable, *names, &block)
41
+ end
42
+
43
+ def with_connection(mode, *names, &block)
44
+ names.reverse.inject(block) do |func, name|
45
+ lambda do
46
+ ProxyRepository.checkout(name).with_connection(mode, &func)
47
+ end
48
+ end.call
49
+ end
34
50
  end
35
51
  extend ClassMethods
36
52
  end
@@ -1,10 +1,22 @@
1
1
  module SwitchPoint
2
2
  class Config
3
+ def initialize
4
+ self.auto_writable = false
5
+ end
6
+
3
7
  def define_switch_point(name, config)
4
8
  assert_valid_config!(config)
5
9
  switch_points[name] = config
6
10
  end
7
11
 
12
+ def auto_writable=(val)
13
+ @auto_writable = val
14
+ end
15
+
16
+ def auto_writable?
17
+ @auto_writable
18
+ end
19
+
8
20
  def switch_points
9
21
  @switch_points ||= {}
10
22
  end
@@ -16,6 +16,9 @@ module SwitchPoint
16
16
  end
17
17
  end
18
18
 
19
+ class ReadonlyError < StandardError
20
+ end
21
+
19
22
  def self.handle_base_connection(conn, parent_method, *args, &block)
20
23
  switch_points = conn.pool.instance_variable_get(:@switch_points)
21
24
  if switch_points
@@ -36,7 +39,11 @@ module SwitchPoint
36
39
  proxy = ProxyRepository.find(switch_point[:name])
37
40
  case switch_point[:mode]
38
41
  when :readonly
39
- proxy_to_writable(proxy, method_name, *args, &block)
42
+ if SwitchPoint.config.auto_writable?
43
+ proxy_to_writable(proxy, method_name, *args, &block)
44
+ else
45
+ raise ReadonlyError.new("#{switch_point[:name]} is readonly, but destructive method #{method_name} is called")
46
+ end
40
47
  when :writable
41
48
  purge_readonly_query_cache(proxy)
42
49
  conn.send(parent_method, *args, &block)
@@ -1,3 +1,3 @@
1
1
  module SwitchPoint
2
- VERSION = "0.3.1"
2
+ VERSION = "0.4.0"
3
3
  end
@@ -17,8 +17,16 @@ SwitchPoint.configure do |config|
17
17
  readonly: :main_readonly
18
18
  end
19
19
 
20
+ require 'active_record'
21
+
20
22
  class Book < ActiveRecord::Base
21
23
  use_switch_point :main
24
+ after_save :do_after_save
25
+
26
+ private
27
+
28
+ def do_after_save
29
+ end
22
30
  end
23
31
 
24
32
  class Publisher < ActiveRecord::Base
@@ -1,4 +1,15 @@
1
- require 'active_record'
1
+ require 'coveralls'
2
+ require 'simplecov'
3
+
4
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
5
+ SimpleCov::Formatter::HTMLFormatter,
6
+ Coveralls::SimpleCov::Formatter,
7
+ ]
8
+ SimpleCov.start do
9
+ add_filter Bundler.bundle_path.to_s
10
+ add_filter File.dirname(__FILE__)
11
+ end
12
+
2
13
  require 'switch_point'
3
14
  require 'models'
4
15
 
@@ -39,7 +50,9 @@ RSpec.configure do |config|
39
50
  end
40
51
 
41
52
  config.after(:each) do
42
- Book.delete_all # This queries to writable database
53
+ Book.with_writable do
54
+ Book.delete_all
55
+ end
43
56
  FileUtils.cp('main_writable.sqlite3', 'main_readonly.sqlite3')
44
57
  end
45
58
  end
@@ -31,16 +31,48 @@ RSpec.describe SwitchPoint::Model do
31
31
  expect(Book.switch_point_proxy).to be_readonly
32
32
  end
33
33
 
34
- it 'sends destructive queries to writable' do
35
- Book.create
36
- Book.with_readonly { expect(Book.count).to eq(0) }
37
- Book.with_writable { expect(Book.count).to eq(1) }
34
+ context 'when auto_writable is disabled' do
35
+ it 'raises error when destructive query is requested in readonly mode' do
36
+ expect { Book.create }.to raise_error(SwitchPoint::Connection::ReadonlyError)
37
+ expect { Book.with_readonly { Book.create } }.to raise_error(SwitchPoint::Connection::ReadonlyError)
38
+ expect { Book.with_writable { Book.create } }.to_not raise_error
39
+ end
40
+ end
41
+
42
+ context 'when auto_writable is enabled' do
43
+ around do |example|
44
+ SwitchPoint.configure do |config|
45
+ config.auto_writable = true
46
+ end
47
+ example.run
48
+ SwitchPoint.configure do |config|
49
+ config.auto_writable = false
50
+ end
51
+ end
52
+
53
+ it 'sends destructive queries to writable' do
54
+ expect { Book.create }.to_not raise_error
55
+ expect { Book.with_readonly { Book.create } }.to_not raise_error
56
+ Book.with_readonly { expect(Book.count).to eq(0) }
57
+ Book.with_writable { expect(Book.count).to eq(2) }
58
+ end
59
+
60
+ it 'executes after_save callback in readonly mode!' do
61
+ book = Book.new
62
+ expect(book).to receive(:do_after_save) {
63
+ expect(Book.switch_point_proxy).to be_readonly
64
+ expect(Book.connection.open_transactions).to eq(1)
65
+ }
66
+ book.save!
67
+ end
38
68
  end
39
69
 
40
70
  it 'works with newly checked-out connection' do
41
71
  Thread.start do
42
72
  expect(Book.connection.pool.connections.size).to be > 1 # Assertion
43
- Book.create
73
+ Book.with_writable do
74
+ Book.create
75
+ end
44
76
  Book.with_readonly { expect(Book.count).to eq(0) }
45
77
  Book.with_writable { expect(Book.count).to eq(1) }
46
78
  end.join
@@ -32,4 +32,17 @@ RSpec.describe SwitchPoint do
32
32
  end
33
33
  end
34
34
  end
35
+
36
+ describe '.with_writable' do
37
+ it 'changes connection' do
38
+ SwitchPoint.with_writable(:main, :nanika1) do
39
+ expect(Book).to connect_to('main_writable.sqlite3')
40
+ expect(Publisher).to connect_to('main_writable.sqlite3')
41
+ expect(Nanika1).to connect_to('default.sqlite3')
42
+ end
43
+ expect(Book).to connect_to('main_readonly.sqlite3')
44
+ expect(Publisher).to connect_to('main_readonly.sqlite3')
45
+ expect(Nanika1).to connect_to('main_readonly.sqlite3')
46
+ end
47
+ end
35
48
  end
@@ -20,6 +20,7 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.add_development_dependency "appraisal"
22
22
  spec.add_development_dependency "bundler"
23
+ spec.add_development_dependency "coveralls"
23
24
  spec.add_development_dependency "rake"
24
25
  spec.add_development_dependency "rspec", "~> 3.0.0.rc1"
25
26
  spec.add_development_dependency "sqlite3"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: switch_point
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kohei Suzuki
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-06-04 00:00:00.000000000 Z
11
+ date: 2014-06-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: appraisal
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: coveralls
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: rake
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -110,6 +124,7 @@ files:
110
124
  - LICENSE.txt
111
125
  - README.md
112
126
  - Rakefile
127
+ - assets/switch_point.svg
113
128
  - gemfiles/rails_3.2.gemfile
114
129
  - gemfiles/rails_4.0.gemfile
115
130
  - gemfiles/rails_4.1.gemfile