returning 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +0 -1
- data/CHANGELOG.md +3 -0
- data/lib/returning.rb +20 -7
- data/lib/returning/active_record/returning.rb +26 -19
- data/lib/returning/arel/delete_update_manager.rb +10 -0
- data/lib/returning/arel/nodes/delete_update_statement.rb +14 -0
- data/lib/returning/arel/nodes/returning.rb +18 -0
- data/lib/returning/arel/nodes/select_core.rb +14 -0
- data/lib/returning/arel/tree_manager.rb +10 -0
- data/lib/returning/arel/visitors/postgresql.rb +32 -0
- data/lib/returning/rails30/active_record/persistence.rb +29 -0
- data/lib/returning/rails30/arel/crud.rb +42 -0
- data/lib/returning/rails30/returning.rb +6 -0
- data/lib/returning/rails31/active_record/persistence.rb +51 -0
- data/lib/returning/rails31/arel/crud.rb +32 -0
- data/lib/returning/rails31/returning.rb +6 -0
- data/lib/returning/version.rb +1 -1
- data/spec/returning_spec.rb +12 -1
- data/spec/spec_helper.rb +1 -1
- data/spec/support/ar.rb +12 -0
- metadata +16 -4
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
0.0.4 - 2011-08-24
|
2
|
+
* Save returning in an instance variable of the model, instead of connection. Previous approach failed when you tried to load an association inside a callback.
|
3
|
+
|
1
4
|
0.0.3 - 2011-08-22
|
2
5
|
-----
|
3
6
|
* Pass parameters down on save. This makes update_attribute work.
|
data/lib/returning.rb
CHANGED
@@ -2,14 +2,27 @@ require 'active_record'
|
|
2
2
|
require 'active_record/connection_adapters/postgresql_adapter'
|
3
3
|
|
4
4
|
require "returning/version"
|
5
|
-
|
6
|
-
require 'returning/
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
#
|
5
|
+
if ActiveRecord::VERSION::STRING =~ /^3\.0/
|
6
|
+
require 'returning/rails30/returning'
|
7
|
+
elsif ActiveRecord::VERSION::STRING =~ /^3\.1/
|
8
|
+
require 'returning/rails31/returning'
|
9
|
+
else
|
10
|
+
raise "ActiveRecord version #{ActiveRecord::VERSION::STRING} is not supported!"
|
11
11
|
end
|
12
12
|
|
13
|
+
require 'returning/active_record/returning'
|
14
|
+
require 'returning/arel/tree_manager'
|
15
|
+
require 'returning/arel/nodes/select_core'
|
16
|
+
require 'returning/arel/nodes/returning'
|
17
|
+
require 'returning/arel/delete_update_manager'
|
18
|
+
require 'returning/arel/nodes/delete_update_statement'
|
19
|
+
require 'returning/arel/visitors/postgresql'
|
13
20
|
|
14
21
|
ActiveRecord::Base.send(:include, Returning::ActiveRecord::Returning)
|
15
|
-
|
22
|
+
Arel::SelectManager.send(:include, Returning::Arel::TreeManager)
|
23
|
+
Arel::UpdateManager.send(:include, Returning::Arel::DeleteUpdateManager)
|
24
|
+
Arel::DeleteManager.send(:include, Returning::Arel::DeleteUpdateManager)
|
25
|
+
Arel::Nodes::SelectCore.send(:include, Returning::Arel::Nodes::SelectCore)
|
26
|
+
Arel::Nodes::UpdateStatement.send(:include, Returning::Arel::Nodes::DeleteUpdateStatement)
|
27
|
+
Arel::Nodes::DeleteStatement.send(:include, Returning::Arel::Nodes::DeleteUpdateStatement)
|
28
|
+
Arel::Visitors::PostgreSQL.send(:include, Returning::Arel::Visitors::PostgreSQL)
|
@@ -3,22 +3,13 @@ require 'active_support/concern'
|
|
3
3
|
module Returning
|
4
4
|
module ActiveRecord
|
5
5
|
module Returning
|
6
|
-
extend ActiveSupport::Concern
|
7
|
-
|
8
|
-
included do
|
9
|
-
if method(:find_by_sql).arity == 1
|
10
|
-
class_eval do
|
11
|
-
def self.find_by_sql(sql, binds = [])
|
12
|
-
connection.select_all(sanitize_sql(sql), "#{name} Load").collect! { |record| instantiate(record) }
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
6
|
def save(options = {})
|
19
7
|
if r = options[:returning]
|
20
|
-
|
8
|
+
begin
|
9
|
+
old_returning, @_returning = @_returning, r
|
21
10
|
super
|
11
|
+
ensure
|
12
|
+
@_returning = old_returning
|
22
13
|
end
|
23
14
|
else
|
24
15
|
super
|
@@ -26,10 +17,18 @@ module Returning
|
|
26
17
|
end
|
27
18
|
|
28
19
|
def create_or_update
|
29
|
-
if
|
30
|
-
|
31
|
-
|
32
|
-
|
20
|
+
if @_returning
|
21
|
+
raise ReadOnlyRecord if readonly?
|
22
|
+
if new_record?
|
23
|
+
create
|
24
|
+
self
|
25
|
+
elsif r = update
|
26
|
+
r = self.class.send(:instantiate, r[0])
|
27
|
+
r.readonly!
|
28
|
+
r
|
29
|
+
else
|
30
|
+
false
|
31
|
+
end
|
33
32
|
else
|
34
33
|
super
|
35
34
|
end
|
@@ -37,8 +36,16 @@ module Returning
|
|
37
36
|
|
38
37
|
def destroy(options = {})
|
39
38
|
if r = options[:returning]
|
40
|
-
|
41
|
-
|
39
|
+
begin
|
40
|
+
old_returning, @_returning = @_returning, r
|
41
|
+
if r = super()
|
42
|
+
r = self.class.send(:instantiate, r[0])
|
43
|
+
r.readonly!
|
44
|
+
end
|
45
|
+
|
46
|
+
r
|
47
|
+
ensure
|
48
|
+
@_returning = old_returning
|
42
49
|
end
|
43
50
|
else
|
44
51
|
super()
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Returning
|
2
|
+
module Arel
|
3
|
+
module Nodes
|
4
|
+
class Returning < ::Arel::Nodes::Node
|
5
|
+
attr_accessor :returnings
|
6
|
+
|
7
|
+
def initialize(returnings)
|
8
|
+
@returnings = returnings
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize_copy other
|
12
|
+
super
|
13
|
+
@returnings = @returnings.clone if @returnings
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Returning
|
2
|
+
module Arel
|
3
|
+
module Visitors
|
4
|
+
module PostgreSQL
|
5
|
+
private
|
6
|
+
def visit_Returning_Arel_Nodes_Returning o
|
7
|
+
if o.returnings.empty?
|
8
|
+
""
|
9
|
+
else
|
10
|
+
" RETURNING #{o.returnings.join(', ')}"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def visit_Arel_Nodes_UpdateStatement o
|
15
|
+
if o.returnings
|
16
|
+
"#{super}#{visit o.returnings}"
|
17
|
+
else
|
18
|
+
super
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def visit_Arel_Nodes_DeleteStatement o
|
23
|
+
if o.returnings
|
24
|
+
"#{super}#{visit o.returnings}"
|
25
|
+
else
|
26
|
+
super
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Returning
|
2
|
+
module Rails30
|
3
|
+
module ActiveRecord
|
4
|
+
module Persistence
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
included do
|
7
|
+
def update(attribute_names = @attributes.keys, options = {})
|
8
|
+
attributes_with_values = arel_attributes_values(false, false, attribute_names)
|
9
|
+
return @_returning ? [@attributes] : 0 if attributes_with_values.empty?
|
10
|
+
self.class.unscoped.where(self.class.arel_table[self.class.primary_key].eq(id)).arel.returning(@_returning).update(attributes_with_values)
|
11
|
+
end
|
12
|
+
|
13
|
+
def destroy
|
14
|
+
destroy_associations
|
15
|
+
|
16
|
+
if persisted?
|
17
|
+
result = self.class.unscoped.where(self.class.arel_table[self.class.primary_key].eq(id)).arel.returning(@_returning).delete
|
18
|
+
end
|
19
|
+
|
20
|
+
@destroyed = true
|
21
|
+
freeze
|
22
|
+
|
23
|
+
result ? result : self
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Returning
|
2
|
+
module Rails30
|
3
|
+
module Arel
|
4
|
+
module Crud
|
5
|
+
def update values
|
6
|
+
um = ::Arel::UpdateManager.new @engine
|
7
|
+
|
8
|
+
if ::Arel::Nodes::SqlLiteral === values
|
9
|
+
relation = @ctx.froms
|
10
|
+
else
|
11
|
+
relation = values.first.first.relation
|
12
|
+
end
|
13
|
+
um.table relation
|
14
|
+
um.set values
|
15
|
+
um.take @ast.limit.expr if @ast.limit
|
16
|
+
um.order(*@ast.orders)
|
17
|
+
um.wheres = @ctx.wheres
|
18
|
+
um.returning @ctx.returnings if @ctx.returnings
|
19
|
+
|
20
|
+
if @ctx.returnings
|
21
|
+
@engine.connection.select_all um.to_sql, 'AREL'
|
22
|
+
else
|
23
|
+
@engine.connection.update um.to_sql, 'AREL'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def delete
|
28
|
+
dm = ::Arel::DeleteManager.new @engine
|
29
|
+
dm.wheres = @ctx.wheres
|
30
|
+
dm.from @ctx.froms
|
31
|
+
dm.returning @ctx.returnings if @ctx.returnings
|
32
|
+
|
33
|
+
if @ctx.returnings
|
34
|
+
@engine.connection.select_all dm.to_sql, 'AREL'
|
35
|
+
else
|
36
|
+
@engine.connection.delete dm.to_sql, 'AREL'
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Returning
|
2
|
+
module Rails31
|
3
|
+
module ActiveRecord
|
4
|
+
module Persistence
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
included do
|
7
|
+
def update(attribute_names = @attributes.keys)
|
8
|
+
attributes_with_values = arel_attributes_values(false, false, attribute_names)
|
9
|
+
return @_returning ? [@attributes] : 0 if attributes_with_values.empty?
|
10
|
+
klass = self.class
|
11
|
+
stmt = klass.unscoped.where(klass.arel_table[klass.primary_key].eq(id)).arel.returning(@_returning).compile_update(attributes_with_values)
|
12
|
+
if @_returning
|
13
|
+
klass.connection.select_all stmt
|
14
|
+
else
|
15
|
+
klass.connection.update stmt
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def destroy
|
20
|
+
destroy_associations
|
21
|
+
|
22
|
+
if persisted?
|
23
|
+
::ActiveRecord::IdentityMap.remove(self) if ::ActiveRecord::IdentityMap.enabled?
|
24
|
+
pk = self.class.primary_key
|
25
|
+
column = self.class.columns_hash[pk]
|
26
|
+
substitute = connection.substitute_at(column, 0)
|
27
|
+
|
28
|
+
relation = self.class.unscoped.where(
|
29
|
+
self.class.arel_table[pk].eq(substitute))
|
30
|
+
|
31
|
+
relation.bind_values = [[column, id]]
|
32
|
+
stmt = relation.arel.returning(@_returning).compile_delete
|
33
|
+
|
34
|
+
klass = self.class
|
35
|
+
result = if @_returning
|
36
|
+
klass.connection.select_all stmt, 'SQL', relation.bind_values
|
37
|
+
else
|
38
|
+
klass.connection.delete stmt, 'SQL', relation.bind_values
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
@destroyed = true
|
43
|
+
freeze
|
44
|
+
|
45
|
+
result ? result : self
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Returning
|
2
|
+
module Rails31
|
3
|
+
module Arel
|
4
|
+
module Crud
|
5
|
+
def compile_update values
|
6
|
+
um = ::Arel::UpdateManager.new @engine
|
7
|
+
|
8
|
+
if ::Arel::Nodes::SqlLiteral === values
|
9
|
+
relation = @ctx.from
|
10
|
+
else
|
11
|
+
relation = values.first.first.relation
|
12
|
+
end
|
13
|
+
um.table relation
|
14
|
+
um.set values
|
15
|
+
um.take @ast.limit.expr if @ast.limit
|
16
|
+
um.order(*@ast.orders)
|
17
|
+
um.wheres = @ctx.wheres
|
18
|
+
um.returning @ctx.returnings if @ctx.returnings
|
19
|
+
um
|
20
|
+
end
|
21
|
+
|
22
|
+
def compile_delete
|
23
|
+
dm = ::Arel::DeleteManager.new @engine
|
24
|
+
dm.wheres = @ctx.wheres
|
25
|
+
dm.from @ctx.froms
|
26
|
+
dm.returning @ctx.returnings if @ctx.returnings
|
27
|
+
dm
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/returning/version.rb
CHANGED
data/spec/returning_spec.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
+
require 'logger'
|
2
3
|
|
3
4
|
describe Returning do
|
4
5
|
before do
|
@@ -37,13 +38,23 @@ describe Returning do
|
|
37
38
|
post.save(:returning => "name", :validate => false).should be_true
|
38
39
|
end
|
39
40
|
end
|
41
|
+
|
42
|
+
context 'works fine with associations' do
|
43
|
+
it "does not pollute destroy with RETURNING of an association" do
|
44
|
+
post = Post.first
|
45
|
+
post.update_attributes :tags_attributes => [{:tag => 'a'}, {:tag => 'b'}]
|
46
|
+
post.tags_attributes = Post.find(post.id).tags.map { |t| {:id => t.id, :_destroy => '1'} }
|
47
|
+
post.name = 'New name'
|
48
|
+
post.save(:returning => 'name')
|
49
|
+
end
|
50
|
+
end
|
40
51
|
end
|
41
52
|
|
42
53
|
describe '#destroy' do
|
43
54
|
it 'returns the column passed to returning' do
|
44
55
|
post = Post.first
|
45
56
|
post.name = 'hello world'
|
46
|
-
post.destroy(:returning => 'name').name.should == 'hello
|
57
|
+
post.destroy(:returning => 'name').name.should == 'hello'
|
47
58
|
end
|
48
59
|
|
49
60
|
context 'with query cache' do
|
data/spec/spec_helper.rb
CHANGED
data/spec/support/ar.rb
CHANGED
@@ -23,16 +23,28 @@ class Migration < ActiveRecord::Migration
|
|
23
23
|
create_table :posts, :force => true do |t|
|
24
24
|
t.string :name, :author
|
25
25
|
end
|
26
|
+
create_table :tags, :force => true do |t|
|
27
|
+
t.string :tag
|
28
|
+
t.references :post
|
29
|
+
end
|
26
30
|
end
|
27
31
|
|
28
32
|
def self.down
|
29
33
|
drop_table :posts
|
34
|
+
drop_table :tags
|
30
35
|
end
|
31
36
|
end
|
32
37
|
|
33
38
|
Migration.up
|
34
39
|
|
35
40
|
class Post < ActiveRecord::Base
|
41
|
+
has_many :tags
|
42
|
+
|
43
|
+
accepts_nested_attributes_for :tags, :allow_destroy => true
|
44
|
+
end
|
45
|
+
|
46
|
+
class Tag < ActiveRecord::Base
|
47
|
+
belongs_to :post
|
36
48
|
end
|
37
49
|
|
38
50
|
class PostQueryCache < ActiveRecord::Base
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: returning
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 23
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 4
|
10
|
+
version: 0.0.4
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Eugene Pimenov
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-08-
|
18
|
+
date: 2011-08-24 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
requirement: &id001 !ruby/object:Gem::Requirement
|
@@ -67,6 +67,18 @@ files:
|
|
67
67
|
- lib/returning.rb
|
68
68
|
- lib/returning/active_record/adapter.rb
|
69
69
|
- lib/returning/active_record/returning.rb
|
70
|
+
- lib/returning/arel/delete_update_manager.rb
|
71
|
+
- lib/returning/arel/nodes/delete_update_statement.rb
|
72
|
+
- lib/returning/arel/nodes/returning.rb
|
73
|
+
- lib/returning/arel/nodes/select_core.rb
|
74
|
+
- lib/returning/arel/tree_manager.rb
|
75
|
+
- lib/returning/arel/visitors/postgresql.rb
|
76
|
+
- lib/returning/rails30/active_record/persistence.rb
|
77
|
+
- lib/returning/rails30/arel/crud.rb
|
78
|
+
- lib/returning/rails30/returning.rb
|
79
|
+
- lib/returning/rails31/active_record/persistence.rb
|
80
|
+
- lib/returning/rails31/arel/crud.rb
|
81
|
+
- lib/returning/rails31/returning.rb
|
70
82
|
- lib/returning/version.rb
|
71
83
|
- returning.gemspec
|
72
84
|
- spec/returning_spec.rb
|