nobrainer 0.14.0 → 0.15.0
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.
- checksums.yaml +4 -4
- data/lib/no_brainer/config.rb +17 -1
- data/lib/no_brainer/criteria/count.rb +1 -1
- data/lib/no_brainer/criteria/first.rb +6 -0
- data/lib/no_brainer/criteria/where.rb +11 -5
- data/lib/no_brainer/decorated_symbol.rb +2 -1
- data/lib/no_brainer/document/attributes.rb +5 -3
- data/lib/no_brainer/document/criteria.rb +2 -2
- data/lib/no_brainer/document/persistance.rb +2 -2
- data/lib/no_brainer/document/types.rb +61 -129
- data/lib/no_brainer/document/types/boolean.rb +26 -0
- data/lib/no_brainer/document/types/date.rb +26 -0
- data/lib/no_brainer/document/types/float.rb +20 -0
- data/lib/no_brainer/document/types/integer.rb +18 -0
- data/lib/no_brainer/document/types/string.rb +14 -0
- data/lib/no_brainer/document/types/symbol.rb +21 -0
- data/lib/no_brainer/document/types/time.rb +41 -0
- data/lib/no_brainer/document/validation.rb +1 -0
- data/lib/no_brainer/error.rb +1 -1
- data/lib/nobrainer.rb +4 -0
- data/lib/rails/generators/nobrainer/model/model_generator.rb +2 -1
- data/lib/rails/generators/nobrainer/model/templates/model.rb.tt +7 -2
- metadata +9 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e97dd4f563340a2c8551ffefb21f22fc628954b2
|
4
|
+
data.tar.gz: 1fca054e8f966be9e7518f8245c39987d40068c7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1cbfebfa6ac2922e733d157522eda4e6c9edf9de9e51601f6892ac2ac2814593ed20807c68441a2ff7391398cf37896eeb739eaf2cdafa0da8e9fe91bb02fce2
|
7
|
+
data.tar.gz: ace1719ae85c7593145e81818fb1b93f715ad65d4634130c664b0fdd134c637aba0395066163b9fd3aee91f7ec0b27a53338e857ec2c089a4b425e02f2eba00b
|
data/lib/no_brainer/config.rb
CHANGED
@@ -4,7 +4,8 @@ module NoBrainer::Config
|
|
4
4
|
class << self
|
5
5
|
mattr_accessor :rethinkdb_url, :logger, :warn_on_active_record,
|
6
6
|
:auto_create_databases, :auto_create_tables,
|
7
|
-
:max_reconnection_tries, :durability,
|
7
|
+
:max_reconnection_tries, :durability,
|
8
|
+
:user_timezone, :db_timezone, :colorize_logger,
|
8
9
|
:distributed_lock_class
|
9
10
|
|
10
11
|
def apply_defaults
|
@@ -15,6 +16,8 @@ module NoBrainer::Config
|
|
15
16
|
self.auto_create_tables = true
|
16
17
|
self.max_reconnection_tries = 10
|
17
18
|
self.durability = default_durability
|
19
|
+
self.user_timezone = :local
|
20
|
+
self.db_timezone = :utc
|
18
21
|
self.colorize_logger = true
|
19
22
|
self.distributed_lock_class = nil
|
20
23
|
end
|
@@ -27,6 +30,7 @@ module NoBrainer::Config
|
|
27
30
|
def configure(&block)
|
28
31
|
apply_defaults unless configured?
|
29
32
|
block.call(self) if block
|
33
|
+
assert_valid_options!
|
30
34
|
@configured = true
|
31
35
|
|
32
36
|
NoBrainer.disconnect_if_url_changed
|
@@ -36,6 +40,18 @@ module NoBrainer::Config
|
|
36
40
|
!!@configured
|
37
41
|
end
|
38
42
|
|
43
|
+
def assert_valid_options!
|
44
|
+
assert_array_in :durability, [:hard, :soft]
|
45
|
+
assert_array_in :user_timezone, [:unchanged, :utc, :local]
|
46
|
+
assert_array_in :db_timezone, [:unchanged, :utc, :local]
|
47
|
+
end
|
48
|
+
|
49
|
+
def assert_array_in(name, values)
|
50
|
+
unless __send__(name).in?(values)
|
51
|
+
raise ArgumentError.new("Unknown configuration for #{name}: #{__send__(name)}. Valid values are: #{values.inspect}")
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
39
55
|
def default_rethinkdb_url
|
40
56
|
db = ENV['RETHINKDB_DB'] || ENV['RDB_DB']
|
41
57
|
db ||= "#{Rails.application.class.parent_name.underscore}_#{Rails.env}" rescue nil
|
@@ -17,6 +17,12 @@ module NoBrainer::Criteria::First
|
|
17
17
|
last.tap { |doc| raise NoBrainer::Error::DocumentNotFound unless doc }
|
18
18
|
end
|
19
19
|
|
20
|
+
def sample(n=nil)
|
21
|
+
result = NoBrainer.run { self.without_ordering.to_rql.sample(n.nil? ? 1 : n) }
|
22
|
+
result = result.map(&method(:instantiate_doc))
|
23
|
+
n.nil? ? result.first : result
|
24
|
+
end
|
25
|
+
|
20
26
|
private
|
21
27
|
|
22
28
|
def get_one(criteria)
|
@@ -54,24 +54,26 @@ module NoBrainer::Criteria::Where
|
|
54
54
|
end
|
55
55
|
end
|
56
56
|
|
57
|
-
class BinaryOperator < Struct.new(:key, :op, :value, :criteria)
|
57
|
+
class BinaryOperator < Struct.new(:key, :op, :value, :criteria, :casted_values)
|
58
58
|
def simplify
|
59
59
|
key = cast_key(self.key)
|
60
60
|
case op
|
61
61
|
when :in then
|
62
62
|
case value
|
63
|
-
when Range then BinaryOperator.new(key, :between, (cast_value(value.min)..cast_value(value.max)), criteria)
|
64
|
-
when Array then BinaryOperator.new(key, :in, value.map(&method(:cast_value)).uniq, criteria)
|
63
|
+
when Range then BinaryOperator.new(key, :between, (cast_value(value.min)..cast_value(value.max)), criteria, true)
|
64
|
+
when Array then BinaryOperator.new(key, :in, value.map(&method(:cast_value)).uniq, criteria, true)
|
65
65
|
else raise ArgumentError.new ":in takes an array/range, not #{value}"
|
66
66
|
end
|
67
|
-
|
67
|
+
when :between then BinaryOperator.new(key, :between, (cast_value(value.min)..cast_value(value.max)), criteria, true)
|
68
|
+
else BinaryOperator.new(key, op, cast_value(value), criteria, true)
|
68
69
|
end
|
69
70
|
end
|
70
71
|
|
71
72
|
def to_rql(doc)
|
72
73
|
case op
|
74
|
+
when :defined then value ? doc.has_fields(key) : doc.has_fields(key).not
|
73
75
|
when :between then (doc[key] >= value.min) & (doc[key] <= value.max)
|
74
|
-
when :in
|
76
|
+
when :in then RethinkDB::RQL.new.expr(value).contains(doc[key])
|
75
77
|
else doc[key].__send__(op, value)
|
76
78
|
end
|
77
79
|
end
|
@@ -87,6 +89,8 @@ module NoBrainer::Criteria::Where
|
|
87
89
|
end
|
88
90
|
|
89
91
|
def cast_value(value)
|
92
|
+
return value if casted_values
|
93
|
+
|
90
94
|
case association
|
91
95
|
when NoBrainer::Document::Association::BelongsTo::Metadata
|
92
96
|
target_klass = association.target_klass
|
@@ -99,6 +103,8 @@ module NoBrainer::Criteria::Where
|
|
99
103
|
end
|
100
104
|
|
101
105
|
def cast_key(key)
|
106
|
+
return key if casted_values
|
107
|
+
|
102
108
|
case association
|
103
109
|
when NoBrainer::Document::Association::BelongsTo::Metadata
|
104
110
|
association.foreign_key
|
@@ -2,7 +2,8 @@ class NoBrainer::DecoratedSymbol < Struct.new(:symbol, :modifier, :args)
|
|
2
2
|
MODIFIERS = { :in => :in, :nin => :nin,
|
3
3
|
:eq => :eq, :ne => :ne, :not => :ne,
|
4
4
|
:gt => :gt, :ge => :ge, :gte => :ge,
|
5
|
-
:lt => :lt, :le => :le, :lte => :le
|
5
|
+
:lt => :lt, :le => :le, :lte => :le,
|
6
|
+
:defined => :defined }
|
6
7
|
|
7
8
|
def self.hook
|
8
9
|
Symbol.class_eval do
|
@@ -1,7 +1,5 @@
|
|
1
1
|
module NoBrainer::Document::Attributes
|
2
|
-
VALID_FIELD_OPTIONS = [:index, :default, :type, :
|
3
|
-
:cast_db_to_user, :validates, :required, :unique,
|
4
|
-
:readonly, :primary_key]
|
2
|
+
VALID_FIELD_OPTIONS = [:index, :default, :type, :validates, :required, :unique, :in, :readonly, :primary_key]
|
5
3
|
RESERVED_FIELD_NAMES = [:index, :default, :and, :or, :selector, :associations, :pk_value] \
|
6
4
|
+ NoBrainer::DecoratedSymbol::MODIFIERS.keys
|
7
5
|
extend ActiveSupport::Concern
|
@@ -64,6 +62,10 @@ module NoBrainer::Document::Attributes
|
|
64
62
|
Hash[@_attributes.sort_by { |k,v| self.class.fields.keys.index(k.to_sym) || 2**10 }]
|
65
63
|
end
|
66
64
|
|
65
|
+
def to_s
|
66
|
+
"#<#{self.class} #{self.class.pk_name}: #{self.pk_value.inspect}>"
|
67
|
+
end
|
68
|
+
|
67
69
|
def inspect
|
68
70
|
"#<#{self.class} #{inspectable_attributes.map { |k,v| "#{k}: #{v.inspect}" }.join(', ')}>"
|
69
71
|
end
|
@@ -10,7 +10,7 @@ module NoBrainer::Document::Criteria
|
|
10
10
|
module ClassMethods
|
11
11
|
delegate :to_rql, # Core
|
12
12
|
:limit, :offset, :skip, # Limit
|
13
|
-
:order_by, :reverse_order,
|
13
|
+
:order_by, :reverse_order, :without_ordering, # OrderBy
|
14
14
|
:scoped, :unscoped, # Scope
|
15
15
|
:where, :with_index, :without_index, :used_index, :indexed?, # Where
|
16
16
|
:with_cache, :without_cache, # Cache
|
@@ -18,7 +18,7 @@ module NoBrainer::Document::Criteria
|
|
18
18
|
:delete_all, :destroy_all, # Delete
|
19
19
|
:includes, :preload, # Preload
|
20
20
|
:each, :to_a, # Enumerable
|
21
|
-
:first, :last, :first!, :last!, # First
|
21
|
+
:first, :last, :first!, :last!, :sample, # First
|
22
22
|
:update_all, :replace_all, # Update
|
23
23
|
:to => :all
|
24
24
|
|
@@ -28,7 +28,7 @@ module NoBrainer::Document::Persistance
|
|
28
28
|
|
29
29
|
def _create(options={})
|
30
30
|
return false if options[:validate] && !valid?
|
31
|
-
keys = self.class.insert_all(@_attributes)
|
31
|
+
keys = self.class.insert_all(self.class.persistable_attributes(@_attributes))
|
32
32
|
self.pk_value ||= keys.first
|
33
33
|
@new_record = false
|
34
34
|
true
|
@@ -50,7 +50,7 @@ module NoBrainer::Document::Persistance
|
|
50
50
|
attr = RethinkDB::RQL.new.literal(attr) if attr.is_a?(Hash)
|
51
51
|
[k, attr]
|
52
52
|
end]
|
53
|
-
_update(attrs) if attrs.present?
|
53
|
+
_update(self.class.persistable_attributes(attrs)) if attrs.present?
|
54
54
|
true
|
55
55
|
end
|
56
56
|
|
@@ -1,102 +1,7 @@
|
|
1
1
|
module NoBrainer::Document::Types
|
2
2
|
extend ActiveSupport::Concern
|
3
3
|
|
4
|
-
|
5
|
-
extend self
|
6
|
-
InvalidType = NoBrainer::Error::InvalidType
|
7
|
-
|
8
|
-
def String(value)
|
9
|
-
case value
|
10
|
-
when Symbol then value.to_s
|
11
|
-
else raise InvalidType
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
def Integer(value)
|
16
|
-
case value
|
17
|
-
when String
|
18
|
-
value = value.strip.gsub(/^\+/, '')
|
19
|
-
value.to_i.tap { |new_value| new_value.to_s == value or raise InvalidType }
|
20
|
-
when Float
|
21
|
-
value.to_i.tap { |new_value| new_value.to_f == value or raise InvalidType }
|
22
|
-
else raise InvalidType
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def Float(value)
|
27
|
-
case value
|
28
|
-
when Integer then value.to_f
|
29
|
-
when String
|
30
|
-
value = value.strip.gsub(/^\+/, '')
|
31
|
-
value = value.gsub(/0+$/, '') if value['.']
|
32
|
-
value = value.gsub(/\.$/, '')
|
33
|
-
value = "#{value}.0" unless value['.']
|
34
|
-
value.to_f.tap { |new_value| new_value.to_s == value or raise InvalidType }
|
35
|
-
else raise InvalidType
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def Boolean(value)
|
40
|
-
case value
|
41
|
-
when TrueClass then true
|
42
|
-
when FalseClass then false
|
43
|
-
when String, Integer
|
44
|
-
value = value.to_s.strip.downcase
|
45
|
-
return true if value.in? %w(true yes t 1)
|
46
|
-
return false if value.in? %w(false no f 0)
|
47
|
-
raise InvalidType
|
48
|
-
else raise InvalidType
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
def Symbol(value)
|
53
|
-
case value
|
54
|
-
when String
|
55
|
-
value = value.strip
|
56
|
-
raise InvalidType if value.empty?
|
57
|
-
value.to_sym
|
58
|
-
else raise InvalidType
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
def lookup(type)
|
63
|
-
public_method(type.to_s)
|
64
|
-
rescue NameError
|
65
|
-
proc { raise InvalidType }
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
module CastDBToUser
|
70
|
-
extend self
|
71
|
-
|
72
|
-
def Symbol(value)
|
73
|
-
value.to_sym rescue value
|
74
|
-
end
|
75
|
-
|
76
|
-
def lookup(type)
|
77
|
-
public_method(type.to_s)
|
78
|
-
rescue NameError
|
79
|
-
nil
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
included do
|
84
|
-
# We namespace our fake Boolean class to avoid polluting the global namespace
|
85
|
-
class_exec do
|
86
|
-
class Boolean
|
87
|
-
def initialize; raise; end
|
88
|
-
def self.inspect; 'Boolean'; end
|
89
|
-
def self.to_s; inspect; end
|
90
|
-
def self.name; inspect; end
|
91
|
-
end
|
92
|
-
end
|
93
|
-
before_validation :add_type_errors
|
94
|
-
|
95
|
-
# Fast access for db->user cast methods for performance when reading from
|
96
|
-
# the database.
|
97
|
-
singleton_class.send(:attr_accessor, :cast_db_to_user_fields)
|
98
|
-
self.cast_db_to_user_fields = Set.new
|
99
|
-
end
|
4
|
+
included { before_validation :add_type_errors }
|
100
5
|
|
101
6
|
def add_type_errors
|
102
7
|
return unless @pending_type_errors
|
@@ -108,49 +13,59 @@ module NoBrainer::Document::Types
|
|
108
13
|
def assign_attributes(attrs, options={})
|
109
14
|
super
|
110
15
|
if options[:from_db]
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
value = @_attributes[attr.to_s]
|
115
|
-
unless value.nil? || value.is_a?(type)
|
116
|
-
@_attributes[attr.to_s] = field_def[:cast_db_to_user].call(value)
|
117
|
-
end
|
118
|
-
end
|
16
|
+
@_attributes = Hash[@_attributes.map do |k,v|
|
17
|
+
[k, self.class.cast_db_to_model_for(k, v)]
|
18
|
+
end].with_indifferent_access
|
119
19
|
end
|
120
20
|
end
|
121
21
|
|
122
22
|
module ClassMethods
|
123
|
-
def
|
124
|
-
|
125
|
-
return value if
|
126
|
-
type
|
127
|
-
|
128
|
-
|
23
|
+
def cast_user_to_model_for(attr, value)
|
24
|
+
type = fields[attr.to_sym].try(:[], :type)
|
25
|
+
return value if type.nil? || value.nil?
|
26
|
+
if type.respond_to?(:nobrainer_cast_user_to_model)
|
27
|
+
type.nobrainer_cast_user_to_model(value)
|
28
|
+
else
|
29
|
+
raise NoBrainer::Error::InvalidType unless value.is_a?(type)
|
30
|
+
value
|
31
|
+
end
|
129
32
|
rescue NoBrainer::Error::InvalidType => error
|
130
|
-
error.type =
|
33
|
+
error.type = type
|
131
34
|
error.value = value
|
132
35
|
error.attr_name = attr
|
133
36
|
raise error
|
134
37
|
end
|
135
38
|
|
136
|
-
def
|
137
|
-
|
138
|
-
|
39
|
+
def cast_model_to_db_for(attr, value)
|
40
|
+
type = fields[attr.to_sym].try(:[], :type)
|
41
|
+
return value if type.nil? || value.nil? || !type.respond_to?(:nobrainer_cast_model_to_db)
|
42
|
+
type.nobrainer_cast_model_to_db(value)
|
43
|
+
end
|
44
|
+
|
45
|
+
def cast_db_to_model_for(attr, value)
|
46
|
+
type = fields[attr.to_sym].try(:[], :type)
|
47
|
+
return value if type.nil? || value.nil? || !type.respond_to?(:nobrainer_cast_db_to_model)
|
48
|
+
type.nobrainer_cast_db_to_model(value)
|
49
|
+
end
|
50
|
+
|
51
|
+
def cast_user_to_db_for(attr, value)
|
52
|
+
value = cast_user_to_model_for(attr, value)
|
53
|
+
cast_model_to_db_for(attr, value)
|
54
|
+
end
|
55
|
+
|
56
|
+
def persistable_attributes(attrs)
|
57
|
+
Hash[attrs.map { |k,v| [k, cast_model_to_db_for(k, v)] }]
|
139
58
|
end
|
140
59
|
|
141
60
|
def _field(attr, options={})
|
142
61
|
super
|
143
62
|
|
144
|
-
if options[:
|
145
|
-
([self] + descendants).each do |klass|
|
146
|
-
klass.cast_db_to_user_fields << attr
|
147
|
-
end
|
148
|
-
end
|
63
|
+
NoBrainer::Document::Types.load_type_extensions(options[:type]) if options[:type]
|
149
64
|
|
150
65
|
inject_in_layer :types do
|
151
66
|
define_method("#{attr}=") do |value|
|
152
67
|
begin
|
153
|
-
value = self.class.
|
68
|
+
value = self.class.cast_user_to_model_for(attr, value)
|
154
69
|
@pending_type_errors.try(:delete, attr)
|
155
70
|
rescue NoBrainer::Error::InvalidType => error
|
156
71
|
@pending_type_errors ||= {}
|
@@ -163,21 +78,38 @@ module NoBrainer::Document::Types
|
|
163
78
|
end
|
164
79
|
end
|
165
80
|
|
166
|
-
def field(attr, options={})
|
167
|
-
if options[:type]
|
168
|
-
options = options.merge(
|
169
|
-
:cast_user_to_db => NoBrainer::Document::Types::CastUserToDB.lookup(options[:type]),
|
170
|
-
:cast_db_to_user => NoBrainer::Document::Types::CastDBToUser.lookup(options[:type]))
|
171
|
-
end
|
172
|
-
super
|
173
|
-
end
|
174
|
-
|
175
81
|
def _remove_field(attr, options={})
|
176
82
|
super
|
83
|
+
|
177
84
|
inject_in_layer :types do
|
178
85
|
remove_method("#{attr}=")
|
179
86
|
remove_method("#{attr}?") if method_defined?("#{attr}?")
|
180
87
|
end
|
181
88
|
end
|
89
|
+
|
90
|
+
def field(attr, options={})
|
91
|
+
if options[:type] == Array || options[:type] == Hash
|
92
|
+
# XXX For the moment, NoBrainer does not support these complex types
|
93
|
+
options.delete(:type)
|
94
|
+
end
|
95
|
+
super
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
require File.join(File.dirname(__FILE__), 'types', 'boolean')
|
100
|
+
Boolean = NoBrainer::Boolean
|
101
|
+
|
102
|
+
class << self
|
103
|
+
mattr_accessor :loaded_extensions
|
104
|
+
self.loaded_extensions = Set.new
|
105
|
+
def load_type_extensions(klass)
|
106
|
+
unless loaded_extensions.include?(klass)
|
107
|
+
begin
|
108
|
+
require File.join(File.dirname(__FILE__), 'types', klass.name.underscore)
|
109
|
+
rescue LoadError
|
110
|
+
end
|
111
|
+
loaded_extensions << klass
|
112
|
+
end
|
113
|
+
end
|
182
114
|
end
|
183
115
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# We namespace our fake Boolean class to avoid polluting the global namespace
|
2
|
+
class NoBrainer::Boolean
|
3
|
+
def initialize; raise; end
|
4
|
+
def self.inspect; 'Boolean'; end
|
5
|
+
def self.to_s; inspect; end
|
6
|
+
def self.name; inspect; end
|
7
|
+
|
8
|
+
module NoBrainerExtentions
|
9
|
+
InvalidType = NoBrainer::Error::InvalidType
|
10
|
+
|
11
|
+
def nobrainer_cast_user_to_model(value)
|
12
|
+
case value
|
13
|
+
when TrueClass then true
|
14
|
+
when FalseClass then false
|
15
|
+
when String, Integer
|
16
|
+
value = value.to_s.strip.downcase
|
17
|
+
return true if value.in? %w(true yes t 1)
|
18
|
+
return false if value.in? %w(false no f 0)
|
19
|
+
raise InvalidType
|
20
|
+
else raise InvalidType
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
extend NoBrainerExtentions
|
25
|
+
end
|
26
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class Date
|
2
|
+
module NoBrainerExtentions
|
3
|
+
InvalidType = NoBrainer::Error::InvalidType
|
4
|
+
|
5
|
+
def nobrainer_cast_user_to_model(value)
|
6
|
+
case value
|
7
|
+
when Date then value
|
8
|
+
when String
|
9
|
+
value = value.strip
|
10
|
+
date = Date.parse(value) rescue (raise InvalidType)
|
11
|
+
raise InvalidType unless date.iso8601 == value
|
12
|
+
date
|
13
|
+
else raise InvalidType
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def nobrainer_cast_db_to_model(value)
|
18
|
+
value.is_a?(Time) ? value.to_date : value
|
19
|
+
end
|
20
|
+
|
21
|
+
def nobrainer_cast_model_to_db(value)
|
22
|
+
value.is_a?(Date) ? Time.utc(value.year, value.month, value.day) : value
|
23
|
+
end
|
24
|
+
end
|
25
|
+
extend NoBrainerExtentions
|
26
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class Float
|
2
|
+
module NoBrainerExtentions
|
3
|
+
InvalidType = NoBrainer::Error::InvalidType
|
4
|
+
|
5
|
+
def nobrainer_cast_user_to_model(value)
|
6
|
+
case value
|
7
|
+
when Float then value
|
8
|
+
when Integer then value.to_f
|
9
|
+
when String
|
10
|
+
value = value.strip.gsub(/^\+/, '')
|
11
|
+
value = value.gsub(/0+$/, '') if value['.']
|
12
|
+
value = value.gsub(/\.$/, '')
|
13
|
+
value = "#{value}.0" unless value['.']
|
14
|
+
value.to_f.tap { |new_value| new_value.to_s == value or raise InvalidType }
|
15
|
+
else raise InvalidType
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
extend NoBrainerExtentions
|
20
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class Integer
|
2
|
+
module NoBrainerExtentions
|
3
|
+
InvalidType = NoBrainer::Error::InvalidType
|
4
|
+
|
5
|
+
def nobrainer_cast_user_to_model(value)
|
6
|
+
case value
|
7
|
+
when Integer then value
|
8
|
+
when String
|
9
|
+
value = value.strip.gsub(/^\+/, '')
|
10
|
+
value.to_i.tap { |new_value| new_value.to_s == value or raise InvalidType }
|
11
|
+
when Float
|
12
|
+
value.to_i.tap { |new_value| new_value.to_f == value or raise InvalidType }
|
13
|
+
else raise InvalidType
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
extend NoBrainerExtentions
|
18
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class String
|
2
|
+
module NoBrainerExtentions
|
3
|
+
InvalidType = NoBrainer::Error::InvalidType
|
4
|
+
|
5
|
+
def nobrainer_cast_user_to_model(value)
|
6
|
+
case value
|
7
|
+
when String then value
|
8
|
+
when Symbol then value.to_s
|
9
|
+
else raise InvalidType
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
extend NoBrainerExtentions
|
14
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class Symbol
|
2
|
+
module NoBrainerExtentions
|
3
|
+
InvalidType = NoBrainer::Error::InvalidType
|
4
|
+
|
5
|
+
def nobrainer_cast_user_to_model(value)
|
6
|
+
case value
|
7
|
+
when Symbol then value
|
8
|
+
when String
|
9
|
+
value = value.strip
|
10
|
+
raise InvalidType if value.empty?
|
11
|
+
value.to_sym
|
12
|
+
else raise InvalidType
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def nobrainer_cast_db_to_model(value)
|
17
|
+
value.to_sym rescue (value.to_s.to_sym rescue value)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
extend NoBrainerExtentions
|
21
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'time'
|
2
|
+
|
3
|
+
class Time
|
4
|
+
module NoBrainerExtentions
|
5
|
+
InvalidType = NoBrainer::Error::InvalidType
|
6
|
+
|
7
|
+
def nobrainer_cast_user_to_model(value)
|
8
|
+
case value
|
9
|
+
when Time then time = value
|
10
|
+
when String
|
11
|
+
value = value.strip.sub(/Z$/, '+00:00')
|
12
|
+
# Using DateTime to preserve the timezone offset
|
13
|
+
dt = DateTime.parse(value) rescue (raise InvalidType)
|
14
|
+
time = Time.new(dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.zone)
|
15
|
+
raise InvalidType unless time.iso8601 == value
|
16
|
+
else raise InvalidType
|
17
|
+
end
|
18
|
+
|
19
|
+
nobrainer_timezoned(NoBrainer::Config.user_timezone, time)
|
20
|
+
end
|
21
|
+
|
22
|
+
def nobrainer_cast_db_to_model(value)
|
23
|
+
return value unless value.is_a?(Time)
|
24
|
+
nobrainer_timezoned(NoBrainer::Config.user_timezone, value)
|
25
|
+
end
|
26
|
+
|
27
|
+
def nobrainer_cast_model_to_db(value)
|
28
|
+
return value unless value.is_a?(Time)
|
29
|
+
nobrainer_timezoned(NoBrainer::Config.db_timezone, value)
|
30
|
+
end
|
31
|
+
|
32
|
+
def nobrainer_timezoned(tz, value)
|
33
|
+
case tz
|
34
|
+
when :local then value.getlocal
|
35
|
+
when :utc then value.getutc
|
36
|
+
when :unchanged then value
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
extend NoBrainerExtentions
|
41
|
+
end
|
@@ -18,6 +18,7 @@ module NoBrainer::Document::Validation
|
|
18
18
|
super
|
19
19
|
validates(attr, { :presence => options[:required] }) if options.has_key?(:required)
|
20
20
|
validates(attr, { :uniqueness => options[:unique] }) if options.has_key?(:unique)
|
21
|
+
validates(attr, { :inclusion => {:in => options[:in]} }) if options.has_key?(:in)
|
21
22
|
validates(attr, options[:validates]) if options[:validates]
|
22
23
|
end
|
23
24
|
end
|
data/lib/no_brainer/error.rb
CHANGED
data/lib/nobrainer.rb
CHANGED
@@ -2,7 +2,8 @@ require "rails/generators/nobrainer"
|
|
2
2
|
|
3
3
|
module NoBrainer::Generators
|
4
4
|
class ModelGenerator < Base
|
5
|
-
argument
|
5
|
+
argument(:attributes, :type => :array, default: [],
|
6
|
+
banner: "field[:type][:index] ... field[:type][:index]")
|
6
7
|
|
7
8
|
check_class_collision
|
8
9
|
|
@@ -2,12 +2,17 @@
|
|
2
2
|
class <%= class_name %><%= " < #{options[:parent].classify}" if options[:parent] %>
|
3
3
|
<% unless options[:parent] -%>
|
4
4
|
include NoBrainer::Document
|
5
|
+
include NoBrainer::Document::Timestamps
|
6
|
+
|
5
7
|
<% end -%>
|
6
8
|
<% attributes.reject(&:reference?).each do |attribute| -%>
|
7
|
-
field :<%= attribute.name
|
9
|
+
field :<%= attribute.name -%>
|
10
|
+
<%= puts attribute; ", :type => #{attribute.type.to_s.classify}" if attribute.type != :object -%>
|
11
|
+
<%= ", :index => true" if attribute.has_index? %>
|
8
12
|
<% end -%>
|
9
13
|
<% attributes.select(&:reference?).each do |attribute| -%>
|
10
|
-
belongs_to :<%= attribute.name
|
14
|
+
belongs_to :<%= attribute.name -%>
|
15
|
+
<%= ", :index => true" if attribute.has_index? %>
|
11
16
|
<% end -%>
|
12
17
|
end
|
13
18
|
<% end -%>
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nobrainer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.15.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nicolas Viennot
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-07-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rethinkdb
|
@@ -119,6 +119,13 @@ files:
|
|
119
119
|
- lib/no_brainer/document/store_in.rb
|
120
120
|
- lib/no_brainer/document/timestamps.rb
|
121
121
|
- lib/no_brainer/document/types.rb
|
122
|
+
- lib/no_brainer/document/types/boolean.rb
|
123
|
+
- lib/no_brainer/document/types/date.rb
|
124
|
+
- lib/no_brainer/document/types/float.rb
|
125
|
+
- lib/no_brainer/document/types/integer.rb
|
126
|
+
- lib/no_brainer/document/types/string.rb
|
127
|
+
- lib/no_brainer/document/types/symbol.rb
|
128
|
+
- lib/no_brainer/document/types/time.rb
|
122
129
|
- lib/no_brainer/document/uniqueness.rb
|
123
130
|
- lib/no_brainer/document/validation.rb
|
124
131
|
- lib/no_brainer/error.rb
|