returning 0.0.3 → 0.0.4

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.
@@ -6,7 +6,6 @@ rvm:
6
6
  - rbx
7
7
  - rbx-2.0
8
8
  - ree
9
- - jruby
10
9
  - ruby-head
11
10
  gemfile:
12
11
  - Gemfile
@@ -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.
@@ -2,14 +2,27 @@ require 'active_record'
2
2
  require 'active_record/connection_adapters/postgresql_adapter'
3
3
 
4
4
  require "returning/version"
5
- require 'returning/active_record/returning'
6
- require 'returning/active_record/adapter'
7
-
8
-
9
- module Returning
10
- # Your code goes here...
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
- ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.send(:include, Returning::ActiveRecord::Adapter)
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
- connection.returning(r, self.class) do
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 connection.returning? && !new_record?
30
- fields = update
31
- # if no attributes were changed return self
32
- fields == 0 ? self : fields[0]
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
- connection.returning(r, self.class) do
41
- super()
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,10 @@
1
+ module Returning
2
+ module Arel
3
+ module DeleteUpdateManager
4
+ def returning returnings
5
+ @ast.returnings = Nodes::Returning.new(returnings) if returnings
6
+ self
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,14 @@
1
+ module Returning
2
+ module Arel
3
+ module Nodes
4
+ module DeleteUpdateStatement
5
+ attr_accessor :returnings
6
+
7
+ def initialize_copy other
8
+ super
9
+ @returnings = @returnings.clone if @returnings
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -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,14 @@
1
+ module Returning
2
+ module Arel
3
+ module Nodes
4
+ module SelectCore
5
+ attr_accessor :returnings
6
+
7
+ def initialize_copy other
8
+ super
9
+ @returnings = @returnings.clone if @returnings
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,10 @@
1
+ module Returning
2
+ module Arel
3
+ module TreeManager
4
+ def returning *returnings
5
+ @ctx.returnings = returnings if !returnings.compact.empty?
6
+ self
7
+ end
8
+ end
9
+ end
10
+ 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,6 @@
1
+ require 'returning/rails30/active_record/persistence'
2
+ require 'returning/rails30/arel/crud'
3
+
4
+
5
+ Arel::SelectManager.send(:include, Returning::Rails30::Arel::Crud)
6
+ ActiveRecord::Persistence.send(:include, Returning::Rails30::ActiveRecord::Persistence)
@@ -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
@@ -0,0 +1,6 @@
1
+ require 'returning/rails31/active_record/persistence'
2
+ require 'returning/rails31/arel/crud'
3
+
4
+
5
+ Arel::SelectManager.send(:include, Returning::Rails31::Arel::Crud)
6
+ ActiveRecord::Persistence.send(:include, Returning::Rails31::ActiveRecord::Persistence)
@@ -1,3 +1,3 @@
1
1
  module Returning
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.4"
3
3
  end
@@ -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 world'
57
+ post.destroy(:returning => 'name').name.should == 'hello'
47
58
  end
48
59
 
49
60
  context 'with query cache' do
@@ -3,7 +3,7 @@ require 'bundler/setup'
3
3
 
4
4
  Bundler.require
5
5
 
6
- Dir['spec/support/**/*.rb'].each { |f| require f }
6
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
7
7
 
8
8
  RSpec.configure do
9
9
  end
@@ -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: 25
4
+ hash: 23
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 3
10
- version: 0.0.3
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-22 00:00:00 Z
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