simply_stored 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (121) hide show
  1. data/lib/simply_stored/class_methods_base.rb +31 -0
  2. data/lib/simply_stored/couch/belongs_to.rb +117 -0
  3. data/lib/simply_stored/couch/ext/couch_potato.rb +16 -0
  4. data/lib/simply_stored/couch/has_many.rb +148 -0
  5. data/lib/simply_stored/couch/has_one.rb +93 -0
  6. data/lib/simply_stored/couch/validations.rb +74 -0
  7. data/lib/simply_stored/couch/views/array_property_view_spec.rb +22 -0
  8. data/lib/simply_stored/couch/views.rb +1 -0
  9. data/lib/simply_stored/couch.rb +278 -0
  10. data/lib/simply_stored/instance_methods.rb +143 -0
  11. data/lib/simply_stored/simpledb/associations.rb +196 -0
  12. data/lib/simply_stored/simpledb/attributes.rb +173 -0
  13. data/lib/simply_stored/simpledb/storag.rb +85 -0
  14. data/lib/simply_stored/simpledb/validations.rb +88 -0
  15. data/lib/simply_stored/simpledb.rb +212 -0
  16. data/lib/simply_stored/storage.rb +93 -0
  17. data/lib/simply_stored.rb +9 -0
  18. data/test/custom_views_test.rb +33 -0
  19. data/test/fixtures/couch.rb +182 -0
  20. data/test/fixtures/simpledb/item.rb +11 -0
  21. data/test/fixtures/simpledb/item_daddy.rb +8 -0
  22. data/test/fixtures/simpledb/log_item.rb +3 -0
  23. data/test/fixtures/simpledb/namespace_bar.rb +5 -0
  24. data/test/fixtures/simpledb/namespace_foo.rb +7 -0
  25. data/test/fixtures/simpledb/protected_item.rb +3 -0
  26. data/test/simply_stored_couch_test.rb +1684 -0
  27. data/test/simply_stored_simpledb_test.rb +1341 -0
  28. data/test/test_helper.rb +22 -0
  29. data/test/vendor/dhaka-2.2.1/lib/dhaka/dot/dot.rb +29 -0
  30. data/test/vendor/dhaka-2.2.1/lib/dhaka/evaluator/evaluator.rb +133 -0
  31. data/test/vendor/dhaka-2.2.1/lib/dhaka/grammar/closure_hash.rb +15 -0
  32. data/test/vendor/dhaka-2.2.1/lib/dhaka/grammar/grammar.rb +240 -0
  33. data/test/vendor/dhaka-2.2.1/lib/dhaka/grammar/grammar_symbol.rb +27 -0
  34. data/test/vendor/dhaka-2.2.1/lib/dhaka/grammar/precedence.rb +19 -0
  35. data/test/vendor/dhaka-2.2.1/lib/dhaka/grammar/production.rb +36 -0
  36. data/test/vendor/dhaka-2.2.1/lib/dhaka/lexer/accept_actions.rb +36 -0
  37. data/test/vendor/dhaka-2.2.1/lib/dhaka/lexer/alphabet.rb +21 -0
  38. data/test/vendor/dhaka-2.2.1/lib/dhaka/lexer/compiled_lexer.rb +46 -0
  39. data/test/vendor/dhaka-2.2.1/lib/dhaka/lexer/dfa.rb +121 -0
  40. data/test/vendor/dhaka-2.2.1/lib/dhaka/lexer/lexeme.rb +32 -0
  41. data/test/vendor/dhaka-2.2.1/lib/dhaka/lexer/lexer.rb +70 -0
  42. data/test/vendor/dhaka-2.2.1/lib/dhaka/lexer/lexer_run.rb +78 -0
  43. data/test/vendor/dhaka-2.2.1/lib/dhaka/lexer/regex_grammar.rb +392 -0
  44. data/test/vendor/dhaka-2.2.1/lib/dhaka/lexer/regex_parser.rb +2010 -0
  45. data/test/vendor/dhaka-2.2.1/lib/dhaka/lexer/regex_tokenizer.rb +14 -0
  46. data/test/vendor/dhaka-2.2.1/lib/dhaka/lexer/specification.rb +96 -0
  47. data/test/vendor/dhaka-2.2.1/lib/dhaka/lexer/state.rb +68 -0
  48. data/test/vendor/dhaka-2.2.1/lib/dhaka/lexer/state_machine.rb +37 -0
  49. data/test/vendor/dhaka-2.2.1/lib/dhaka/parser/action.rb +55 -0
  50. data/test/vendor/dhaka-2.2.1/lib/dhaka/parser/channel.rb +58 -0
  51. data/test/vendor/dhaka-2.2.1/lib/dhaka/parser/compiled_parser.rb +51 -0
  52. data/test/vendor/dhaka-2.2.1/lib/dhaka/parser/conflict.rb +54 -0
  53. data/test/vendor/dhaka-2.2.1/lib/dhaka/parser/item.rb +42 -0
  54. data/test/vendor/dhaka-2.2.1/lib/dhaka/parser/parse_result.rb +50 -0
  55. data/test/vendor/dhaka-2.2.1/lib/dhaka/parser/parse_tree.rb +66 -0
  56. data/test/vendor/dhaka-2.2.1/lib/dhaka/parser/parser.rb +165 -0
  57. data/test/vendor/dhaka-2.2.1/lib/dhaka/parser/parser_methods.rb +11 -0
  58. data/test/vendor/dhaka-2.2.1/lib/dhaka/parser/parser_run.rb +39 -0
  59. data/test/vendor/dhaka-2.2.1/lib/dhaka/parser/parser_state.rb +74 -0
  60. data/test/vendor/dhaka-2.2.1/lib/dhaka/parser/token.rb +22 -0
  61. data/test/vendor/dhaka-2.2.1/lib/dhaka/runtime.rb +51 -0
  62. data/test/vendor/dhaka-2.2.1/lib/dhaka/tokenizer/tokenizer.rb +190 -0
  63. data/test/vendor/dhaka-2.2.1/lib/dhaka.rb +62 -0
  64. data/test/vendor/dhaka-2.2.1/test/all_tests.rb +5 -0
  65. data/test/vendor/dhaka-2.2.1/test/arithmetic/arithmetic_evaluator.rb +64 -0
  66. data/test/vendor/dhaka-2.2.1/test/arithmetic/arithmetic_evaluator_test.rb +43 -0
  67. data/test/vendor/dhaka-2.2.1/test/arithmetic/arithmetic_grammar.rb +41 -0
  68. data/test/vendor/dhaka-2.2.1/test/arithmetic/arithmetic_grammar_test.rb +9 -0
  69. data/test/vendor/dhaka-2.2.1/test/arithmetic/arithmetic_test_methods.rb +9 -0
  70. data/test/vendor/dhaka-2.2.1/test/arithmetic/arithmetic_tokenizer.rb +39 -0
  71. data/test/vendor/dhaka-2.2.1/test/arithmetic/arithmetic_tokenizer_test.rb +38 -0
  72. data/test/vendor/dhaka-2.2.1/test/arithmetic_precedence/arithmetic_precedence_evaluator.rb +43 -0
  73. data/test/vendor/dhaka-2.2.1/test/arithmetic_precedence/arithmetic_precedence_grammar.rb +24 -0
  74. data/test/vendor/dhaka-2.2.1/test/arithmetic_precedence/arithmetic_precedence_grammar_test.rb +30 -0
  75. data/test/vendor/dhaka-2.2.1/test/arithmetic_precedence/arithmetic_precedence_lexer_specification.rb +23 -0
  76. data/test/vendor/dhaka-2.2.1/test/arithmetic_precedence/arithmetic_precedence_parser_test.rb +33 -0
  77. data/test/vendor/dhaka-2.2.1/test/brackets/bracket_grammar.rb +23 -0
  78. data/test/vendor/dhaka-2.2.1/test/brackets/bracket_tokenizer.rb +22 -0
  79. data/test/vendor/dhaka-2.2.1/test/brackets/brackets_test.rb +28 -0
  80. data/test/vendor/dhaka-2.2.1/test/chittagong/chittagong_driver.rb +46 -0
  81. data/test/vendor/dhaka-2.2.1/test/chittagong/chittagong_driver_test.rb +276 -0
  82. data/test/vendor/dhaka-2.2.1/test/chittagong/chittagong_evaluator.rb +284 -0
  83. data/test/vendor/dhaka-2.2.1/test/chittagong/chittagong_evaluator_test.rb +38 -0
  84. data/test/vendor/dhaka-2.2.1/test/chittagong/chittagong_grammar.rb +104 -0
  85. data/test/vendor/dhaka-2.2.1/test/chittagong/chittagong_lexer.rb +109 -0
  86. data/test/vendor/dhaka-2.2.1/test/chittagong/chittagong_lexer_specification.rb +37 -0
  87. data/test/vendor/dhaka-2.2.1/test/chittagong/chittagong_lexer_test.rb +58 -0
  88. data/test/vendor/dhaka-2.2.1/test/chittagong/chittagong_parser.rb +879 -0
  89. data/test/vendor/dhaka-2.2.1/test/chittagong/chittagong_parser_test.rb +55 -0
  90. data/test/vendor/dhaka-2.2.1/test/chittagong/chittagong_test.rb +170 -0
  91. data/test/vendor/dhaka-2.2.1/test/core/another_lalr_but_not_slr_grammar.rb +20 -0
  92. data/test/vendor/dhaka-2.2.1/test/core/compiled_parser_test.rb +44 -0
  93. data/test/vendor/dhaka-2.2.1/test/core/dfa_test.rb +170 -0
  94. data/test/vendor/dhaka-2.2.1/test/core/evaluator_test.rb +22 -0
  95. data/test/vendor/dhaka-2.2.1/test/core/grammar_test.rb +83 -0
  96. data/test/vendor/dhaka-2.2.1/test/core/lalr_but_not_slr_grammar.rb +19 -0
  97. data/test/vendor/dhaka-2.2.1/test/core/lexer_test.rb +139 -0
  98. data/test/vendor/dhaka-2.2.1/test/core/malformed_grammar.rb +7 -0
  99. data/test/vendor/dhaka-2.2.1/test/core/malformed_grammar_test.rb +8 -0
  100. data/test/vendor/dhaka-2.2.1/test/core/nullable_grammar.rb +21 -0
  101. data/test/vendor/dhaka-2.2.1/test/core/parse_result_test.rb +44 -0
  102. data/test/vendor/dhaka-2.2.1/test/core/parser_state_test.rb +24 -0
  103. data/test/vendor/dhaka-2.2.1/test/core/parser_test.rb +131 -0
  104. data/test/vendor/dhaka-2.2.1/test/core/precedence_grammar.rb +17 -0
  105. data/test/vendor/dhaka-2.2.1/test/core/precedence_grammar_test.rb +9 -0
  106. data/test/vendor/dhaka-2.2.1/test/core/rr_conflict_grammar.rb +21 -0
  107. data/test/vendor/dhaka-2.2.1/test/core/simple_grammar.rb +22 -0
  108. data/test/vendor/dhaka-2.2.1/test/core/sr_conflict_grammar.rb +16 -0
  109. data/test/vendor/dhaka-2.2.1/test/dhaka_test_helper.rb +17 -0
  110. data/test/vendor/dhaka-2.2.1/test/fake_logger.rb +17 -0
  111. data/test/vendor/simplerdb-0.2/lib/simplerdb/client_exception.rb +10 -0
  112. data/test/vendor/simplerdb-0.2/lib/simplerdb/db.rb +146 -0
  113. data/test/vendor/simplerdb-0.2/lib/simplerdb/query_language.rb +266 -0
  114. data/test/vendor/simplerdb-0.2/lib/simplerdb/server.rb +33 -0
  115. data/test/vendor/simplerdb-0.2/lib/simplerdb/servlet.rb +191 -0
  116. data/test/vendor/simplerdb-0.2/lib/simplerdb.rb +3 -0
  117. data/test/vendor/simplerdb-0.2/test/functional_test.rb +81 -0
  118. data/test/vendor/simplerdb-0.2/test/query_evaluator_test.rb +73 -0
  119. data/test/vendor/simplerdb-0.2/test/query_parser_test.rb +64 -0
  120. data/test/vendor/simplerdb-0.2/test/simplerdb_test.rb +80 -0
  121. metadata +182 -0
@@ -0,0 +1,31 @@
1
+ module SimplyStored
2
+ module ClassMethods
3
+ module Base
4
+ def get_class_from_name(klass_name)
5
+ klass_name.to_s.gsub('__','/').gsub('__','::').classify.constantize
6
+ end
7
+
8
+ def foreign_key
9
+ name.underscore.gsub('/','__').gsub('::','__') + "_id"
10
+ end
11
+
12
+ def foreign_property
13
+ name.underscore.gsub('/','__').gsub('::','__')
14
+ end
15
+
16
+ def attr_protected(*args)
17
+ @_protected_attributes ||= []
18
+ @_protected_attributes += args.to_a
19
+ end
20
+
21
+ def attr_accessible(*args)
22
+ @_accessible_attributes ||= []
23
+ @_accessible_attributes += args.to_a
24
+ end
25
+
26
+ def _find_property(name)
27
+ properties.find{|property| property.name == name}
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,117 @@
1
+ # Gracefully taken from CouchPotato after it has been removed for good.
2
+ module SimplyStored
3
+ module Couch
4
+ module BelongsTo
5
+
6
+ def belongs_to(name)
7
+ map_definition_without_deleted = <<-eos
8
+ function(doc) {
9
+ if (doc['ruby_class'] == '#{self.to_s}' && doc['#{name.to_s}_id'] != null) {
10
+ if (doc['#{soft_delete_attribute}'] && doc['#{soft_delete_attribute}'] != null){
11
+ // "soft" deleted
12
+ }else{
13
+ emit(doc.#{name.to_s}_id, null);
14
+ }
15
+ }
16
+ }
17
+ eos
18
+
19
+ view "association_#{self.name.underscore}_belongs_to_#{name}",
20
+ :map => map_definition_without_deleted,
21
+ :type => "custom",
22
+ :include_docs => true
23
+
24
+ map_definition_with_deleted = <<-eos
25
+ function(doc) {
26
+ if (doc['ruby_class'] == '#{self.to_s}' && doc['#{name.to_s}_id'] != null) {
27
+ emit(doc.#{name.to_s}_id, null);
28
+ }
29
+ }
30
+ eos
31
+
32
+ view "association_#{self.name.underscore}_belongs_to_#{name}_with_deleted",
33
+ :map => map_definition_with_deleted,
34
+ :type => "custom",
35
+ :include_docs => true
36
+
37
+ property name, :class => SimplyStored::Couch::BelongsTo::Property
38
+ end
39
+
40
+ class Property #:nodoc:
41
+ attr_accessor :name, :options
42
+
43
+ def initialize(owner_clazz, name, options = {})
44
+ @name, @options = name, options
45
+ item_class_name = self.item_class_name
46
+ owner_clazz.class_eval do
47
+ attr_reader "#{name}_id"
48
+ attr_accessor "#{name}_id_was"
49
+
50
+ define_method name do |*args|
51
+ options = args.last.is_a?(Hash) ? args.last : {}
52
+ options.assert_valid_keys(:force_reload, :with_deleted)
53
+ forced_reload = options[:force_reload] || false
54
+ with_deleted = options[:with_deleted] || false
55
+
56
+ return instance_variable_get("@#{name}") unless instance_variable_get("@#{name}").nil? or forced_reload
57
+ instance_variable_set("@#{name}", send("#{name}_id") ? Object.const_get(item_class_name).find(send("#{name}_id"), :with_deleted => with_deleted) : nil)
58
+ end
59
+
60
+ define_method "#{name}=" do |value|
61
+ klass = self.class.get_class_from_name(name)
62
+ raise ArgumentError, "expected #{klass} got #{value.class}" unless value.nil? || value.is_a?(klass)
63
+
64
+ instance_variable_set("@#{name}", value)
65
+ if value.nil?
66
+ instance_variable_set("@#{name}_id", nil)
67
+ else
68
+ instance_variable_set("@#{name}_id", value.id)
69
+ end
70
+ end
71
+
72
+ define_method "#{name}_id=" do |id|
73
+ remove_instance_variable("@#{name}") if instance_variable_defined?("@#{name}")
74
+ instance_variable_set("@#{name}_id", id)
75
+ end
76
+
77
+ define_method "#{name}_changed?" do
78
+ self.send("#{name}_id") != self.send("#{name}_id_was")
79
+ end
80
+ end
81
+ end
82
+
83
+ def save(object)
84
+ end
85
+
86
+ def dirty?(object)
87
+ object.send("#{name}_id_was") != object.send("#{name}_id")
88
+ end
89
+
90
+ def reset_dirty_attribute(object)
91
+ object.send("#{name}_id_was=", object.send("#{name}_id"))
92
+ end
93
+
94
+ def destroy(object)
95
+
96
+ end
97
+
98
+ def build(object, json)
99
+ object.send "#{name}_id=", json["#{name}_id"]
100
+ object.send "#{name}_id_was=", json["#{name}_id"]
101
+ end
102
+
103
+ def serialize(json, object)
104
+ json["#{name}_id"] = object.send("#{name}_id") if object.send("#{name}_id")
105
+ end
106
+
107
+ def item_class_name
108
+ @name.to_s.camelize
109
+ end
110
+
111
+ def association?
112
+ true
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,16 @@
1
+ module CouchPotato
2
+ module Persistence
3
+ module DirtyAttributes
4
+ private
5
+
6
+ def reset_dirty_attributes
7
+ self.class.properties.each do |property|
8
+ if !property.respond_to?(:supports_dirty?) || property.supports_dirty?
9
+ property.respond_to?(:reset_dirty_attribute) ? property.reset_dirty_attribute(self) :
10
+ instance_variable_set("@#{property.name}_was", send(property.name))
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,148 @@
1
+ module SimplyStored
2
+ module Couch
3
+ module HasMany
4
+ def has_many(name, options = {})
5
+ property name, options.merge(:class => SimplyStored::Couch::HasMany::Property)
6
+ end
7
+
8
+ def define_has_many_getter(name)
9
+ define_method(name) do |*args|
10
+ options = args.first && args.first.is_a?(Hash) && args.first
11
+ if options
12
+ options.assert_valid_keys(:force_reload, :with_deleted)
13
+ forced_reload = options[:force_reload]
14
+ with_deleted = options[:with_deleted]
15
+ else
16
+ forced_reload = false
17
+ with_deleted = false
18
+ end
19
+
20
+ if forced_reload || instance_variable_get("@#{name}").nil?
21
+ instance_variable_set("@#{name}", find_associated(name, self.class, :with_deleted => with_deleted))
22
+ end
23
+ instance_variable_get("@#{name}")
24
+ end
25
+ end
26
+
27
+ def define_has_many_through_getter(name, through)
28
+ raise ArgumentError, "no such relation: #{self} - #{through}" unless instance_methods.map(&:to_sym).include?(through.to_sym)
29
+
30
+ define_method(name) do |*args|
31
+ options = args.first && args.first.is_a?(Hash) && args.first
32
+ if options
33
+ options.assert_valid_keys(:force_reload, :with_deleted)
34
+ forced_reload = options[:force_reload]
35
+ with_deleted = options[:with_deleted]
36
+ else
37
+ forced_reload = false
38
+ with_deleted = false
39
+ end
40
+
41
+ if forced_reload || instance_variable_get("@#{name}").nil?
42
+
43
+ # there is probably a faster way to query this
44
+ intermediate_objects = find_associated(through, self.class, :with_deleted => with_deleted)
45
+
46
+ through_objects = intermediate_objects.map do |intermediate_object|
47
+ intermediate_object.send(name.to_s.singularize.underscore, :with_deleted => with_deleted)
48
+ end.flatten.uniq
49
+
50
+ instance_variable_set("@#{name}", through_objects)
51
+ end
52
+ instance_variable_get("@#{name}")
53
+ end
54
+ end
55
+
56
+ def define_has_many_setter_add(name)
57
+ define_method("add_#{name.to_s.singularize}") do |value|
58
+ klass = self.class.get_class_from_name(name)
59
+ raise ArgumentError, "expected #{klass} got #{value.class}" unless value.is_a?(klass)
60
+
61
+ value.send("#{self.class.foreign_key}=", id)
62
+ value.save
63
+ cached_version = instance_variable_get("@#{name}") || []
64
+ instance_variable_set("@#{name}", cached_version << value)
65
+ end
66
+ end
67
+
68
+ def define_has_many_setter_remove(name)
69
+ define_method "remove_#{name.to_s.singularize}" do |value|
70
+ klass = self.class.get_class_from_name(name)
71
+ raise ArgumentError, "expected #{klass} got #{value.class}" unless value.is_a?(klass)
72
+ raise ArgumentError, "cannot remove not mine" unless value.send(self.class.foreign_key.to_sym) == id
73
+
74
+ if self.class._find_property(name).options[:dependent] == :destroy
75
+ value.destroy
76
+ else
77
+ value.send("#{self.class.foreign_key}=", nil)
78
+ value.save
79
+ end
80
+
81
+ cached_version = instance_variable_get("@#{name}") || []
82
+ instance_variable_set("@#{name}", cached_version.delete_if{|item| item.id == value.id})
83
+ end
84
+ end
85
+
86
+ def define_has_many_setter_remove_all(name)
87
+ define_method "remove_all_#{name}" do
88
+ all = send("#{name}", :force_reload => true)
89
+
90
+ all.collect{|i| i}.each do |item|
91
+ send("remove_#{name.to_s.singularize}", item)
92
+ end
93
+ end
94
+ end
95
+
96
+ class Property
97
+ attr_reader :name, :options
98
+
99
+ def initialize(owner_clazz, name, options = {})
100
+ options = {
101
+ :dependent => :nullify,
102
+ :through => nil
103
+ }.update(options)
104
+ @name, @options = name, options
105
+
106
+ options.assert_valid_keys(:dependent, :through)
107
+
108
+ if options[:through]
109
+ owner_clazz.class_eval do
110
+ define_has_many_through_getter(name, options[:through])
111
+ end
112
+ else
113
+ owner_clazz.class_eval do
114
+ define_has_many_getter(name)
115
+ define_has_many_setter_add(name)
116
+ define_has_many_setter_remove(name)
117
+ define_has_many_setter_remove_all(name)
118
+ end
119
+ end
120
+ end
121
+
122
+ def save(object)
123
+ end
124
+
125
+ def dirty?(object)
126
+ false
127
+ end
128
+
129
+ def destroy(object)
130
+ end
131
+
132
+ def build(object, json)
133
+ end
134
+
135
+ def serialize(json, object)
136
+ end
137
+
138
+ def supports_dirty?
139
+ false
140
+ end
141
+
142
+ def association?
143
+ true
144
+ end
145
+ end
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,93 @@
1
+ module SimplyStored
2
+ module Couch
3
+ module HasOne
4
+ def has_one(name, options = {})
5
+ property name, options.merge(:class => SimplyStored::Couch::HasOne::Property)
6
+ end
7
+
8
+ def define_has_one_setter(name)
9
+ define_method("#{name}=") do |value|
10
+ klass = self.class.get_class_from_name(name)
11
+ raise ArgumentError, "expected #{klass} got #{value.class}" unless value.nil? || value.is_a?(klass)
12
+ old_value = send("#{name}", :force_reload => true)
13
+ if value.nil?
14
+ instance_variable_set("@#{name}", nil)
15
+ else
16
+ instance_variable_set("@#{name}", value)
17
+ value.send("#{self.class.foreign_key}=", id)
18
+ value.save
19
+ end
20
+
21
+ if old_value
22
+ if self.class._find_property(name).options[:dependent] == :destroy
23
+ old_value.destroy
24
+ else
25
+ old_value.send("#{self.class.foreign_property}=", nil)
26
+ old_value.save
27
+ end
28
+ end
29
+ old_value
30
+ end
31
+ end
32
+
33
+ def define_has_one_getter(name)
34
+ define_method(name) do |*args|
35
+ options = args.first && args.first.is_a?(Hash) && args.first
36
+ if options
37
+ options.assert_valid_keys(:force_reload, :with_deleted)
38
+ forced_reload = options[:force_reload]
39
+ with_deleted = options[:with_deleted]
40
+ else
41
+ forced_reload = false
42
+ with_deleted = false
43
+ end
44
+
45
+ if forced_reload || instance_variable_get("@#{name}").nil?
46
+ instance_variable_set("@#{name}", find_one_associated(name, self.class, :with_deleted => with_deleted))
47
+ end
48
+ instance_variable_get("@#{name}")
49
+ end
50
+ end
51
+
52
+ class Property
53
+ attr_reader :name, :options
54
+
55
+ def initialize(owner_clazz, name, options = {})
56
+ options = {:dependent => :nullify}.update(options)
57
+ @name, @options = name, options
58
+
59
+ options.assert_valid_keys(:dependent)
60
+
61
+ owner_clazz.class_eval do
62
+ define_has_one_getter(name)
63
+ define_has_one_setter(name)
64
+ end
65
+ end
66
+
67
+ def save(object)
68
+ end
69
+
70
+ def dirty?(object)
71
+ false
72
+ end
73
+
74
+ def destroy(object)
75
+ end
76
+
77
+ def build(object, json)
78
+ end
79
+
80
+ def serialize(json, object)
81
+ end
82
+
83
+ def supports_dirty?
84
+ false
85
+ end
86
+
87
+ def association?
88
+ true
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,74 @@
1
+ module SimplyStored
2
+ module Couch
3
+ module Validations
4
+ class ValidatesInclusionOf < ::Validatable::ValidationBase
5
+ required_option :in
6
+ option :allow_blank
7
+
8
+ def valid?(instance)
9
+ if self.allow_blank && instance.send(attribute).blank?
10
+ true
11
+ else
12
+ values = instance.send(attribute)
13
+ values = [values] unless values.is_a?(Array)
14
+ values.select{|value|
15
+ !self.in.include?(value)
16
+ }.empty?
17
+ end
18
+ end
19
+
20
+ def message(instance)
21
+ super || "must be one or more of #{self.in.join(", ")}"
22
+ end
23
+ end
24
+
25
+ class ValidatesFormatOf < ::Validatable::ValidationBase #:nodoc:
26
+ required_option :with
27
+ option :allow_blank
28
+
29
+ def valid?(instance)
30
+ (allow_blank && instance.send(attribute).blank?) ||
31
+ !(instance.send(self.attribute).to_s =~ self.with).nil?
32
+ end
33
+
34
+ def message(instance)
35
+ super || "is invalid"
36
+ end
37
+ end
38
+
39
+ class ValidatesUniquenessOf < ::Validatable::ValidationBase
40
+ def valid?(instance)
41
+ other_instance = instance.class.send("find_by_#{attribute}", instance.send(attribute))
42
+ if other_instance && other_instance != instance &&
43
+ other_instance.send(attribute) == instance.send(attribute)
44
+ false
45
+ else
46
+ true
47
+ end
48
+ end
49
+
50
+ def message(instance)
51
+ super || "#{attribute.to_s.try(:humanize) || attribute.to_s} is already taken"
52
+ end
53
+ end
54
+
55
+ def validates_inclusion_of(*args)
56
+ add_validations(args, ValidatesInclusionOf)
57
+ end
58
+
59
+ def validates_format_of(*args)
60
+ add_validations(args, ValidatesFormatOf)
61
+ end
62
+
63
+ def validates_uniqueness_of(*args)
64
+ args.each do |name|
65
+ view "by_#{name}", :key => name
66
+ end
67
+
68
+ add_validations(args, ValidatesUniquenessOf)
69
+ end
70
+ end
71
+ end
72
+ end
73
+
74
+
@@ -0,0 +1,22 @@
1
+ module SimplyStored
2
+ module Couch
3
+ module Views
4
+ class ArrayPropertyViewSpec < CouchPotato::View::ModelViewSpec
5
+ def map_function
6
+ "function(doc) {
7
+ if(doc.ruby_class && doc.ruby_class == '#{@klass.name}') {
8
+ if (#{formatted_key(key)}.constructor.toString().match(/function Array()/)) {
9
+ for (var i in #{formatted_key(key)}) {
10
+ emit(#{formatted_key(key)}[i], null);
11
+ }
12
+ } else {
13
+ emit(#{formatted_key(key)}, null);
14
+ }
15
+ }
16
+ }"
17
+ end
18
+
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1 @@
1
+ require 'simply_stored/couch/views/array_property_view_spec'