volt 0.9.3.pre1 → 0.9.3.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/.ruby-version +1 -1
- data/CHANGELOG.md +15 -1
- data/Gemfile +30 -3
- data/README.md +7 -2
- data/Rakefile +17 -0
- data/app/volt/models/user.rb +1 -1
- data/app/volt/tasks/live_query/live_query.rb +0 -1
- data/app/volt/tasks/live_query/live_query_pool.rb +8 -2
- data/app/volt/tasks/live_query/query_tracker.rb +2 -2
- data/app/volt/tasks/query_tasks.rb +10 -27
- data/app/volt/tasks/store_tasks.rb +6 -5
- data/app/volt/tasks/user_tasks.rb +2 -2
- data/docs/UPGRADE_GUIDE.md +14 -0
- data/lib/volt/boot.rb +1 -0
- data/lib/volt/cli/asset_compile.rb +25 -7
- data/lib/volt/cli/console.rb +6 -5
- data/lib/volt/cli/generate.rb +2 -2
- data/lib/volt/config.rb +2 -1
- data/lib/volt/controllers/http_controller.rb +4 -3
- data/lib/volt/controllers/model_controller.rb +41 -19
- data/lib/volt/controllers/template_helpers.rb +19 -0
- data/lib/volt/extra_core/array.rb +6 -0
- data/lib/volt/extra_core/hash.rb +8 -26
- data/lib/volt/extra_core/string.rb +1 -1
- data/lib/volt/models/array_model.rb +12 -4
- data/lib/volt/models/associations.rb +11 -13
- data/lib/volt/models/buffer.rb +1 -1
- data/lib/volt/models/model.rb +22 -13
- data/lib/volt/models/model_helpers/model_change_helpers.rb +0 -1
- data/lib/volt/models/model_helpers/model_helpers.rb +11 -0
- data/lib/volt/models/permissions.rb +9 -12
- data/lib/volt/models/persistors/array_store.rb +7 -7
- data/lib/volt/models/persistors/base.rb +9 -0
- data/lib/volt/models/persistors/cookies.rb +0 -4
- data/lib/volt/models/persistors/flash.rb +0 -4
- data/lib/volt/models/persistors/local_store.rb +0 -4
- data/lib/volt/models/persistors/model_store.rb +13 -21
- data/lib/volt/models/persistors/page.rb +22 -0
- data/lib/volt/models/persistors/params.rb +0 -4
- data/lib/volt/models/persistors/query/query_listener.rb +3 -2
- data/lib/volt/models/url.rb +2 -2
- data/lib/volt/models/validators/unique_validator.rb +1 -1
- data/lib/volt/models.rb +1 -0
- data/lib/volt/page/bindings/attribute_binding.rb +2 -2
- data/lib/volt/page/bindings/base_binding.rb +7 -3
- data/lib/volt/page/bindings/bindings.rb +9 -0
- data/lib/volt/page/bindings/content_binding.rb +2 -2
- data/lib/volt/page/bindings/each_binding.rb +16 -12
- data/lib/volt/page/bindings/event_binding.rb +4 -4
- data/lib/volt/page/bindings/if_binding.rb +3 -3
- data/lib/volt/page/bindings/view_binding.rb +4 -4
- data/lib/volt/page/bindings/yield_binding.rb +3 -3
- data/lib/volt/page/channel.rb +6 -0
- data/lib/volt/page/channel_stub.rb +1 -1
- data/lib/volt/page/page.rb +20 -54
- data/lib/volt/page/path_string_renderer.rb +5 -6
- data/lib/volt/page/string_template_renderer.rb +2 -2
- data/lib/volt/page/targets/attribute_section.rb +47 -0
- data/lib/volt/page/targets/base_section.rb +5 -5
- data/lib/volt/page/targets/binding_document/component_node.rb +6 -1
- data/lib/volt/page/template_renderer.rb +4 -4
- data/lib/volt/reactive/computation.rb +32 -3
- data/lib/volt/router/routes.rb +5 -5
- data/lib/volt/server/component_templates.rb +30 -2
- data/lib/volt/server/forking_server.rb +2 -2
- data/lib/volt/server/message_bus/base_message_bus.rb +52 -0
- data/lib/volt/server/message_bus/message_encoder.rb +64 -0
- data/lib/volt/server/message_bus/peer_to_peer/peer_connection.rb +186 -0
- data/lib/volt/server/message_bus/peer_to_peer/peer_server.rb +78 -0
- data/lib/volt/server/message_bus/peer_to_peer/server_tracker.rb +57 -0
- data/lib/volt/server/message_bus/peer_to_peer/socket_with_timeout.rb +27 -0
- data/lib/volt/server/message_bus/peer_to_peer.rb +198 -0
- data/lib/volt/server/message_bus/redis.rb +1 -0
- data/lib/volt/server/rack/asset_files.rb +2 -2
- data/lib/volt/server/rack/component_paths.rb +1 -1
- data/lib/volt/server/rack/http_resource.rb +3 -2
- data/lib/volt/server/rack/opal_files.rb +6 -9
- data/lib/volt/server/websocket/websocket_handler.rb +0 -3
- data/lib/volt/server.rb +5 -3
- data/lib/volt/spec/setup.rb +11 -12
- data/lib/volt/tasks/dispatcher.rb +8 -12
- data/lib/volt/tasks/task_handler.rb +3 -2
- data/lib/volt/utils/csso_patch.rb +24 -0
- data/lib/volt/utils/promise_patch.rb +2 -0
- data/lib/volt/version.rb +1 -1
- data/lib/volt/volt/app.rb +73 -36
- data/lib/volt/volt/server_setup/app.rb +81 -0
- data/lib/volt.rb +22 -1
- data/spec/apps/kitchen_sink/Gemfile +1 -1
- data/spec/controllers/http_controller_spec.rb +5 -3
- data/spec/controllers/model_controller_spec.rb +2 -2
- data/spec/extra_core/hash_spec.rb +9 -0
- data/spec/integration/list_spec.rb +3 -3
- data/spec/models/associations_spec.rb +10 -2
- data/spec/models/dirty_spec.rb +7 -7
- data/spec/models/model_spec.rb +10 -2
- data/spec/models/permissions_spec.rb +9 -0
- data/spec/models/persistors/store_spec.rb +8 -0
- data/spec/page/bindings/content_binding_spec.rb +6 -2
- data/spec/page/bindings/each_binding_spec.rb +59 -0
- data/spec/page/bindings/if_binding_spec.rb +57 -0
- data/spec/page/path_string_renderer_spec.rb +5 -5
- data/spec/reactive/computation_spec.rb +65 -1
- data/spec/router/routes_spec.rb +1 -1
- data/spec/server/html_parser/sandlebars_parser_spec.rb +12 -22
- data/spec/server/message_bus/message_encoder_spec.rb +49 -0
- data/spec/server/message_bus/peer_to_peer/peer_connection_spec.rb +108 -0
- data/spec/server/message_bus/peer_to_peer/peer_server_spec.rb +66 -0
- data/spec/server/message_bus/peer_to_peer/socket_with_timeout_spec.rb +11 -0
- data/spec/server/message_bus/peer_to_peer_spec.rb +11 -0
- data/spec/server/rack/asset_files_spec.rb +1 -1
- data/spec/server/rack/http_resource_spec.rb +4 -4
- data/spec/spec_helper.rb +16 -3
- data/spec/tasks/dispatcher_spec.rb +17 -5
- data/spec/tasks/live_query_spec.rb +1 -1
- data/spec/tasks/query_tracker_spec.rb +34 -34
- data/spec/tasks/user_tasks_spec.rb +4 -2
- data/templates/project/Gemfile.tt +14 -3
- data/templates/project/config/app.rb.tt +27 -2
- data/volt.gemspec +3 -8
- metadata +32 -101
- data/docs/FAQ.md +0 -7
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module Volt
|
|
2
|
+
module TemplateHelpders
|
|
3
|
+
module ClassMethods
|
|
4
|
+
def template(name, template, bindings)
|
|
5
|
+
@templates[name] = { 'html' => template, 'bindings' => bindings }
|
|
6
|
+
end
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def self.included(base)
|
|
10
|
+
# Setup blank templates class variable
|
|
11
|
+
base.class_attribute :__templates
|
|
12
|
+
base.__templates = {}
|
|
13
|
+
|
|
14
|
+
base.send :extend, ClassMethods
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
end
|
data/lib/volt/extra_core/hash.rb
CHANGED
|
@@ -1,26 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
#
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
# end
|
|
10
|
-
#
|
|
11
|
-
# def key?(key)
|
|
12
|
-
# super(convert_key(key))
|
|
13
|
-
# end
|
|
14
|
-
#
|
|
15
|
-
# def fetch(key, *args)
|
|
16
|
-
# super(convert_key(key), *args)
|
|
17
|
-
# end
|
|
18
|
-
#
|
|
19
|
-
# private
|
|
20
|
-
#
|
|
21
|
-
# # Converts all keys to symbols for assignments
|
|
22
|
-
# def convert_key(key)
|
|
23
|
-
# key.is_a?(String) ? key : key.to_sym
|
|
24
|
-
# end
|
|
25
|
-
# end
|
|
26
|
-
# end
|
|
1
|
+
class Hash
|
|
2
|
+
# Returns a hash excluding the keys passed in.
|
|
3
|
+
def without(*keys)
|
|
4
|
+
reject do |key, value|
|
|
5
|
+
keys.include?(key)
|
|
6
|
+
end
|
|
7
|
+
end
|
|
8
|
+
end
|
|
@@ -7,7 +7,7 @@ class String
|
|
|
7
7
|
# Turns a string into the camel case version. If it is already camel case, it should
|
|
8
8
|
# return the same string.
|
|
9
9
|
def camelize(first_letter = :upper)
|
|
10
|
-
new_str = gsub(/_[a-z]/) { |a| a[1].upcase }
|
|
10
|
+
new_str = gsub(/[_\-][a-z]/) { |a| a[1].upcase }
|
|
11
11
|
new_str = new_str[0].capitalize + new_str[1..-1] if first_letter == :upper
|
|
12
12
|
|
|
13
13
|
new_str
|
|
@@ -67,7 +67,7 @@ module Volt
|
|
|
67
67
|
# Make sure it gets wrapped
|
|
68
68
|
def <<(model)
|
|
69
69
|
if model.is_a?(Model)
|
|
70
|
-
# Set the new path
|
|
70
|
+
# Set the new path and the persistor.
|
|
71
71
|
model.options = @options.merge(path: @options[:path] + [:[]])
|
|
72
72
|
else
|
|
73
73
|
model = wrap_values([model]).first
|
|
@@ -77,12 +77,17 @@ module Volt
|
|
|
77
77
|
fail "permissions did not allow create for #{model.inspect}"
|
|
78
78
|
end
|
|
79
79
|
|
|
80
|
+
# Add it to the array and trigger any watches or on events.
|
|
80
81
|
super(model)
|
|
81
82
|
|
|
82
83
|
if @persistor
|
|
83
84
|
promise = @persistor.added(model, @array.size - 1)
|
|
84
85
|
if promise && promise.is_a?(Promise)
|
|
85
86
|
return promise.then do
|
|
87
|
+
|
|
88
|
+
# Mark the model as not new
|
|
89
|
+
model.instance_variable_set('@new', false)
|
|
90
|
+
|
|
86
91
|
# Mark the model as loaded
|
|
87
92
|
model.change_state_to(:loaded_state, :loaded)
|
|
88
93
|
|
|
@@ -191,8 +196,9 @@ module Volt
|
|
|
191
196
|
Computation.run_without_tracking do
|
|
192
197
|
# Track on size
|
|
193
198
|
@size_dep.depend
|
|
194
|
-
str = "#<#{self.class}
|
|
195
|
-
str += "
|
|
199
|
+
str = "#<#{self.class}"
|
|
200
|
+
# str += " state:#{loaded_state}"
|
|
201
|
+
# str += " path:#{path.join('.')}" if path
|
|
196
202
|
# str += " persistor:#{persistor.inspect}" if persistor
|
|
197
203
|
str += " #{@array.inspect}>"
|
|
198
204
|
|
|
@@ -214,7 +220,9 @@ module Volt
|
|
|
214
220
|
|
|
215
221
|
# Takes the persistor if there is one and
|
|
216
222
|
def setup_persistor(persistor)
|
|
217
|
-
|
|
223
|
+
# Use page as the default persistor
|
|
224
|
+
persistor ||= Persistors::Page
|
|
225
|
+
@persistor = persistor.new(self)
|
|
218
226
|
end
|
|
219
227
|
end
|
|
220
228
|
end
|
|
@@ -2,28 +2,25 @@ module Volt
|
|
|
2
2
|
module Associations
|
|
3
3
|
module ClassMethods
|
|
4
4
|
def belongs_to(method_name, key_name = nil)
|
|
5
|
+
key_name ||= "#{method_name}_id"
|
|
6
|
+
# Add a field for the association_id
|
|
7
|
+
field(key_name)
|
|
8
|
+
|
|
5
9
|
# getter
|
|
6
10
|
define_method(method_name) do
|
|
7
11
|
association_with_root_model('belongs_to') do |root|
|
|
8
12
|
# Lookup the associated model id
|
|
9
|
-
lookup_key =
|
|
13
|
+
lookup_key = get(key_name)
|
|
10
14
|
|
|
11
15
|
# Return a promise for the belongs_to
|
|
12
|
-
root.
|
|
16
|
+
root.get(method_name.pluralize).where(id: lookup_key).fetch_first
|
|
13
17
|
end
|
|
14
18
|
end
|
|
15
19
|
end
|
|
16
20
|
|
|
17
21
|
def has_many(method_name, remote_key_name = nil)
|
|
18
22
|
define_method(method_name) do
|
|
19
|
-
|
|
20
|
-
id = _id
|
|
21
|
-
|
|
22
|
-
# The key will be "{this class name}_id"
|
|
23
|
-
remote_key_name ||= :"#{path[-2].singularize}_id"
|
|
24
|
-
|
|
25
|
-
root.send(:"_#{method_name.pluralize}!").where(remote_key_name => id)
|
|
26
|
-
end
|
|
23
|
+
get(method_name.pluralize, true)
|
|
27
24
|
end
|
|
28
25
|
end
|
|
29
26
|
end
|
|
@@ -37,10 +34,11 @@ module Volt
|
|
|
37
34
|
# Currently the has_many and belongs_to associations only work on the store collection,
|
|
38
35
|
# this method checks to make sure we are on store and returns the root reference to it.
|
|
39
36
|
def association_with_root_model(method_name)
|
|
40
|
-
persistor = self.persistor || (respond_to?(:save_to) && save_to.persistor)
|
|
37
|
+
persistor = self.persistor || (respond_to?(:save_to) && save_to && save_to.persistor)
|
|
41
38
|
|
|
42
39
|
# Check if we are on the store collection
|
|
43
|
-
if persistor.is_a?(Volt::Persistors::ModelStore)
|
|
40
|
+
if persistor.is_a?(Volt::Persistors::ModelStore) ||
|
|
41
|
+
persistor.is_a?(Volt::Persistors::Page)
|
|
44
42
|
# Get the root node
|
|
45
43
|
root = persistor.try(:root_model)
|
|
46
44
|
|
|
@@ -48,7 +46,7 @@ module Volt
|
|
|
48
46
|
yield(root)
|
|
49
47
|
else
|
|
50
48
|
# raise an error about the method not being supported on this collection
|
|
51
|
-
fail "#{method_name} currently only works on the store collection (support for other collections coming soon)"
|
|
49
|
+
fail "#{method_name} currently only works on the store and page collection (support for other collections coming soon)"
|
|
52
50
|
end
|
|
53
51
|
end
|
|
54
52
|
end
|
data/lib/volt/models/buffer.rb
CHANGED
data/lib/volt/models/model.rb
CHANGED
|
@@ -104,13 +104,16 @@ module Volt
|
|
|
104
104
|
super
|
|
105
105
|
end
|
|
106
106
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
107
|
+
def id
|
|
108
|
+
get(:id)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def id=(val)
|
|
112
|
+
set(:id, val)
|
|
110
113
|
end
|
|
111
114
|
|
|
112
|
-
def _id
|
|
113
|
-
|
|
115
|
+
def _id
|
|
116
|
+
raise "Accessing _id has been deprecated in favor of id"
|
|
114
117
|
end
|
|
115
118
|
|
|
116
119
|
# Return true if the model hasn't been saved yet
|
|
@@ -302,14 +305,14 @@ module Volt
|
|
|
302
305
|
|
|
303
306
|
def inspect
|
|
304
307
|
Computation.run_without_tracking do
|
|
305
|
-
str = "<#{self.class}
|
|
308
|
+
str = "<#{self.class}"
|
|
306
309
|
|
|
307
310
|
# Get path, loaded_state, and persistor, but cache in local var
|
|
308
|
-
path = self.path
|
|
309
|
-
str += " path:#{path}" if path
|
|
311
|
+
# path = self.path
|
|
312
|
+
# str += " path:#{path}" if path
|
|
310
313
|
|
|
311
|
-
loaded_state = self.loaded_state
|
|
312
|
-
str += " state:#{loaded_state}" if loaded_state
|
|
314
|
+
# loaded_state = self.loaded_state
|
|
315
|
+
# str += " state:#{loaded_state}" if loaded_state
|
|
313
316
|
|
|
314
317
|
persistor = self.persistor
|
|
315
318
|
# str += " persistor:#{persistor.inspect}" if persistor
|
|
@@ -339,7 +342,6 @@ module Volt
|
|
|
339
342
|
|
|
340
343
|
private
|
|
341
344
|
def run_initial_setup(initial_setup)
|
|
342
|
-
|
|
343
345
|
# Save the changes
|
|
344
346
|
if initial_setup
|
|
345
347
|
# Run initial validation
|
|
@@ -372,7 +374,9 @@ module Volt
|
|
|
372
374
|
|
|
373
375
|
# Takes the persistor if there is one and
|
|
374
376
|
def setup_persistor(persistor)
|
|
375
|
-
|
|
377
|
+
# Use page as the default persistor
|
|
378
|
+
persistor ||= Persistors::Page
|
|
379
|
+
@persistor = persistor.new(self)
|
|
376
380
|
end
|
|
377
381
|
|
|
378
382
|
# Used internally from other methods that assign all attributes
|
|
@@ -390,9 +394,14 @@ module Volt
|
|
|
390
394
|
send(:"#{key}=", value)
|
|
391
395
|
else
|
|
392
396
|
# Otherwise, use the _ version
|
|
393
|
-
|
|
397
|
+
set(key, value)
|
|
394
398
|
end
|
|
395
399
|
end
|
|
400
|
+
|
|
401
|
+
# Make an id if there isn't one yet
|
|
402
|
+
if @attributes[:id].nil? && persistor.try(:auto_generate_id)
|
|
403
|
+
self.id = generate_id
|
|
404
|
+
end
|
|
396
405
|
end
|
|
397
406
|
end
|
|
398
407
|
end
|
|
@@ -21,6 +21,17 @@ module Volt
|
|
|
21
21
|
@persistor.event_removed(event, last, last_for_event) if @persistor
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
+
ID_CHARS = [('a'..'f'), ('0'..'9')].map(&:to_a).flatten
|
|
25
|
+
|
|
26
|
+
# Create a random unique id that can be used as the mongo id as well
|
|
27
|
+
def generate_id
|
|
28
|
+
id = []
|
|
29
|
+
24.times { id << ID_CHARS.sample }
|
|
30
|
+
|
|
31
|
+
id.join
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
|
|
24
35
|
module ClassMethods
|
|
25
36
|
# Gets the class for a model at the specified path.
|
|
26
37
|
def class_at_path(path)
|
|
@@ -9,7 +9,13 @@ module Volt
|
|
|
9
9
|
#
|
|
10
10
|
# @param key [Symbol] the name of the attribute to store
|
|
11
11
|
def own_by_user(key = :user_id)
|
|
12
|
-
|
|
12
|
+
relation, pattern = key.to_s, /_id$/
|
|
13
|
+
if relation.match(pattern)
|
|
14
|
+
belongs_to key.to_s.gsub(pattern, '')
|
|
15
|
+
else
|
|
16
|
+
raise "You tried to auto associate a model using #{key}, but #{key} "\
|
|
17
|
+
"does not end in `_id`"
|
|
18
|
+
end # When the model is created, assign it the user_id (if the user is logged in)
|
|
13
19
|
on(:new) do
|
|
14
20
|
# Only assign the user_id if there isn't already one and the user is logged in.
|
|
15
21
|
if _user_id.nil? && !(user_id = Volt.current_user_id).nil?
|
|
@@ -33,15 +39,6 @@ module Volt
|
|
|
33
39
|
end
|
|
34
40
|
end
|
|
35
41
|
|
|
36
|
-
# TODO: Change to
|
|
37
|
-
# permissions(:create, :read, :update) do |action|
|
|
38
|
-
# if owner?
|
|
39
|
-
# allow
|
|
40
|
-
# else
|
|
41
|
-
# deny :user_id
|
|
42
|
-
# end
|
|
43
|
-
# end
|
|
44
|
-
|
|
45
42
|
# permissions takes a block and yields
|
|
46
43
|
def permissions(*actions, &block)
|
|
47
44
|
# Store the permissions block so we can run it in validations
|
|
@@ -156,14 +153,14 @@ module Volt
|
|
|
156
153
|
|
|
157
154
|
if allow && allow != true && allow.size > 0
|
|
158
155
|
# always keep id
|
|
159
|
-
allow << :
|
|
156
|
+
allow << :id
|
|
160
157
|
|
|
161
158
|
# Only keep fields in the allow list
|
|
162
159
|
return @attributes.select { |key| allow.include?(key) }
|
|
163
160
|
elsif deny == true
|
|
164
161
|
# Only keep id
|
|
165
162
|
# TODO: Should this be a full reject?
|
|
166
|
-
return @attributes.reject { |key| key != :
|
|
163
|
+
return @attributes.reject { |key| key != :id }
|
|
167
164
|
elsif deny && deny.size > 0
|
|
168
165
|
# Reject any in the deny list
|
|
169
166
|
return @attributes.reject { |key| deny.include?(key) }
|
|
@@ -134,10 +134,10 @@ module Volt
|
|
|
134
134
|
|
|
135
135
|
parent.persistor.ensure_setup if parent.persistor
|
|
136
136
|
|
|
137
|
-
if parent && (attrs = parent.attributes) && attrs[:
|
|
137
|
+
if parent && (attrs = parent.attributes) && attrs[:id]
|
|
138
138
|
query = query.dup
|
|
139
139
|
|
|
140
|
-
query << [:find, { :"#{@model.path[-3].singularize}_id" => attrs[:
|
|
140
|
+
query << [:find, { :"#{@model.path[-3].singularize}_id" => attrs[:id] }]
|
|
141
141
|
end
|
|
142
142
|
end
|
|
143
143
|
|
|
@@ -208,7 +208,7 @@ module Volt
|
|
|
208
208
|
$loading_models = true
|
|
209
209
|
|
|
210
210
|
Model.no_validate do
|
|
211
|
-
data_id = data['
|
|
211
|
+
data_id = data['id'] || data[:id]
|
|
212
212
|
|
|
213
213
|
# Don't add if the model is already in the ArrayModel (from the client already)
|
|
214
214
|
unless @ids[data_id]
|
|
@@ -232,7 +232,7 @@ module Volt
|
|
|
232
232
|
ids.each do |id|
|
|
233
233
|
# TODO: optimize this delete so we don't need to loop
|
|
234
234
|
@model.each_with_index do |model, index|
|
|
235
|
-
if model.
|
|
235
|
+
if model.id == id
|
|
236
236
|
@ids.delete(id)
|
|
237
237
|
del = @model.delete_at(index)
|
|
238
238
|
break
|
|
@@ -259,7 +259,7 @@ module Volt
|
|
|
259
259
|
promise = model.persistor.add_to_collection
|
|
260
260
|
|
|
261
261
|
# Track the the model got added
|
|
262
|
-
@ids[model.
|
|
262
|
+
@ids[model.id] = true
|
|
263
263
|
|
|
264
264
|
promise
|
|
265
265
|
end
|
|
@@ -271,13 +271,13 @@ module Volt
|
|
|
271
271
|
# Tell the persistor it was removed
|
|
272
272
|
model.persistor.remove_from_collection
|
|
273
273
|
|
|
274
|
-
@ids.delete(model.
|
|
274
|
+
@ids.delete(model.id)
|
|
275
275
|
end
|
|
276
276
|
|
|
277
277
|
if defined?($loading_models) && $loading_models
|
|
278
278
|
return
|
|
279
279
|
else
|
|
280
|
-
StoreTasks.delete(channel_name, model.attributes[:
|
|
280
|
+
StoreTasks.delete(channel_name, model.attributes[:id])
|
|
281
281
|
end
|
|
282
282
|
end
|
|
283
283
|
end
|
|
@@ -2,6 +2,10 @@ module Volt
|
|
|
2
2
|
module Persistors
|
|
3
3
|
# Implements the base persistor functionality.
|
|
4
4
|
class Base
|
|
5
|
+
def initialize(model)
|
|
6
|
+
@model = model
|
|
7
|
+
end
|
|
8
|
+
|
|
5
9
|
def loaded(initial_state = nil)
|
|
6
10
|
@model.change_state_to(:loaded_state, initial_state || :loaded)
|
|
7
11
|
end
|
|
@@ -27,6 +31,11 @@ module Volt
|
|
|
27
31
|
def event_removed(event, last, last_for_event)
|
|
28
32
|
end
|
|
29
33
|
|
|
34
|
+
# Specify if this collection should auto-generate id's
|
|
35
|
+
def auto_generate_id
|
|
36
|
+
false
|
|
37
|
+
end
|
|
38
|
+
|
|
30
39
|
# Find the root for this model
|
|
31
40
|
def root_model
|
|
32
41
|
node = @model
|
|
@@ -6,10 +6,6 @@ module Volt
|
|
|
6
6
|
module Persistors
|
|
7
7
|
# Backs a collection in the local store
|
|
8
8
|
class LocalStore < Base
|
|
9
|
-
def initialize(model)
|
|
10
|
-
@model = model
|
|
11
|
-
end
|
|
12
|
-
|
|
13
9
|
# Called when a model is added to the collection
|
|
14
10
|
def added(model, index)
|
|
15
11
|
root_model.persistor.save_all
|
|
@@ -11,8 +11,6 @@ module Volt
|
|
|
11
11
|
class ModelStore < Store
|
|
12
12
|
include StoreState
|
|
13
13
|
|
|
14
|
-
ID_CHARS = [('a'..'f'), ('0'..'9')].map(&:to_a).flatten
|
|
15
|
-
|
|
16
14
|
attr_reader :model
|
|
17
15
|
attr_accessor :in_identity_map
|
|
18
16
|
|
|
@@ -40,32 +38,23 @@ module Volt
|
|
|
40
38
|
@in_collection = false
|
|
41
39
|
end
|
|
42
40
|
|
|
41
|
+
def auto_generate_id
|
|
42
|
+
true
|
|
43
|
+
end
|
|
44
|
+
|
|
43
45
|
# Called the first time a value is assigned into this model
|
|
44
46
|
def ensure_setup
|
|
45
|
-
|
|
46
|
-
# Do a nil check incase there is a nil model there
|
|
47
|
-
@model.__id = generate_id if attrs[:_id].nil?
|
|
48
|
-
|
|
49
|
-
add_to_identity_map
|
|
50
|
-
end
|
|
47
|
+
add_to_identity_map
|
|
51
48
|
end
|
|
52
49
|
|
|
53
50
|
def add_to_identity_map
|
|
54
51
|
unless @in_identity_map
|
|
55
|
-
@@identity_map.add(@model.
|
|
52
|
+
@@identity_map.add(@model.id, @model)
|
|
56
53
|
|
|
57
54
|
@in_identity_map = true
|
|
58
55
|
end
|
|
59
56
|
end
|
|
60
57
|
|
|
61
|
-
# Create a random unique id that can be used as the mongo id as well
|
|
62
|
-
def generate_id
|
|
63
|
-
id = []
|
|
64
|
-
24.times { id << ID_CHARS.sample }
|
|
65
|
-
|
|
66
|
-
id.join
|
|
67
|
-
end
|
|
68
|
-
|
|
69
58
|
def save_changes?
|
|
70
59
|
if RUBY_PLATFORM == 'opal'
|
|
71
60
|
!(defined?($loading_models) && $loading_models) && @tasks
|
|
@@ -85,7 +74,7 @@ module Volt
|
|
|
85
74
|
path_size = path.size
|
|
86
75
|
if save_changes? && path_size > 0 && !@model.nil?
|
|
87
76
|
if path_size > 3 && (parent = @model.parent) && (source = parent.parent)
|
|
88
|
-
@model.attributes[:"#{path[-4].singularize}_id"] = source.
|
|
77
|
+
@model.attributes[:"#{path[-4].singularize}_id"] = source.id
|
|
89
78
|
end
|
|
90
79
|
|
|
91
80
|
if !collection
|
|
@@ -152,7 +141,7 @@ module Volt
|
|
|
152
141
|
|
|
153
142
|
if model
|
|
154
143
|
data.each_pair do |key, value|
|
|
155
|
-
model.
|
|
144
|
+
model.set(key, value)# if key != :id
|
|
156
145
|
end
|
|
157
146
|
end
|
|
158
147
|
end
|
|
@@ -186,7 +175,7 @@ module Volt
|
|
|
186
175
|
return errors if errors.present?
|
|
187
176
|
|
|
188
177
|
# Passed, save it
|
|
189
|
-
id = values[:
|
|
178
|
+
id = values[:id]
|
|
190
179
|
|
|
191
180
|
# Try to create
|
|
192
181
|
update_result = db.update(collection, values)
|
|
@@ -194,7 +183,10 @@ module Volt
|
|
|
194
183
|
# An error hash will be returned if the update doesn't work
|
|
195
184
|
return update_result if update_result
|
|
196
185
|
|
|
197
|
-
|
|
186
|
+
# If we are running in a task, or the console, push update
|
|
187
|
+
if (volt_app = Volt.current_app)
|
|
188
|
+
volt_app.live_query_pool.updated_collection(collection.to_s, Thread.current['in_channel'])
|
|
189
|
+
end
|
|
198
190
|
{}
|
|
199
191
|
end
|
|
200
192
|
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
require 'volt/models/persistors/base'
|
|
2
|
+
|
|
3
|
+
module Volt
|
|
4
|
+
module Persistors
|
|
5
|
+
class Page < Base
|
|
6
|
+
def auto_generate_id
|
|
7
|
+
true
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def where(query)
|
|
11
|
+
@model.select do |model|
|
|
12
|
+
# Filter through each part of the query and make sure it matches.
|
|
13
|
+
query.each_pair do |key, value|
|
|
14
|
+
next false unless model.get(key) == value
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
true
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -40,8 +40,9 @@ module Volt
|
|
|
40
40
|
end
|
|
41
41
|
end.fail do |err|
|
|
42
42
|
# TODO: need to make it so we can re-raise out of this promise
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
msg = "Error adding listener: #{err.inspect}"
|
|
44
|
+
msg += "\n#{err.backtrace.join("\n")}" if err.respond_to?(:backtrace)
|
|
45
|
+
Volt.logger.error(msg)
|
|
45
46
|
|
|
46
47
|
# If we get back that the user signature is wrong, log the user out.
|
|
47
48
|
if err.to_s.start_with?('user id or hash is incorrectly signed')
|
data/lib/volt/models/url.rb
CHANGED
|
@@ -102,7 +102,7 @@ module Volt
|
|
|
102
102
|
# browser should be updated
|
|
103
103
|
# Called when an attribute changes to update the url
|
|
104
104
|
def update!
|
|
105
|
-
if Volt.
|
|
105
|
+
if Volt.in_browser?
|
|
106
106
|
new_url = url_for(@params.to_h)
|
|
107
107
|
|
|
108
108
|
# Push the new url if pushState is supported
|
|
@@ -116,7 +116,7 @@ module Volt
|
|
|
116
116
|
end
|
|
117
117
|
|
|
118
118
|
def scroll
|
|
119
|
-
if Volt.
|
|
119
|
+
if Volt.in_browser?
|
|
120
120
|
frag = fragment
|
|
121
121
|
if frag.present?
|
|
122
122
|
# Scroll to anchor via http://www.w3.org/html/wg/drafts/html/master/browsers.html#scroll-to-fragid
|
|
@@ -8,7 +8,7 @@ module Volt
|
|
|
8
8
|
query = {}
|
|
9
9
|
# Check to see if any other documents have this value.
|
|
10
10
|
query[field_name.to_s] = value
|
|
11
|
-
query['
|
|
11
|
+
query['id'] = { '$ne' => model.id }
|
|
12
12
|
|
|
13
13
|
# Check if the value is taken
|
|
14
14
|
# TODO: need a way to handle scope for unique
|
data/lib/volt/models.rb
CHANGED
|
@@ -2,6 +2,7 @@ require 'volt/extra_core/extra_core'
|
|
|
2
2
|
require 'volt/models/model'
|
|
3
3
|
require 'volt/models/cursor'
|
|
4
4
|
require 'volt/models/persistors/store_factory'
|
|
5
|
+
require 'volt/models/persistors/page'
|
|
5
6
|
require 'volt/models/persistors/array_store'
|
|
6
7
|
require 'volt/models/persistors/model_store'
|
|
7
8
|
require 'volt/models/persistors/params'
|
|
@@ -3,8 +3,8 @@ require 'volt/page/targets/attribute_target'
|
|
|
3
3
|
|
|
4
4
|
module Volt
|
|
5
5
|
class AttributeBinding < BaseBinding
|
|
6
|
-
def initialize(
|
|
7
|
-
super(
|
|
6
|
+
def initialize(volt_app, target, context, binding_name, attribute_name, getter, setter)
|
|
7
|
+
super(volt_app, target, context, binding_name)
|
|
8
8
|
|
|
9
9
|
@attribute_name = attribute_name
|
|
10
10
|
@getter = getter
|
|
@@ -10,10 +10,10 @@
|
|
|
10
10
|
# binding will be inserted.
|
|
11
11
|
module Volt
|
|
12
12
|
class BaseBinding
|
|
13
|
-
attr_accessor :target, :context, :binding_name
|
|
13
|
+
attr_accessor :target, :context, :binding_name, :volt_app
|
|
14
14
|
|
|
15
|
-
def initialize(
|
|
16
|
-
@
|
|
15
|
+
def initialize(volt_app, target, context, binding_name)
|
|
16
|
+
@volt_app = volt_app
|
|
17
17
|
@target = target
|
|
18
18
|
@context = context
|
|
19
19
|
@binding_name = binding_name
|
|
@@ -21,6 +21,10 @@ module Volt
|
|
|
21
21
|
@@binding_number ||= 10_000
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
+
def page
|
|
25
|
+
@volt_app.page
|
|
26
|
+
end
|
|
27
|
+
|
|
24
28
|
def dom_section
|
|
25
29
|
@dom_section ||= target.dom_section(@binding_name)
|
|
26
30
|
end
|