ixtlan-datamapper 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +9 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.md +94 -0
  5. data/Rakefile +29 -0
  6. data/ixtlan-datamapper.gemspec +32 -0
  7. data/lib/ixtlan-datamapper.rb +23 -0
  8. data/lib/ixtlan/datamapper/collection.rb +28 -0
  9. data/lib/ixtlan/datamapper/collection.rb~ +28 -0
  10. data/lib/ixtlan/datamapper/conditional_get.rb +46 -0
  11. data/lib/ixtlan/datamapper/conditional_get.rb~ +47 -0
  12. data/lib/ixtlan/datamapper/cuba_plugin.rb~ +74 -0
  13. data/lib/ixtlan/datamapper/immutable.rb +18 -0
  14. data/lib/ixtlan/datamapper/immutable.rb~ +83 -0
  15. data/lib/ixtlan/datamapper/modified.rb~ +83 -0
  16. data/lib/ixtlan/datamapper/modified_by.rb +39 -0
  17. data/lib/ixtlan/datamapper/modified_by.rb~ +39 -0
  18. data/lib/ixtlan/datamapper/optimistic.rb~ +53 -0
  19. data/lib/ixtlan/datamapper/optimistic_get.rb +71 -0
  20. data/lib/ixtlan/datamapper/optimistic_get.rb~ +72 -0
  21. data/lib/ixtlan/datamapper/stale_check.rb~ +49 -0
  22. data/lib/ixtlan/datamapper/stale_object_exception.rb +26 -0
  23. data/lib/ixtlan/datamapper/stale_object_exception.rb~ +26 -0
  24. data/lib/ixtlan/datamapper/use_utc.rb +4 -0
  25. data/lib/ixtlan/datamapper/use_utc.rb~ +5 -0
  26. data/lib/ixtlan/datamapper/validations_ext.rb +61 -0
  27. data/spec/collection_spec.rb +57 -0
  28. data/spec/collection_spec.rb~ +54 -0
  29. data/spec/conditional_get_spec.rb +69 -0
  30. data/spec/conditional_get_spec.rb~ +70 -0
  31. data/spec/datamapper_spec.rb~ +74 -0
  32. data/spec/immutable_spec.rb +33 -0
  33. data/spec/immutable_spec.rb~ +70 -0
  34. data/spec/modified_by_spec.rb +54 -0
  35. data/spec/modified_by_spec.rb~ +33 -0
  36. data/spec/optimistic_get_spec.rb +57 -0
  37. data/spec/spec_helper.rb +15 -0
  38. data/spec/spec_helper.rb~ +12 -0
  39. metadata +199 -0
@@ -0,0 +1,18 @@
1
+ module Ixtlan
2
+ module DataMapper
3
+ module Immutable
4
+ def self.included( model )
5
+ model.class_eval do
6
+ validates_with_method :validate_immutable
7
+ end
8
+ end
9
+ def validate_immutable
10
+ if dirty? && ! new?
11
+ [ false, 'object is immutable' ]
12
+ else
13
+ true
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,83 @@
1
+ require 'dm-aggregates'
2
+ module Ixtlan
3
+ module ConditionalGet
4
+
5
+ private
6
+
7
+ def _conditional_get( method, id, modified_since, attribute )
8
+ if self.count( attribute => modified_since,
9
+ :id => id ) == 0
10
+ self.send( method, id )
11
+ else
12
+ # return false when up-to-date
13
+ # that helps to distinguish nil from not-found
14
+ false
15
+ end
16
+ end
17
+
18
+ public
19
+
20
+ def conditional_get!( id, modified_since, attribute = :updated_at )
21
+ _conditional_get( :get!, id, modified_since, attribute )
22
+ end
23
+
24
+ def conditional_get( id, modified_since, attribute = :updated_at )
25
+ _conditional_get( :get, id, modified_since, attribute )
26
+ end
27
+ end
28
+ DataMapper::Associations::OneToMany::Collection.send( :include,
29
+ ConditionalGet )
30
+ DataMapper::Associations::ManyToMany::Collection.send( :include,
31
+ ConditionalGet )
32
+
33
+ module Immutable
34
+ def self.included( model )
35
+ model.class_eval do
36
+ validates_with_method :validate_immutable
37
+ end
38
+ end
39
+ def validate_immutable
40
+ if dirty? && ! new?
41
+ [ false, 'object is immutable' ]
42
+ else
43
+ true
44
+ end
45
+ end
46
+ end
47
+
48
+ module ModifiedBy
49
+
50
+ def current_user=( user )
51
+ @_current_user = user
52
+ end
53
+
54
+ def current_user
55
+ @_current_user
56
+ end
57
+
58
+ def _modified_by
59
+ self.modified_by = @_current_user if dirty? && @_current_user
60
+ end
61
+
62
+ def validate_modified_by
63
+ if @_current_user || ! dirty?
64
+ true
65
+ else
66
+ [ false, 'current_user was not set' ]
67
+ end
68
+ end
69
+
70
+ module Methods
71
+ def modified_by( *args )
72
+ belongs_to :modified_by, *args
73
+
74
+ before :valid?, :_modified_by
75
+
76
+ validates_with_method :validate_modified_by
77
+ end
78
+ end
79
+
80
+ DataMapper::Model.append_inclusions self
81
+ DataMapper::Model.append_extensions Methods
82
+ end
83
+ end
@@ -0,0 +1,83 @@
1
+ require 'dm-aggregates'
2
+ module Ixtlan
3
+ module ConditionalGet
4
+
5
+ private
6
+
7
+ def _conditional_get( method, id, modified_since, attribute )
8
+ if self.count( attribute => modified_since,
9
+ :id => id ) == 0
10
+ self.send( method, id )
11
+ else
12
+ # return false when up-to-date
13
+ # that helps to distinguish nil from not-found
14
+ false
15
+ end
16
+ end
17
+
18
+ public
19
+
20
+ def conditional_get!( id, modified_since, attribute = :updated_at )
21
+ _conditional_get( :get!, id, modified_since, attribute )
22
+ end
23
+
24
+ def conditional_get( id, modified_since, attribute = :updated_at )
25
+ _conditional_get( :get, id, modified_since, attribute )
26
+ end
27
+ end
28
+ DataMapper::Associations::OneToMany::Collection.send( :include,
29
+ ConditionalGet )
30
+ DataMapper::Associations::ManyToMany::Collection.send( :include,
31
+ ConditionalGet )
32
+
33
+ module Immutable
34
+ def self.included( model )
35
+ model.class_eval do
36
+ validates_with_method :validate_immutable
37
+ end
38
+ end
39
+ def validate_immutable
40
+ if dirty? && ! new?
41
+ [ false, 'object is immutable' ]
42
+ else
43
+ true
44
+ end
45
+ end
46
+ end
47
+
48
+ module ModifiedBy
49
+
50
+ def current_user=( user )
51
+ @_current_user = user
52
+ end
53
+
54
+ def current_user
55
+ @_current_user
56
+ end
57
+
58
+ def _modified_by
59
+ self.modified_by = @_current_user if dirty? && @_current_user
60
+ end
61
+
62
+ def validate_modified_by
63
+ if @_current_user || ! dirty?
64
+ true
65
+ else
66
+ [ false, 'current_user was not set' ]
67
+ end
68
+ end
69
+
70
+ module Methods
71
+ def modified_by( *args )
72
+ belongs_to :modified_by, *args
73
+
74
+ before :valid?, :_modified_by
75
+
76
+ validates_with_method :validate_modified_by
77
+ end
78
+ end
79
+
80
+ DataMapper::Model.append_inclusions self
81
+ DataMapper::Model.append_extensions Methods
82
+ end
83
+ end
@@ -0,0 +1,39 @@
1
+ module Ixtlan
2
+ module DataMapper
3
+ module ModifiedBy
4
+
5
+ def current_user=( user )
6
+ @_current_user = user
7
+ end
8
+
9
+ def current_user
10
+ @_current_user
11
+ end
12
+
13
+ def _modified_by
14
+ self.modified_by = @_current_user if dirty? && @_current_user
15
+ end
16
+
17
+ def validate_modified_by
18
+ if @_current_user || ! dirty?
19
+ true
20
+ else
21
+ [ false, 'current_user was not set' ]
22
+ end
23
+ end
24
+
25
+ module Methods
26
+ def modified_by( *args )
27
+ belongs_to :modified_by, *args
28
+
29
+ before :valid?, :_modified_by
30
+
31
+ validates_with_method :validate_modified_by
32
+ end
33
+ end
34
+
35
+ ::DataMapper::Model.append_inclusions self
36
+ ::DataMapper::Model.append_extensions Methods
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,39 @@
1
+ module Ixtlan
2
+ module DataMapper
3
+ module ModifiedBy
4
+
5
+ def current_user=( user )
6
+ @_current_user = user
7
+ end
8
+
9
+ def current_user
10
+ @_current_user
11
+ end
12
+
13
+ def _modified_by
14
+ self.modified_by = @_current_user if dirty? && @_current_user
15
+ end
16
+
17
+ def validate_modified_by
18
+ if @_current_user || ! dirty?
19
+ true
20
+ else
21
+ [ false, 'current_user was not set' ]
22
+ end
23
+ end
24
+
25
+ module Methods
26
+ def modified_by( *args )
27
+ belongs_to :modified_by, *args
28
+
29
+ before :valid?, :_modified_by
30
+
31
+ validates_with_method :validate_modified_by
32
+ end
33
+ end
34
+
35
+ ::DataMapper::Model.append_inclusions self
36
+ ::DataMapper::Model.append_extensions Methods
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,53 @@
1
+ #
2
+ # Copyright (C) 2012 mkristian
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of
5
+ # this software and associated documentation files (the "Software"), to deal in
6
+ # the Software without restriction, including without limitation the rights to
7
+ # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
8
+ # the Software, and to permit persons to whom the Software is furnished to do so,
9
+ # subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in all
12
+ # copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
16
+ # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
17
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
18
+ # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19
+ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
+ #
21
+ require 'ixtlan/optimistic/stale_check'
22
+ module Ixtlan
23
+ module Optimistic
24
+ module DataMapper
25
+
26
+ def self.included(base)
27
+ base.extend StaleCheck
28
+ base.class_eval do
29
+
30
+ def self.optimistic_get(updated_at, *args)
31
+ result = get( *args )
32
+ if result
33
+ __check( updated_at )
34
+ __check_stale( updated_at, result )
35
+ end
36
+ end
37
+
38
+ def self.optimistic_get!(updated_at, *args)
39
+ result = get!( *args )
40
+ __check( updated_at )
41
+ __check_stale( updated_at, result )
42
+ end
43
+ end
44
+ end
45
+
46
+ ::DataMapper::Model.append_inclusions( Ixtlan::Optimistic::DataMapper )
47
+ ::DataMapper::Associations::OneToMany::Collection.send( :include,
48
+ Ixtlan::Optimistic::DataMapper )
49
+ ::DataMapper::Associations::ManyToMany::Collection.send( :include,
50
+ Ixtlan::Optimistic::DataMapper )
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,71 @@
1
+ #
2
+ # Copyright (C) 2012 mkristian
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of
5
+ # this software and associated documentation files (the "Software"), to deal in
6
+ # the Software without restriction, including without limitation the rights to
7
+ # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
8
+ # the Software, and to permit persons to whom the Software is furnished to do so,
9
+ # subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in all
12
+ # copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
16
+ # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
17
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
18
+ # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19
+ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
+ #
21
+ require 'ixtlan/datamapper/stale_object_exception'
22
+ module Ixtlan
23
+ module DataMapper
24
+ module OptimisticGet
25
+
26
+ def self.included(base)
27
+ base.extend OptimisticGet
28
+ end
29
+
30
+ public
31
+
32
+ def optimistic_get(updated_at, *args)
33
+ result = get( *args )
34
+ if result
35
+ check_stale( updated_at, result )
36
+ end
37
+ end
38
+
39
+ def optimistic_get!(updated_at, *args)
40
+ result = get!( *args )
41
+ check_stale( updated_at, result )
42
+ end
43
+
44
+ private
45
+
46
+ def check_stale( updated_at, result )
47
+ unless updated_at
48
+ raise StaleObjectException.new "no 'updated_at' given for #{self}."
49
+ end
50
+ if updated_at.is_a? String
51
+ updated_at = DateTime.parse( updated_at.sub(/[.][0-9]+/, '') )
52
+ end
53
+ # rails hacky-de-hack
54
+ if defined?( ActiveSupport::TimeWithZone ) && updated_at.is_a?( ActiveSupport::TimeWithZone )
55
+ updated_at = updated_at.to_datetime
56
+ end
57
+ if updated_at != result.updated_at && updated_at.strftime("%Y:%m:%d %H:%M:%S") != result.updated_at.strftime("%Y:%m:%d %H:%M:%S")
58
+
59
+ raise StaleObjectException.new "#{result.model} with key [#{result.id}] was updated at #{result.updated_at} is newer than #{updated_at}."
60
+ end
61
+ result
62
+ end
63
+ end
64
+
65
+ ::DataMapper::Model.append_inclusions( OptimisticGet )
66
+ ::DataMapper::Associations::OneToMany::Collection.send( :include,
67
+ OptimisticGet )
68
+ ::DataMapper::Associations::ManyToMany::Collection.send( :include,
69
+ OptimisticGet )
70
+ end
71
+ end
@@ -0,0 +1,72 @@
1
+ #
2
+ # Copyright (C) 2012 mkristian
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of
5
+ # this software and associated documentation files (the "Software"), to deal in
6
+ # the Software without restriction, including without limitation the rights to
7
+ # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
8
+ # the Software, and to permit persons to whom the Software is furnished to do so,
9
+ # subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in all
12
+ # copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
16
+ # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
17
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
18
+ # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19
+ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
+ #
21
+ require 'ixtlan/datamapper/stale_object_exception'
22
+ module Ixtlan
23
+ module DataMapper
24
+ module OptimisticGet
25
+
26
+ def self.included(base)
27
+ base.extend OptimisticGet
28
+ end
29
+
30
+ public
31
+
32
+ def optimistic_get(updated_at, *args)
33
+ result = get( *args )
34
+ if result
35
+ check_stale( updated_at, result )
36
+ end
37
+ end
38
+
39
+ def optimistic_get!(updated_at, *args)
40
+ result = get!( *args )
41
+ check_stale( updated_at, result )
42
+ end
43
+
44
+ private
45
+
46
+ def check_stale( updated_at, result )
47
+ unless updated_at
48
+ raise StaleObjectException.new "no 'updated_at' given for #{self}."
49
+ end
50
+ if updated_at.is_a? String
51
+ updated_at = DateTime.parse( updated_at.sub(/[.][0-9]+/, '') )
52
+ end
53
+ # rails hacky-de-hack
54
+ if defined?( ActiveSupport::TimeWithZone ) && updated_at.is_a?( ActiveSupport::TimeWithZone )
55
+ updated_at = updated_at.to_datetime
56
+ end
57
+ updated_at = updated_at.new_offset(0)
58
+ if updated_at != result.updated_at && updated_at.strftime("%Y:%m:%d %H:%M:%S") != result.updated_at.strftime("%Y:%m:%d %H:%M:%S")
59
+
60
+ raise StaleObjectException.new "#{result.model} with key [#{result.id}] was updated at #{result.updated_at} is newer than #{updated_at}."
61
+ end
62
+ result
63
+ end
64
+ end
65
+
66
+ ::DataMapper::Model.append_inclusions( OptimisticGet )
67
+ ::DataMapper::Associations::OneToMany::Collection.send( :include,
68
+ OptimisticGet )
69
+ ::DataMapper::Associations::ManyToMany::Collection.send( :include,
70
+ OptimisticGet )
71
+ end
72
+ end