dm-adjust 0.9.2

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Sindre Aarsaether
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,12 @@
1
+ dm-adjust
2
+ =============
3
+
4
+ DataMapper plugin providing methods to increment and decrement properties
5
+
6
+ It provides the following function (for collections and resources):
7
+
8
+ == adjust
9
+
10
+ Person.adjust(:salary => 1000) # increases the salary of all people with 1000.
11
+ Person.all(:age.gte => 40).adjust(:salary => 2000) # increase salary of them oldies.
12
+ Children.adjust(:allowance => -100) # less money for candy and concerts
data/Rakefile ADDED
@@ -0,0 +1,60 @@
1
+ require 'rubygems'
2
+ require 'spec'
3
+ require 'rake/clean'
4
+ require 'rake/gempackagetask'
5
+ require 'spec/rake/spectask'
6
+ require 'pathname'
7
+
8
+ CLEAN.include '{log,pkg}/'
9
+
10
+ spec = Gem::Specification.new do |s|
11
+ s.name = 'dm-adjust'
12
+ s.version = '0.9.2'
13
+ s.platform = Gem::Platform::RUBY
14
+ s.has_rdoc = true
15
+ s.extra_rdoc_files = %w[ README LICENSE TODO ]
16
+ s.summary = 'DataMapper plugin providing methods to increment and decrement properties'
17
+ s.description = s.summary
18
+ s.author = 'Sindre Aarsaether'
19
+ s.email = 'sindre [a] identu [d] no'
20
+ s.homepage = 'http://github.com/sam/dm-more/tree/master/dm-adjust'
21
+ s.require_path = 'lib'
22
+ s.files = FileList[ '{lib,spec}/**/*.rb', 'spec/spec.opts', 'Rakefile', *s.extra_rdoc_files ]
23
+ s.add_dependency('dm-core', "=#{s.version}")
24
+ end
25
+
26
+ task :default => [ :spec ]
27
+
28
+ WIN32 = (RUBY_PLATFORM =~ /win32|mingw|cygwin/) rescue nil
29
+ SUDO = WIN32 ? '' : ('sudo' unless ENV['SUDOLESS'])
30
+
31
+ Rake::GemPackageTask.new(spec) do |pkg|
32
+ pkg.gem_spec = spec
33
+ end
34
+
35
+ desc "Install #{spec.name} #{spec.version} (default ruby)"
36
+ task :install => [ :package ] do
37
+ sh "#{SUDO} gem install --local pkg/#{spec.name}-#{spec.version} --no-update-sources", :verbose => false
38
+ end
39
+
40
+ namespace :jruby do
41
+ desc "Install #{spec.name} #{spec.version} with JRuby"
42
+ task :install => [ :package ] do
43
+ sh %{#{SUDO} jruby -S gem install --local pkg/#{spec.name}-#{spec.version} --no-update-sources}, :verbose => false
44
+ end
45
+ end
46
+
47
+ desc 'Run specifications'
48
+ Spec::Rake::SpecTask.new(:spec) do |t|
49
+ t.spec_opts << '--options' << 'spec/spec.opts' if File.exists?('spec/spec.opts')
50
+ t.spec_files = Pathname.glob(Pathname.new(__FILE__).dirname + 'spec/**/*_spec.rb')
51
+
52
+ begin
53
+ t.rcov = ENV.has_key?('NO_RCOV') ? ENV['NO_RCOV'] != 'true' : true
54
+ t.rcov_opts << '--exclude' << 'spec'
55
+ t.rcov_opts << '--text-summary'
56
+ t.rcov_opts << '--sort' << 'coverage' << '--sort-reverse'
57
+ rescue Exception
58
+ # rcov not installed
59
+ end
60
+ end
data/TODO ADDED
@@ -0,0 +1,6 @@
1
+ TODO
2
+ ====
3
+
4
+ ---
5
+ TODO tickets may also be found in the DataMapper Issue Tracker:
6
+ http://wm.lighthouseapp.com/projects/4819-datamapper/overview
data/lib/dm-adjust.rb ADDED
@@ -0,0 +1,11 @@
1
+ require 'rubygems'
2
+
3
+ gem 'dm-core', '=0.9.3'
4
+ require 'dm-core'
5
+
6
+ dir = Pathname(__FILE__).dirname.expand_path / 'dm-adjust'
7
+
8
+ require dir / 'collection'
9
+ require dir / 'model'
10
+ require dir / 'repository'
11
+ require dir / 'adapters' / 'data_objects_adapter'
@@ -0,0 +1,34 @@
1
+ module DataMapper
2
+ module Adapters
3
+ class DataObjectsAdapter
4
+ def adjust(attributes, query)
5
+ statement = adjust_statement(attributes.keys, query)
6
+ bind_values = attributes.values + query.bind_values
7
+ execute(statement, *bind_values)
8
+ end
9
+
10
+ module SQL
11
+ private
12
+
13
+ def adjust_statement(properties, query)
14
+ repository = query.repository
15
+
16
+ statement = "UPDATE #{quote_table_name(query.model.storage_name(repository.name))}"
17
+ statement << " SET #{set_adjustment_statement(repository, properties)}"
18
+ statement << " WHERE #{conditions_statement(query)}" if query.conditions.any?
19
+ statement
20
+ rescue => e
21
+ DataMapper.logger.error("QUERY INVALID: #{query.inspect} (#{e})")
22
+ raise e
23
+ end
24
+
25
+ def set_adjustment_statement(repository, properties)
26
+ properties.map { |p| [quote_column_name(p.field(repository.name))] * 2 * " = " + " + (?)" } * ", "
27
+ end
28
+
29
+ end # module SQL
30
+
31
+ include SQL
32
+ end # class DataObjectsAdapter
33
+ end # module Adapters
34
+ end # module DataMapper
@@ -0,0 +1,60 @@
1
+ module DataMapper
2
+ class Collection
3
+
4
+ def adjust(attributes = {}, reload = false)
5
+ raise NotImplementedError, 'adjust *with* validations has not be written yet, try adjust!'
6
+ end
7
+
8
+ ##
9
+ # increment or decrement attributes on a collection
10
+ #
11
+ # @example [Usage]
12
+ # * People.all.adjust(:salary => +1000)
13
+ # * Children.all(:age.gte => 18).adjust(:allowance => -100)
14
+ #
15
+ # @param attributes <Hash> A hash of attributes to adjust, and their adjustment
16
+ # @param reload <FalseClass,TrueClass> If true, affected objects will be reloaded
17
+ #
18
+ # @public
19
+ def adjust!(attributes = {}, reload = false)
20
+ return true if attributes.empty?
21
+
22
+ adjust_attributes = {}
23
+
24
+ model.properties(repository.name).slice(*attributes.keys).each do |property|
25
+ adjust_attributes[property] = attributes[property.name] if property
26
+ end
27
+
28
+ each { |r| attributes.each_pair{|a,v| r.attribute_set(a,r.send(a) + v) }; r.save } if loaded?
29
+
30
+ # if none of the attributes that are adjusted is part of the collection-query
31
+ # there is no need to load the collection (it will not change after adjustment)
32
+ # if the query contains a raw sql-string, we cannot (truly) know, and must load.
33
+ altered = query.conditions.detect{|c| adjust_attributes.include?(c[1]) || c[0] == :raw }
34
+
35
+ if identity_map.any? && reload
36
+ reload_query = @key_properties.zip(identity_map.keys.transpose).to_hash
37
+ reload_query = all(reload_query.merge(:fields => @key_properties)).send(:keys) if altered
38
+ end
39
+
40
+ repository.adjust(adjust_attributes,scoped_query)
41
+
42
+ # Reload affected objects in identity-map. if collection was affected, dont use the scope.
43
+ (altered ? model : self).all(reload_query).reload(:fields => attributes.keys) if reload_query && reload_query.any?
44
+
45
+ # if preload was set to false, and collection was affected by updates,
46
+ # something is now officially borked. We'll try the best we can (still many cases this is borked for)
47
+ query.conditions.each do |c|
48
+ if adjustment = adjust_attributes[c[1]]
49
+ case c[2]
50
+ when Numeric then c[2] += adjustment
51
+ when Range then c[2] = (c[2].first+adjustment)..(c[2].last+adjustment)
52
+ end if adjustment = adjust_attributes[c[1]]
53
+ end
54
+ end if altered
55
+
56
+ return true
57
+
58
+ end # adjust
59
+ end # Collection
60
+ end # DataMapper
@@ -0,0 +1,17 @@
1
+ module DataMapper
2
+ module Model
3
+
4
+ ##
5
+ # increment or decrement attributes on all objects in a resource
6
+ #
7
+ # @example [Usage]
8
+ # * People.adjust(:salary => +1000)
9
+ # * Children.adjust(:allowance => -100)
10
+ #
11
+ # @param attributes <Hash> A hash of attributes to adjust, and their adjustment
12
+ # @public
13
+ def adjust!(attributes,reload=false)
14
+ all.adjust!(attributes,reload)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,7 @@
1
+ module DataMapper
2
+ class Repository
3
+ def adjust(attributes, query)
4
+ adapter.adjust(attributes, query)
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,61 @@
1
+ require 'pathname'
2
+ require Pathname(__FILE__).dirname.expand_path.parent + 'spec_helper'
3
+
4
+ if HAS_SQLITE3 || HAS_MYSQL || HAS_POSTGRES
5
+
6
+ class Person
7
+ include DataMapper::Resource
8
+ property :id, Integer, :serial => true
9
+ property :name, String
10
+ property :salary, Integer, :default => 20000
11
+ property :age, Integer
12
+ end
13
+
14
+ describe 'Adjust' do
15
+
16
+ before :all do
17
+ Person.auto_migrate!(:default)
18
+ Person.create(:name => 'George', :age => 15)
19
+ Person.create(:name => 'Puff', :age => 18)
20
+ Person.create(:name => 'Danny', :age => 26)
21
+ Person.create(:name => 'Selma', :age => 28)
22
+ Person.create(:name => 'John', :age => 49)
23
+ Person.create(:name => 'Amadeus',:age => 60)
24
+ end
25
+
26
+ describe 'Resource#adjust!' do
27
+ it 'should adjust values' do
28
+ repository(:default) do
29
+ p = Person.get(1)
30
+ p.salary.should == 20000
31
+ Person.adjust!({:salary => 1000},true)
32
+ Person.all.each{|p| p.salary.should == 21000}
33
+ end
34
+ end
35
+ end
36
+
37
+ describe 'Collection#adjust!' do
38
+ it 'should adjust values' do
39
+ repository(:default) do |repos|
40
+ @oldies = Person.all(:age.gte => 40)
41
+ @oldies.adjust!({:salary => 5000},true)
42
+ @oldies.each{|p| p.salary.should == 25000}
43
+
44
+ Person.get(1).salary.should == 20000
45
+
46
+ @children = Person.all(:age.lte => 18)
47
+ @children.adjust!({:salary => -10000},true)
48
+ @children.each{|p| p.salary.should == 10000}
49
+ end
50
+ end
51
+
52
+ it 'should load the query if conditions were adjusted' do
53
+ repository(:default) do |repos|
54
+ @specific = Person.all(:salary => 25000)
55
+ @specific.adjust!({:salary => 5000},true)
56
+ @specific.length.should == 2
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1,2 @@
1
+ --format specdoc
2
+ --colour
@@ -0,0 +1,27 @@
1
+ require 'rubygems'
2
+ require 'pathname'
3
+ require Pathname(__FILE__).dirname.expand_path.parent + 'lib/dm-adjust'
4
+
5
+ def load_driver(name, default_uri)
6
+ return false if ENV['ADAPTER'] != name.to_s
7
+
8
+ lib = "do_#{name}"
9
+
10
+ begin
11
+ gem lib, '=0.9.3'
12
+ require lib
13
+ DataMapper.setup(name, ENV["#{name.to_s.upcase}_SPEC_URI"] || default_uri)
14
+ DataMapper::Repository.adapters[:default] = DataMapper::Repository.adapters[name]
15
+ # DataObjects::Sqlite3.logger = DataObjects::Logger.new(Pathname(__FILE__).dirname+'dm.log',0)
16
+ true
17
+ rescue Gem::LoadError => e
18
+ warn "Could not load #{lib}: #{e}"
19
+ false
20
+ end
21
+ end
22
+
23
+ ENV['ADAPTER'] ||= 'sqlite3'
24
+
25
+ HAS_SQLITE3 = load_driver(:sqlite3, 'sqlite3::memory:')
26
+ HAS_MYSQL = load_driver(:mysql, 'mysql://localhost/dm_core_test')
27
+ HAS_POSTGRES = load_driver(:postgres, 'postgres://postgres@localhost/dm_core_test')
metadata ADDED
@@ -0,0 +1,74 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dm-adjust
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.2
5
+ platform: ruby
6
+ authors:
7
+ - Sindre Aarsaether
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-06-30 00:00:00 -05:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: dm-core
17
+ version_requirement:
18
+ version_requirements: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - "="
21
+ - !ruby/object:Gem::Version
22
+ version: 0.9.2
23
+ version:
24
+ description: DataMapper plugin providing methods to increment and decrement properties
25
+ email: sindre [a] identu [d] no
26
+ executables: []
27
+
28
+ extensions: []
29
+
30
+ extra_rdoc_files:
31
+ - README
32
+ - LICENSE
33
+ - TODO
34
+ files:
35
+ - lib/dm-adjust/adapters/data_objects_adapter.rb
36
+ - lib/dm-adjust/collection.rb
37
+ - lib/dm-adjust/model.rb
38
+ - lib/dm-adjust/repository.rb
39
+ - lib/dm-adjust.rb
40
+ - spec/integration/adjust_spec.rb
41
+ - spec/spec_helper.rb
42
+ - spec/spec.opts
43
+ - Rakefile
44
+ - README
45
+ - LICENSE
46
+ - TODO
47
+ has_rdoc: true
48
+ homepage: http://github.com/sam/dm-more/tree/master/dm-adjust
49
+ post_install_message:
50
+ rdoc_options: []
51
+
52
+ require_paths:
53
+ - lib
54
+ required_ruby_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: "0"
59
+ version:
60
+ required_rubygems_version: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: "0"
65
+ version:
66
+ requirements: []
67
+
68
+ rubyforge_project:
69
+ rubygems_version: 1.0.1
70
+ signing_key:
71
+ specification_version: 2
72
+ summary: DataMapper plugin providing methods to increment and decrement properties
73
+ test_files: []
74
+