volt 0.9.6 → 0.9.7.pre2
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/.gitignore +2 -1
- data/CHANGELOG.md +26 -0
- data/Gemfile +6 -1
- data/README.md +2 -0
- data/Rakefile +1 -0
- data/app/volt/models/active_volt_instance.rb +8 -6
- data/app/volt/models/user.rb +11 -2
- data/app/volt/models/volt_app_property.rb +8 -0
- data/app/volt/tasks/query_tasks.rb +23 -31
- data/app/volt/tasks/store_tasks.rb +2 -2
- data/app/volt/tasks/volt_admin_tasks.rb +24 -0
- data/docs/UPGRADE_GUIDE.md +6 -0
- data/lib/volt.rb +19 -12
- data/lib/volt/boot.rb +1 -0
- data/lib/volt/cli.rb +19 -8
- data/lib/volt/cli/console.rb +0 -1
- data/lib/volt/cli/generators.rb +14 -3
- data/lib/volt/cli/migrate.rb +26 -0
- data/lib/volt/config.rb +17 -4
- data/lib/volt/controllers/http_controller.rb +12 -0
- data/lib/volt/data_stores/base_adaptor_client.rb +2 -2
- data/lib/volt/data_stores/base_adaptor_server.rb +2 -0
- data/lib/volt/data_stores/data_store.rb +20 -14
- data/lib/volt/extra_core/class.rb +28 -14
- data/lib/volt/extra_core/hash.rb +5 -0
- data/lib/volt/extra_core/string.rb +3 -1
- data/lib/volt/helpers/time.rb +9 -43
- data/lib/volt/helpers/time/calculations.rb +204 -0
- data/lib/volt/helpers/time/distance.rb +63 -0
- data/lib/volt/helpers/time/duration.rb +71 -0
- data/lib/volt/helpers/time/local_calculations.rb +49 -0
- data/lib/volt/helpers/time/local_volt_time.rb +23 -0
- data/lib/volt/helpers/time/numeric.rb +59 -0
- data/lib/volt/helpers/time/volt_time.rb +170 -0
- data/lib/volt/models.rb +5 -0
- data/lib/volt/models/array_model.rb +33 -6
- data/lib/volt/models/associations.rb +146 -23
- data/lib/volt/models/buffer.rb +38 -41
- data/lib/volt/models/cursor.rb +15 -0
- data/lib/volt/models/errors.rb +11 -0
- data/lib/volt/models/field_helpers.rb +108 -68
- data/lib/volt/models/helpers/array_model.rb +4 -0
- data/lib/volt/models/helpers/base.rb +8 -1
- data/lib/volt/models/helpers/change_helpers.rb +31 -12
- data/lib/volt/models/helpers/defaults.rb +15 -0
- data/lib/volt/models/location.rb +20 -6
- data/lib/volt/models/migrations/migration.rb +23 -0
- data/lib/volt/models/migrations/migration_runner.rb +146 -0
- data/lib/volt/models/model.rb +38 -1
- data/lib/volt/models/permissions.rb +8 -1
- data/lib/volt/models/persistors/array_store.rb +87 -8
- data/lib/volt/models/persistors/base.rb +19 -0
- data/lib/volt/models/persistors/model_store.rb +1 -1
- data/lib/volt/models/persistors/page.rb +4 -1
- data/lib/volt/models/persistors/query/query_identifier.rb +102 -0
- data/lib/volt/models/persistors/query/query_listener.rb +57 -12
- data/lib/volt/models/root_models/root_models.rb +19 -0
- data/lib/volt/models/url.rb +11 -2
- data/lib/volt/models/validations/validations.rb +5 -2
- data/lib/volt/models/validators/type_validator.rb +11 -0
- data/lib/volt/models/validators/unique_validator.rb +2 -2
- data/lib/volt/page/bindings/attribute_binding.rb +23 -1
- data/lib/volt/page/targets/attribute_section.rb +7 -0
- data/lib/volt/page/targets/binding_document/component_node.rb +44 -18
- data/lib/volt/page/targets/binding_document/tag_node.rb +41 -0
- data/lib/volt/page/tasks.rb +16 -8
- data/lib/volt/queries/live_query.rb +109 -0
- data/lib/volt/queries/live_query_pool.rb +58 -0
- data/lib/volt/queries/live_subquery.rb +0 -0
- data/lib/volt/queries/query_association_splitter.rb +31 -0
- data/lib/volt/queries/query_diff.rb +100 -0
- data/lib/volt/queries/query_runner.rb +110 -0
- data/lib/volt/queries/query_subscription.rb +80 -0
- data/lib/volt/queries/query_subscription_pool.rb +37 -0
- data/lib/volt/reactive/eventable.rb +8 -0
- data/lib/volt/reactive/reactive_array.rb +0 -4
- data/lib/volt/router/routes.rb +81 -31
- data/lib/volt/server/message_bus/base_message_bus.rb +9 -3
- data/lib/volt/server/message_bus/peer_to_peer.rb +6 -6
- data/lib/volt/server/message_bus/peer_to_peer/server_tracker.rb +1 -1
- data/lib/volt/server/middleware/default_middleware_stack.rb +12 -8
- data/lib/volt/server/rack/component_paths.rb +31 -4
- data/lib/volt/server/rack/http_content_types.rb +62 -0
- data/lib/volt/server/rack/http_resource.rb +1 -1
- data/lib/volt/server/rack/index_files.rb +8 -1
- data/lib/volt/server/rack/opal_files.rb +16 -1
- data/lib/volt/server/rack/sprockets_helpers_setup.rb +32 -1
- data/lib/volt/server/socket_connection_handler.rb +16 -7
- data/lib/volt/server/template_handlers/sprockets_component_handler.rb +5 -3
- data/lib/volt/spec/capybara.rb +4 -3
- data/lib/volt/spec/setup.rb +5 -0
- data/lib/volt/tasks/dispatcher.rb +3 -1
- data/lib/volt/utils/data_transformer.rb +4 -4
- data/lib/volt/utils/ejson.rb +19 -6
- data/lib/volt/utils/promise_extensions.rb +1 -1
- data/lib/volt/utils/time_opal_patch.rb +749 -0
- data/lib/volt/utils/time_patch.rb +11 -4
- data/lib/volt/version.rb +1 -1
- data/lib/volt/volt/app.rb +19 -11
- data/lib/volt/volt/properties.rb +24 -0
- data/lib/volt/volt/server_setup/app.rb +30 -7
- data/lib/volt/volt/users.rb +15 -3
- data/spec/apps/kitchen_sink/Gemfile +5 -1
- data/spec/apps/kitchen_sink/app/main/config/routes.rb +1 -0
- data/spec/apps/kitchen_sink/app/main/controllers/save_controller.rb +1 -1
- data/spec/apps/kitchen_sink/app/main/controllers/server/simple_http_controller.rb +4 -0
- data/spec/apps/kitchen_sink/app/main/controllers/todos_controller.rb +4 -2
- data/spec/apps/kitchen_sink/app/main/models/post.rb +0 -1
- data/spec/apps/kitchen_sink/app/main/models/todo.rb +4 -0
- data/spec/apps/kitchen_sink/app/main/views/mailers/reset_password.html +10 -0
- data/spec/apps/kitchen_sink/app/main/views/todos/index.html +2 -0
- data/spec/apps/kitchen_sink/config/app.rb +2 -0
- data/spec/apps/migrations/config/db/migrations/1445111704_migration1.rb +7 -0
- data/spec/apps/migrations/config/db/migrations/1445113517_migration2.rb +7 -0
- data/spec/apps/migrations/config/db/migrations/1445115200_migration3.rb +7 -0
- data/spec/extra_core/class_spec.rb +10 -0
- data/spec/helpers/distance_spec.rb +35 -0
- data/spec/helpers/duration_spec.rb +160 -0
- data/spec/helpers/volt_time_spec.rb +275 -0
- data/spec/integration/callbacks_spec.rb +2 -1
- data/spec/integration/http_endpoints_spec.rb +4 -0
- data/spec/integration/save_spec.rb +1 -1
- data/spec/integration/todos_spec.rb +7 -5
- data/spec/models/array_model_spec.rb +17 -3
- data/spec/models/associations_spec.rb +48 -1
- data/spec/models/field_helpers_spec.rb +7 -3
- data/spec/models/migrations/migration_runner_spec.rb +69 -0
- data/spec/models/model_spec.rb +42 -8
- data/spec/models/permissions_spec.rb +20 -8
- data/spec/models/persistors/array_store_spec.rb +18 -0
- data/spec/models/persistors/page_spec.rb +15 -10
- data/spec/models/persistors/store_spec.rb +13 -3
- data/spec/models/url_spec.rb +4 -3
- data/spec/models/user_spec.rb +6 -3
- data/spec/models/user_validation_spec.rb +3 -3
- data/spec/models/validations_spec.rb +4 -0
- data/spec/models/validators/block_validations_spec.rb +9 -5
- data/spec/models/validators/email_validator_spec.rb +2 -0
- data/spec/models/validators/lifecycle_callbacks_spec.rb +86 -0
- data/spec/models/validators/unique_validator_spec.rb +1 -0
- data/spec/page/path_string_renderer_spec.rb +5 -0
- data/spec/queries/live_query_spec.rb +16 -0
- data/spec/queries/query_association_splitter_spec.rb +14 -0
- data/spec/queries/query_diff_spec.rb +132 -0
- data/spec/queries/query_identifier_spec.rb +98 -0
- data/spec/queries/query_runner_spec.rb +63 -0
- data/spec/queries/query_tracker_spec.rb +141 -0
- data/spec/router/routes_spec.rb +52 -21
- data/spec/server/middleware/rack_content_types_spec.rb +78 -0
- data/spec/server/rack/asset_files_spec.rb +38 -30
- data/spec/spec_helper.rb +8 -0
- data/spec/utils/ejson_spec.rb +9 -8
- data/spec/utils/ejson_volt_time_spec.rb +65 -0
- data/templates/migration/migration.rb.tt +9 -0
- data/templates/newgem/gitignore.tt +1 -0
- data/templates/project/Gemfile.tt +19 -2
- data/templates/project/README.md.tt +6 -1
- data/templates/project/app/main/config/dependencies.rb +6 -0
- data/templates/project/config/app.rb.tt +18 -4
- data/volt.gemspec +2 -2
- metadata +73 -16
- data/app/volt/tasks/live_query/live_query_pool.rb +0 -48
- data/app/volt/tasks/live_query/query_tracker.rb +0 -92
- data/spec/tasks/live_query_spec.rb +0 -18
- data/spec/tasks/query_tasks.rb +0 -7
- data/spec/tasks/query_tracker_spec.rb +0 -145
|
@@ -156,7 +156,7 @@ module Volt
|
|
|
156
156
|
if can_delete
|
|
157
157
|
super(val)
|
|
158
158
|
else
|
|
159
|
-
|
|
159
|
+
Promise.new.reject("permissions did not allow delete for #{val.inspect}.")
|
|
160
160
|
end
|
|
161
161
|
end
|
|
162
162
|
end
|
|
@@ -178,12 +178,28 @@ module Volt
|
|
|
178
178
|
|
|
179
179
|
# Return the first item in the collection, or create one if one does not
|
|
180
180
|
# exist yet.
|
|
181
|
-
def first_or_create
|
|
181
|
+
def first_or_create(attrs={})
|
|
182
182
|
first.then do |item|
|
|
183
183
|
if item
|
|
184
184
|
item
|
|
185
185
|
else
|
|
186
|
-
create
|
|
186
|
+
create(attrs)
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
# Finds a model maching query and calls .update passing in attrs. If the
|
|
192
|
+
# model is not found, it creates the model with attrs merged into query.
|
|
193
|
+
def update_or_create(query, attrs={})
|
|
194
|
+
where(query).first.then do |item|
|
|
195
|
+
if item
|
|
196
|
+
if attrs.size > 0
|
|
197
|
+
item.update(attrs)
|
|
198
|
+
else
|
|
199
|
+
item
|
|
200
|
+
end
|
|
201
|
+
else
|
|
202
|
+
create(query.merge(attrs))
|
|
187
203
|
end
|
|
188
204
|
end
|
|
189
205
|
end
|
|
@@ -241,10 +257,13 @@ module Volt
|
|
|
241
257
|
def new_model(*args)
|
|
242
258
|
Volt::Model.class_at_path(options[:path]).new(*args)
|
|
243
259
|
end
|
|
260
|
+
|
|
244
261
|
alias_method :new, :new_model
|
|
245
262
|
|
|
246
263
|
def new_array_model(*args)
|
|
247
|
-
Volt::ArrayModel.class_at_path(options[:path])
|
|
264
|
+
klass = Volt::ArrayModel.class_at_path(options[:path])
|
|
265
|
+
|
|
266
|
+
klass.new(*args)
|
|
248
267
|
end
|
|
249
268
|
|
|
250
269
|
# Convert the model to an array all of the way down
|
|
@@ -309,10 +328,15 @@ module Volt
|
|
|
309
328
|
|
|
310
329
|
alias_method :reactive_count, :count
|
|
311
330
|
def count(&block)
|
|
312
|
-
|
|
331
|
+
if !block && persistor.is_a?(Persistors::ArrayStore)
|
|
332
|
+
@persistor.resolved_value
|
|
333
|
+
else
|
|
334
|
+
all.reactive_count(&block)
|
|
335
|
+
end
|
|
313
336
|
end
|
|
314
337
|
|
|
315
338
|
private
|
|
339
|
+
|
|
316
340
|
# called form <<, append, and create. If a hash is passed in, it converts
|
|
317
341
|
# it to a model. Then it takes the model and inserts it into the ArrayModel
|
|
318
342
|
# then persists it.
|
|
@@ -328,13 +352,15 @@ module Volt
|
|
|
328
352
|
model = wrap_values([model]).first
|
|
329
353
|
end
|
|
330
354
|
|
|
331
|
-
|
|
332
355
|
if model.is_a?(Model)
|
|
333
356
|
promise = model.can_create?.then do |can_create|
|
|
334
357
|
unless can_create
|
|
335
358
|
fail "permissions did not allow create for #{model.inspect}"
|
|
336
359
|
end
|
|
337
360
|
end.then do
|
|
361
|
+
if (assoc = options[:associate])
|
|
362
|
+
parent.associate(assoc, model)
|
|
363
|
+
end
|
|
338
364
|
|
|
339
365
|
# Add it to the array and trigger any watches or on events.
|
|
340
366
|
reactive_array_append(model)
|
|
@@ -345,6 +371,7 @@ module Volt
|
|
|
345
371
|
# Validate and save
|
|
346
372
|
model.run_changed
|
|
347
373
|
end.then do
|
|
374
|
+
|
|
348
375
|
# Mark the model as not new
|
|
349
376
|
model.instance_variable_set('@new', false)
|
|
350
377
|
|
|
@@ -2,12 +2,12 @@ module Volt
|
|
|
2
2
|
module Associations
|
|
3
3
|
module ClassMethods
|
|
4
4
|
def belongs_to(method_name, options = {})
|
|
5
|
-
collection
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
collection, foreign_key, local_key = assoc_parts_and_track(
|
|
6
|
+
method_name, options, :belongs_to
|
|
7
|
+
)
|
|
8
8
|
|
|
9
9
|
# Add a field for the association_id
|
|
10
|
-
field(local_key)
|
|
10
|
+
field(local_key, String)
|
|
11
11
|
|
|
12
12
|
# getter
|
|
13
13
|
define_method(method_name) do
|
|
@@ -20,43 +20,76 @@ module Volt
|
|
|
20
20
|
end
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
+
# setter
|
|
23
24
|
define_method(:"#{method_name}=") do |obj|
|
|
24
|
-
|
|
25
|
+
# Associatie the obj's foreign key
|
|
26
|
+
obj.set(foreign_key, id)
|
|
25
27
|
|
|
26
|
-
#
|
|
27
|
-
set(
|
|
28
|
+
# Associate on the method name
|
|
29
|
+
set(method_name, obj)
|
|
28
30
|
end
|
|
29
31
|
end
|
|
30
32
|
|
|
31
33
|
def has_many(method_name, options = {})
|
|
32
|
-
|
|
34
|
+
mmethod_name = method_name.to_sym
|
|
35
|
+
if method_name.singular?
|
|
36
|
+
raise NameError, "has_many takes a plural association name"
|
|
37
|
+
end
|
|
33
38
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
39
|
+
collection, foreign_key, local_key = assoc_parts_and_track(
|
|
40
|
+
method_name, options, :has_many
|
|
41
|
+
)
|
|
37
42
|
|
|
38
43
|
define_method(method_name) do
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
# the right parent and path.
|
|
44
|
-
new_path = array_model.options[:path]
|
|
45
|
-
# Assign path and parent
|
|
46
|
-
array_model.path = self.path + new_path
|
|
47
|
-
array_model.parent = self
|
|
44
|
+
# If the association is already in attributes, return
|
|
45
|
+
if attributes[method_name]
|
|
46
|
+
get(method_name)
|
|
47
|
+
else
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
# Get the
|
|
50
|
+
lookup_key = get(local_key)
|
|
51
|
+
array_model = root.get(collection).where(foreign_key => lookup_key)
|
|
52
|
+
|
|
53
|
+
# Since we are coming off of the root collection, we need to setup
|
|
54
|
+
# the right parent and path.
|
|
55
|
+
new_path = array_model.options[:path]
|
|
56
|
+
# Assign path and parent
|
|
57
|
+
array_model.path = self.path + new_path
|
|
58
|
+
array_model.parent = self
|
|
59
|
+
|
|
60
|
+
# Store the associated query, don't track changes, since the
|
|
61
|
+
# association is persisted via _id fields.
|
|
62
|
+
Volt.run_in_mode(:no_change_tracking) do
|
|
63
|
+
set(method_name, array_model)
|
|
64
|
+
end
|
|
65
|
+
array_model
|
|
66
|
+
end
|
|
50
67
|
end
|
|
68
|
+
|
|
69
|
+
# setter
|
|
70
|
+
# define_method(:"#{method_name}=") do |val|
|
|
71
|
+
# assoc = get(method_name)
|
|
72
|
+
|
|
73
|
+
# # Set the foreign_key on the has_many model to the local_key of the
|
|
74
|
+
# # current model.
|
|
75
|
+
# assoc.append(val).then do |model|
|
|
76
|
+
# model.set(foreign_key, get(local_key))
|
|
77
|
+
# end
|
|
78
|
+
# end
|
|
51
79
|
end
|
|
52
80
|
|
|
53
81
|
# has_one creates a method on the Volt::Model that returns a promise
|
|
54
82
|
# to get the associated model.
|
|
55
|
-
def has_one(method_name)
|
|
83
|
+
def has_one(method_name, options={})
|
|
56
84
|
if method_name.plural?
|
|
57
85
|
raise NameError, "has_one takes a singluar association name"
|
|
58
86
|
end
|
|
59
87
|
|
|
88
|
+
collection, foreign_key, local_key = assoc_parts_and_track(
|
|
89
|
+
method_name, options, :has_one
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
|
|
60
93
|
define_method(method_name) do
|
|
61
94
|
association_with_root_model('has_one') do |root|
|
|
62
95
|
key = self.class.to_s.underscore + '_id'
|
|
@@ -64,10 +97,100 @@ module Volt
|
|
|
64
97
|
end
|
|
65
98
|
end
|
|
66
99
|
end
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def assoc_parts(method_name, options, type)
|
|
103
|
+
collection = options.fetch(:collection, method_name).pluralize
|
|
104
|
+
|
|
105
|
+
default_foreign_key = case type
|
|
106
|
+
when :has_many, :has_one
|
|
107
|
+
:"#{to_s.underscore.singularize}_id"
|
|
108
|
+
else
|
|
109
|
+
:id
|
|
110
|
+
end
|
|
111
|
+
foreign_key = options.fetch(:foreign_key, default_foreign_key)
|
|
112
|
+
|
|
113
|
+
default_local_key = case type
|
|
114
|
+
when :belongs_to
|
|
115
|
+
:"#{method_name}_id"
|
|
116
|
+
else
|
|
117
|
+
:id
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
local_key = options.fetch(:local_key, default_local_key)
|
|
121
|
+
|
|
122
|
+
return collection, foreign_key, local_key
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
private
|
|
126
|
+
def check_name_in_use(name)
|
|
127
|
+
if self.fields[name]
|
|
128
|
+
type = 'A field'
|
|
129
|
+
elsif self.associations[name]
|
|
130
|
+
type = 'An association'
|
|
131
|
+
else
|
|
132
|
+
type = nil
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
if type
|
|
136
|
+
raise "#{type} is already defined for `#{name}` on `#{to_s}`"
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# Checks to make sure the association isn't in use, then generates the
|
|
141
|
+
# collection, foreign_key, and local_key's based on the type and options.
|
|
142
|
+
# Then tracks the association data on the model class.
|
|
143
|
+
def assoc_parts_and_track(method_name, options, type)
|
|
144
|
+
method_name = method_name.to_sym
|
|
145
|
+
check_name_in_use(method_name)
|
|
146
|
+
|
|
147
|
+
collection, foreign_key, local_key = assoc_parts(method_name, options,
|
|
148
|
+
type)
|
|
149
|
+
|
|
150
|
+
# Track the association
|
|
151
|
+
self.associations[method_name] = {
|
|
152
|
+
type: type,
|
|
153
|
+
to_many: type == :has_many,
|
|
154
|
+
collection: collection,
|
|
155
|
+
foreign_key: foreign_key,
|
|
156
|
+
local_key: local_key
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return collection, foreign_key, local_key
|
|
160
|
+
end
|
|
67
161
|
end
|
|
68
162
|
|
|
69
163
|
def self.included(base)
|
|
70
164
|
base.send :extend, ClassMethods
|
|
165
|
+
base.class_attribute :associations
|
|
166
|
+
base.associations = {}
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# Associate takes an association name, and a model and changes the
|
|
170
|
+
# association field (the foreign_key for has_one, has_many, or the local_key
|
|
171
|
+
# for belongs_to). This works for both explicit (has_many, has_one,
|
|
172
|
+
# belongs_to) associations, and implicit (._items)
|
|
173
|
+
def associate(method_name, model)
|
|
174
|
+
assoc_data = self.class.associations[method_name]
|
|
175
|
+
|
|
176
|
+
if assoc_data
|
|
177
|
+
# Extract from association data
|
|
178
|
+
collection, foreign_key, local_key, type =
|
|
179
|
+
assoc_data.mfetch(:collection, :foreign_key, :local_key, :type)
|
|
180
|
+
else
|
|
181
|
+
# Association is implicit, generate instead
|
|
182
|
+
type = :has_many
|
|
183
|
+
collection, foreign_key, local_key =
|
|
184
|
+
self.class.assoc_parts(method_name, {}, type)
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
case type
|
|
188
|
+
when :has_many, :has_one
|
|
189
|
+
model.set(foreign_key, get(local_key))
|
|
190
|
+
else
|
|
191
|
+
# belongs_to
|
|
192
|
+
set(local_key, get(foreign_key))
|
|
193
|
+
end
|
|
71
194
|
end
|
|
72
195
|
|
|
73
196
|
private
|
|
@@ -79,7 +202,7 @@ module Volt
|
|
|
79
202
|
|
|
80
203
|
# Check if we are on the store collection
|
|
81
204
|
if persistor.is_a?(Volt::Persistors::ModelStore) ||
|
|
82
|
-
|
|
205
|
+
persistor.is_a?(Volt::Persistors::Page)
|
|
83
206
|
# Get the root node
|
|
84
207
|
root = persistor.try(:root_model)
|
|
85
208
|
|
data/lib/volt/models/buffer.rb
CHANGED
|
@@ -10,60 +10,57 @@ module Volt
|
|
|
10
10
|
# TODO: this shouldn't need to be run, but if no attributes are assigned, then
|
|
11
11
|
# if needs to be run. Maybe there's a better way to handle it.
|
|
12
12
|
validate!.then do
|
|
13
|
-
# Get errors from validate
|
|
14
|
-
errors = self.errors.to_h
|
|
15
|
-
|
|
16
13
|
result = nil
|
|
17
14
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
if save_to
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
result = promise.then do |new_model|
|
|
31
|
-
# The main model saved, so mark the buffer as not new
|
|
32
|
-
@new = false
|
|
15
|
+
# cache save_to in a local
|
|
16
|
+
save_to = self.save_to
|
|
17
|
+
if save_to
|
|
18
|
+
if save_to.is_a?(ArrayModel)
|
|
19
|
+
# Add to the collection
|
|
20
|
+
promise = save_to.create(attributes)
|
|
21
|
+
else
|
|
22
|
+
# We have a saved model
|
|
23
|
+
promise = save_to.assign_attributes(attributes, false, true)
|
|
24
|
+
end
|
|
33
25
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
26
|
+
result = promise.then do |new_model|
|
|
27
|
+
# The main model saved, so mark the buffer as not new
|
|
28
|
+
@new = false
|
|
37
29
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
30
|
+
if new_model
|
|
31
|
+
# Mark the model as loaded
|
|
32
|
+
new_model.change_state_to(:loaded_state, :loaded)
|
|
41
33
|
|
|
42
|
-
#
|
|
43
|
-
|
|
34
|
+
# Set the buffer's id to track the main model's id
|
|
35
|
+
self.save_to = new_model
|
|
36
|
+
end
|
|
44
37
|
|
|
45
|
-
|
|
46
|
-
|
|
38
|
+
# Copy attributes back from save_to model
|
|
39
|
+
@attributes = new_model.attributes
|
|
47
40
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
if errors.is_a?(Hash)
|
|
51
|
-
server_errors.replace(errors)
|
|
41
|
+
# Remove tracked changes
|
|
42
|
+
clear_tracked_changes!
|
|
52
43
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
44
|
+
new_model
|
|
45
|
+
end.fail do |errors|
|
|
46
|
+
if errors.is_a?(Hash)
|
|
47
|
+
server_errors.replace(errors)
|
|
56
48
|
|
|
57
|
-
|
|
49
|
+
# Merge the server errors into the main errors
|
|
50
|
+
self.errors.merge!(server_errors.to_h)
|
|
58
51
|
end
|
|
59
|
-
|
|
60
|
-
|
|
52
|
+
|
|
53
|
+
promise_for_errors(errors)
|
|
61
54
|
end
|
|
55
|
+
|
|
56
|
+
result
|
|
62
57
|
else
|
|
63
|
-
|
|
64
|
-
result = promise_for_errors(errors)
|
|
58
|
+
fail 'Model is not a buffer, can not be saved, modifications should be persisted as they are made.'
|
|
65
59
|
end
|
|
66
|
-
|
|
60
|
+
end.fail do |errors|
|
|
61
|
+
# Some errors, mark all fields
|
|
62
|
+
promise_for_errors(errors)
|
|
63
|
+
end.then do |result|
|
|
67
64
|
# If passed a block, call then on it with the block.
|
|
68
65
|
result = result.then(&block) if block
|
|
69
66
|
|
data/lib/volt/models/cursor.rb
CHANGED
|
@@ -2,5 +2,20 @@ require 'volt/models/array_model'
|
|
|
2
2
|
|
|
3
3
|
module Volt
|
|
4
4
|
class Cursor < ArrayModel
|
|
5
|
+
# Some cursors return a value instead of an ArrayModel, in this case, we
|
|
6
|
+
# store the array in the ArrayModel (so we can reuse ArrayModel's path)
|
|
7
|
+
# TODO: should abstract this into a base class.
|
|
8
|
+
def value=(val)
|
|
9
|
+
@array = val
|
|
10
|
+
@has_value = true
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def value
|
|
14
|
+
@array
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def has_value?
|
|
18
|
+
@has_value
|
|
19
|
+
end
|
|
5
20
|
end
|
|
6
21
|
end
|
data/lib/volt/models/errors.rb
CHANGED