volt 0.8.14 → 0.8.15
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 +1 -1
- data/Readme.md +8 -2
- data/VERSION +1 -1
- data/app/volt/controllers/notices_controller.rb +1 -1
- data/app/volt/models/user.rb +2 -2
- data/app/volt/tasks/live_query/live_query_pool.rb +1 -1
- data/app/volt/tasks/query_tasks.rb +1 -1
- data/app/volt/tasks/store_tasks.rb +1 -1
- data/app/volt/tasks/user_tasks.rb +2 -2
- data/lib/volt/boot.rb +2 -2
- data/lib/volt/cli/asset_compile.rb +31 -27
- data/lib/volt/cli.rb +64 -65
- data/lib/volt/config.rb +25 -23
- data/lib/volt/console.rb +17 -16
- data/lib/volt/controllers/model_controller.rb +82 -80
- data/lib/volt/data_stores/data_store.rb +2 -2
- data/lib/volt/data_stores/mongo_driver.rb +2 -2
- data/lib/volt/extra_core/inflections.rb +2 -2
- data/lib/volt/extra_core/inflector/inflections.rb +185 -183
- data/lib/volt/extra_core/inflector/methods.rb +50 -48
- data/lib/volt/extra_core/string.rb +2 -2
- data/lib/volt/models/array_model.rb +93 -92
- data/lib/volt/models/cursor.rb +3 -2
- data/lib/volt/models/model.rb +248 -251
- data/lib/volt/models/model_hash_behaviour.rb +44 -44
- data/lib/volt/models/model_helpers.rb +38 -36
- data/lib/volt/models/model_state.rb +16 -17
- data/lib/volt/models/model_wrapper.rb +25 -24
- data/lib/volt/models/persistors/array_store.rb +145 -143
- data/lib/volt/models/persistors/base.rb +18 -16
- data/lib/volt/models/persistors/flash.rb +24 -22
- data/lib/volt/models/persistors/local_store.rb +46 -44
- data/lib/volt/models/persistors/model_identity_map.rb +10 -8
- data/lib/volt/models/persistors/model_store.rb +76 -76
- data/lib/volt/models/persistors/params.rb +19 -17
- data/lib/volt/models/persistors/query/query_listener.rb +65 -63
- data/lib/volt/models/persistors/query/query_listener_pool.rb +12 -10
- data/lib/volt/models/persistors/store.rb +28 -28
- data/lib/volt/models/persistors/store_factory.rb +12 -10
- data/lib/volt/models/persistors/store_state.rb +33 -31
- data/lib/volt/models/url.rb +96 -104
- data/lib/volt/models/validations.rb +56 -54
- data/lib/volt/models/validators/length_validator.rb +24 -22
- data/lib/volt/models/validators/presence_validator.rb +14 -12
- data/lib/volt/page/bindings/attribute_binding.rb +106 -106
- data/lib/volt/page/bindings/base_binding.rb +23 -21
- data/lib/volt/page/bindings/component_binding.rb +3 -1
- data/lib/volt/page/bindings/content_binding.rb +34 -34
- data/lib/volt/page/bindings/each_binding.rb +113 -113
- data/lib/volt/page/bindings/event_binding.rb +38 -34
- data/lib/volt/page/bindings/if_binding.rb +56 -54
- data/lib/volt/page/bindings/template_binding/grouped_controllers.rb +24 -22
- data/lib/volt/page/bindings/template_binding.rb +182 -185
- data/lib/volt/page/channel.rb +79 -77
- data/lib/volt/page/channel_stub.rb +29 -27
- data/lib/volt/page/document.rb +6 -5
- data/lib/volt/page/document_events.rb +54 -52
- data/lib/volt/page/page.rb +139 -138
- data/lib/volt/page/string_template_renderer.rb +36 -36
- data/lib/volt/page/sub_context.rb +26 -25
- data/lib/volt/page/targets/attribute_section.rb +27 -25
- data/lib/volt/page/targets/attribute_target.rb +7 -6
- data/lib/volt/page/targets/base_section.rb +27 -26
- data/lib/volt/page/targets/binding_document/base_node.rb +3 -1
- data/lib/volt/page/targets/binding_document/component_node.rb +85 -82
- data/lib/volt/page/targets/binding_document/html_node.rb +11 -9
- data/lib/volt/page/targets/dom_section.rb +78 -77
- data/lib/volt/page/targets/dom_target.rb +8 -6
- data/lib/volt/page/targets/dom_template.rb +90 -88
- data/lib/volt/page/targets/helpers/comment_searchers.rb +51 -49
- data/lib/volt/page/tasks.rb +59 -57
- data/lib/volt/page/template_renderer.rb +17 -14
- data/lib/volt/page/url_tracker.rb +26 -24
- data/lib/volt/reactive/computation.rb +87 -88
- data/lib/volt/reactive/dependency.rb +30 -28
- data/lib/volt/reactive/eventable.rb +64 -62
- data/lib/volt/reactive/hash_dependency.rb +25 -23
- data/lib/volt/reactive/reactive_accessors.rb +34 -32
- data/lib/volt/reactive/reactive_array.rb +162 -162
- data/lib/volt/reactive/reactive_hash.rb +37 -35
- data/lib/volt/router/routes.rb +99 -101
- data/lib/volt/server/component_handler.rb +20 -21
- data/lib/volt/server/component_templates.rb +72 -70
- data/lib/volt/server/html_parser/attribute_scope.rb +109 -99
- data/lib/volt/server/html_parser/each_scope.rb +17 -16
- data/lib/volt/server/html_parser/if_view_scope.rb +51 -49
- data/lib/volt/server/html_parser/sandlebars_parser.rb +184 -177
- data/lib/volt/server/html_parser/textarea_scope.rb +24 -22
- data/lib/volt/server/html_parser/view_handler.rb +66 -65
- data/lib/volt/server/html_parser/view_parser.rb +23 -21
- data/lib/volt/server/html_parser/view_scope.rb +142 -141
- data/lib/volt/server/rack/asset_files.rb +81 -79
- data/lib/volt/server/rack/component_code.rb +17 -15
- data/lib/volt/server/rack/component_html_renderer.rb +14 -12
- data/lib/volt/server/rack/component_paths.rb +72 -71
- data/lib/volt/server/rack/index_files.rb +36 -39
- data/lib/volt/server/rack/opal_files.rb +43 -41
- data/lib/volt/server/rack/source_map_server.rb +23 -21
- data/lib/volt/server/socket_connection_handler.rb +46 -45
- data/lib/volt/server/socket_connection_handler_stub.rb +21 -19
- data/lib/volt/server.rb +60 -58
- data/lib/volt/spec/setup.rb +3 -3
- data/lib/volt/tasks/dispatcher.rb +24 -23
- data/lib/volt/tasks/task_handler.rb +35 -33
- data/lib/volt/utils/ejson.rb +8 -6
- data/lib/volt/utils/generic_counting_pool.rb +33 -31
- data/lib/volt/utils/generic_pool.rb +73 -70
- data/lib/volt/utils/local_storage.rb +42 -38
- data/lib/volt/volt/environment.rb +1 -1
- data/lib/volt.rb +44 -42
- data/spec/apps/kitchen_sink/app/main/assets/css/todos.css +28 -0
- data/spec/apps/kitchen_sink/app/main/config/routes.rb +1 -0
- data/spec/apps/kitchen_sink/app/main/controllers/main_controller.rb +2 -2
- data/spec/apps/kitchen_sink/app/main/controllers/todos_controller.rb +17 -0
- data/spec/apps/kitchen_sink/app/main/views/main/main.html +1 -0
- data/spec/apps/kitchen_sink/app/main/views/todos/index.html +24 -0
- data/spec/apps/kitchen_sink/config.ru +1 -1
- data/spec/controllers/reactive_accessors_spec.rb +5 -5
- data/spec/extra_core/inflector_spec.rb +2 -2
- data/spec/integration/list_spec.rb +68 -0
- data/spec/models/model_spec.rb +57 -57
- data/spec/models/persistors/params_spec.rb +6 -6
- data/spec/models/persistors/store_spec.rb +7 -7
- data/spec/models/validations_spec.rb +3 -3
- data/spec/page/bindings/content_binding_spec.rb +7 -7
- data/spec/page/bindings/template_binding_spec.rb +4 -5
- data/spec/page/sub_context_spec.rb +2 -2
- data/spec/reactive/computation_spec.rb +10 -10
- data/spec/reactive/dependency_spec.rb +2 -2
- data/spec/reactive/eventable_spec.rb +4 -4
- data/spec/reactive/reactive_array_spec.rb +13 -13
- data/spec/router/routes_spec.rb +5 -5
- data/spec/server/html_parser/sandlebars_parser_spec.rb +9 -9
- data/spec/server/html_parser/view_parser_spec.rb +27 -27
- data/spec/server/rack/asset_files_spec.rb +5 -5
- data/spec/server/rack/component_paths_spec.rb +2 -2
- data/spec/tasks/live_query_spec.rb +2 -2
- data/spec/tasks/query_tasks.rb +1 -1
- data/spec/tasks/query_tracker_spec.rb +1 -1
- data/spec/templates/targets/binding_document/component_node_spec.rb +2 -2
- data/spec/utils/generic_counting_pool_spec.rb +2 -2
- data/spec/utils/generic_pool_spec.rb +2 -2
- data/templates/component/controllers/main_controller.rb +1 -1
- data/templates/model/model.rb.tt +2 -2
- data/templates/newgem/app/newgem/controllers/main_controller.rb.tt +2 -2
- data/templates/project/app/main/controllers/main_controller.rb +1 -1
- data/templates/project/config.ru +1 -1
- metadata +10 -3
- data/app/volt/assets/js/vertxbus.js +0 -216
|
@@ -1,62 +1,62 @@
|
|
|
1
|
-
|
|
2
|
-
#
|
|
3
|
-
#
|
|
4
|
-
|
|
1
|
+
module Volt
|
|
2
|
+
# Contains all of the methods on a model that make it behave like a hash.
|
|
3
|
+
# Moving this into a module cleans up the main Model class for things that
|
|
4
|
+
# make it behave like a model.
|
|
5
|
+
module ModelHashBehaviour
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
|
|
7
|
+
def delete(name)
|
|
8
|
+
name = name.to_sym
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
value = attributes.delete(name)
|
|
11
|
+
@deps.delete(name)
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
@persistor.removed(name) if @persistor
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def nil?
|
|
18
|
-
attributes.nil?
|
|
19
|
-
end
|
|
15
|
+
value
|
|
16
|
+
end
|
|
20
17
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
18
|
+
def nil?
|
|
19
|
+
attributes.nil?
|
|
20
|
+
end
|
|
24
21
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
22
|
+
def empty?
|
|
23
|
+
!attributes || attributes.size == 0
|
|
24
|
+
end
|
|
28
25
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
26
|
+
def false?
|
|
27
|
+
attributes.false?
|
|
28
|
+
end
|
|
32
29
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
@deps.changed!(key)
|
|
30
|
+
def true?
|
|
31
|
+
attributes.true?
|
|
36
32
|
end
|
|
37
33
|
|
|
38
|
-
|
|
34
|
+
def clear
|
|
35
|
+
attributes.each_pair do |key, value|
|
|
36
|
+
@deps.changed!(key)
|
|
37
|
+
end
|
|
39
38
|
|
|
40
|
-
|
|
41
|
-
end
|
|
39
|
+
attributes.clear
|
|
42
40
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
end
|
|
41
|
+
@persistor.removed(nil) if @persistor
|
|
42
|
+
end
|
|
46
43
|
|
|
44
|
+
def each_with_object(*args, &block)
|
|
45
|
+
(@attributes || {}).each_with_object(*args, &block)
|
|
46
|
+
end
|
|
47
47
|
|
|
48
|
-
# Convert the model to a hash all of the way down.
|
|
49
|
-
def to_h
|
|
50
|
-
hash = {}
|
|
51
|
-
if empty?
|
|
52
|
-
return nil
|
|
53
|
-
else
|
|
54
|
-
attributes.each_pair do |key, value|
|
|
55
|
-
hash[key] = deep_unwrap(value)
|
|
56
|
-
end
|
|
57
48
|
|
|
58
|
-
|
|
49
|
+
# Convert the model to a hash all of the way down.
|
|
50
|
+
def to_h
|
|
51
|
+
if empty?
|
|
52
|
+
nil
|
|
53
|
+
else
|
|
54
|
+
hash = {}
|
|
55
|
+
attributes.each_pair do |key, value|
|
|
56
|
+
hash[key] = deep_unwrap(value)
|
|
57
|
+
end
|
|
58
|
+
hash
|
|
59
|
+
end
|
|
59
60
|
end
|
|
60
61
|
end
|
|
61
|
-
|
|
62
62
|
end
|
|
@@ -1,47 +1,49 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
module Volt
|
|
2
|
+
# A place for things shared between an ArrayModel and a Model
|
|
3
|
+
module ModelHelpers
|
|
4
|
+
def deep_unwrap(value)
|
|
5
|
+
if value.is_a?(Model)
|
|
6
|
+
value.to_h
|
|
7
|
+
elsif value.is_a?(ArrayModel)
|
|
8
|
+
value.to_a
|
|
9
|
+
else
|
|
10
|
+
value
|
|
11
|
+
end
|
|
8
12
|
end
|
|
9
13
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
def event_added(event, first, first_for_event)
|
|
15
|
-
@persistor.event_added(event, first, first_for_event) if @persistor
|
|
16
|
-
end
|
|
14
|
+
# Pass to the persisotr
|
|
15
|
+
def event_added(event, first, first_for_event)
|
|
16
|
+
@persistor.event_added(event, first, first_for_event) if @persistor
|
|
17
|
+
end
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
# Pass to the persistor
|
|
20
|
+
def event_removed(event, last, last_for_event)
|
|
21
|
+
@persistor.event_removed(event, last, last_for_event) if @persistor
|
|
22
|
+
end
|
|
22
23
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
24
|
+
# Gets the class for a model at the specified path.
|
|
25
|
+
def class_at_path(path)
|
|
26
|
+
if path
|
|
27
|
+
begin
|
|
28
|
+
# remove the _ and then singularize
|
|
29
|
+
if path.last == :[]
|
|
30
|
+
index = -2
|
|
31
|
+
else
|
|
32
|
+
index = -1
|
|
33
|
+
end
|
|
33
34
|
|
|
34
|
-
|
|
35
|
+
klass_name = path[index].singularize.camelize
|
|
35
36
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
klass = $page.model_classes[klass_name] || Model
|
|
38
|
+
rescue NameError => e
|
|
39
|
+
# Ignore exception, just means the model isn't defined
|
|
40
|
+
klass = Model
|
|
41
|
+
end
|
|
42
|
+
else
|
|
39
43
|
klass = Model
|
|
40
44
|
end
|
|
41
|
-
else
|
|
42
|
-
klass = Model
|
|
43
|
-
end
|
|
44
45
|
|
|
45
|
-
|
|
46
|
+
klass
|
|
47
|
+
end
|
|
46
48
|
end
|
|
47
49
|
end
|
|
@@ -1,22 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
# being loaded,
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
module Volt
|
|
2
|
+
# All models have a state that has to do with it being loaded, in process of
|
|
3
|
+
# being loaded, or not yet loading.
|
|
4
|
+
module ModelState
|
|
5
|
+
def state
|
|
6
|
+
if @persistor && @persistor.respond_to?(:state)
|
|
7
|
+
@persistor.state
|
|
8
|
+
else
|
|
9
|
+
@state || :loaded
|
|
10
|
+
end
|
|
10
11
|
end
|
|
11
|
-
end
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
def change_state_to(state)
|
|
14
|
+
@state = state
|
|
15
|
+
end
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
def loaded?
|
|
18
|
+
self.state == :loaded
|
|
19
|
+
end
|
|
19
20
|
end
|
|
20
|
-
|
|
21
|
-
|
|
22
21
|
end
|
|
@@ -1,31 +1,32 @@
|
|
|
1
|
-
module
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
module Volt
|
|
2
|
+
module ModelWrapper
|
|
3
|
+
# For cretain values, we wrap them to make the behave as a
|
|
4
|
+
# model.
|
|
5
|
+
def wrap_value(value, lookup)
|
|
6
|
+
if value.is_a?(Array)
|
|
7
|
+
new_array_model(value, @options.merge(parent: self, path: path + lookup))
|
|
8
|
+
elsif value.is_a?(Hash)
|
|
9
|
+
new_model(value, @options.merge(parent: self, path: path + lookup))
|
|
10
|
+
else
|
|
11
|
+
value
|
|
12
|
+
end
|
|
9
13
|
end
|
|
10
14
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
pairs = values.map do |k,v|
|
|
20
|
-
# TODO: We should be able to move wrapping into the method_missing on model
|
|
21
|
-
path = lookup + [k.to_sym]
|
|
15
|
+
def wrap_values(values, lookup=[])
|
|
16
|
+
if values.is_a?(Array)
|
|
17
|
+
# Coming from an array
|
|
18
|
+
values.map { |v| wrap_value(v, lookup + [:[]]) }
|
|
19
|
+
elsif values.is_a?(Hash)
|
|
20
|
+
pairs = values.map do |k, v|
|
|
21
|
+
# TODO: We should be able to move wrapping into the method_missing on model
|
|
22
|
+
path = lookup + [k.to_sym]
|
|
22
23
|
|
|
23
|
-
|
|
24
|
+
[k, wrap_value(v, path)]
|
|
25
|
+
end
|
|
26
|
+
Hash[pairs]
|
|
27
|
+
else
|
|
28
|
+
values
|
|
24
29
|
end
|
|
25
|
-
|
|
26
|
-
values = Hash[pairs]
|
|
27
30
|
end
|
|
28
|
-
|
|
29
|
-
return values
|
|
30
31
|
end
|
|
31
32
|
end
|
|
@@ -2,203 +2,205 @@ require 'volt/models/persistors/store'
|
|
|
2
2
|
require 'volt/models/persistors/query/query_listener_pool'
|
|
3
3
|
require 'volt/models/persistors/store_state'
|
|
4
4
|
|
|
5
|
-
module
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
module Volt
|
|
6
|
+
module Persistors
|
|
7
|
+
class ArrayStore < Store
|
|
8
|
+
include StoreState
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
@@query_pool = QueryListenerPool.new
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
attr_reader :model
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
def self.query_pool
|
|
15
|
+
@@query_pool
|
|
16
|
+
end
|
|
16
17
|
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
def initialize(model, tasks=nil)
|
|
19
|
+
super
|
|
19
20
|
|
|
20
|
-
|
|
21
|
-
|
|
21
|
+
@query = @model.options[:query]
|
|
22
|
+
end
|
|
22
23
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
def event_added(event, first, first_for_event)
|
|
25
|
+
# First event, we load the data.
|
|
26
|
+
if first
|
|
27
|
+
@has_events = true
|
|
28
|
+
load_data
|
|
29
|
+
end
|
|
28
30
|
end
|
|
29
|
-
end
|
|
30
31
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
def event_removed(event, last, last_for_event)
|
|
33
|
+
# Remove listener where there are no more events on this model
|
|
34
|
+
if last
|
|
35
|
+
@has_events = false
|
|
36
|
+
stop_listening
|
|
37
|
+
end
|
|
36
38
|
end
|
|
37
|
-
end
|
|
38
39
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
40
|
+
# Called when an event is removed and we no longer want to keep in
|
|
41
|
+
# sync with the database.
|
|
42
|
+
def stop_listening(stop_watching_query=true)
|
|
43
|
+
return if @has_events
|
|
44
|
+
return if @fetch_promises && @fetch_promises.size > 0
|
|
44
45
|
|
|
45
|
-
|
|
46
|
+
@query_computation.stop if @query_computation && stop_watching_query
|
|
46
47
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
if @query_listener
|
|
49
|
+
@query_listener.remove_store(self)
|
|
50
|
+
@query_listener = nil
|
|
51
|
+
end
|
|
51
52
|
|
|
52
|
-
|
|
53
|
-
|
|
53
|
+
@state = :dirty
|
|
54
|
+
end
|
|
54
55
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
56
|
+
# Called the first time data is requested from this collection
|
|
57
|
+
def load_data
|
|
58
|
+
# Don't load data from any queried
|
|
59
|
+
if @state == :not_loaded || @state == :dirty
|
|
60
|
+
# puts "Load Data at #{@model.path.inspect} - query: #{@query.inspect} on #{self.inspect}"
|
|
61
|
+
change_state_to :loading
|
|
61
62
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
if @query.is_a?(Proc)
|
|
64
|
+
@query_computation = -> do
|
|
65
|
+
stop_listening(false)
|
|
65
66
|
|
|
66
|
-
|
|
67
|
+
change_state_to :loading
|
|
67
68
|
|
|
68
|
-
|
|
69
|
+
new_query = @query.call
|
|
69
70
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
71
|
+
run_query(@model, @query.call)
|
|
72
|
+
end.watch!
|
|
73
|
+
else
|
|
74
|
+
run_query(@model, @query)
|
|
75
|
+
end
|
|
74
76
|
end
|
|
75
77
|
end
|
|
76
|
-
end
|
|
77
78
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
79
|
+
# Clear out the models data, since we're not listening anymore.
|
|
80
|
+
def unload_data
|
|
81
|
+
change_state_to :not_loaded
|
|
82
|
+
@model.clear
|
|
83
|
+
end
|
|
83
84
|
|
|
84
|
-
|
|
85
|
-
|
|
85
|
+
def run_query(model, query={})
|
|
86
|
+
@model.clear
|
|
86
87
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
88
|
+
collection = model.path.last
|
|
89
|
+
# Scope to the parent
|
|
90
|
+
if model.path.size > 1
|
|
91
|
+
parent = model.parent
|
|
91
92
|
|
|
92
|
-
|
|
93
|
+
parent.persistor.ensure_setup if parent.persistor
|
|
93
94
|
|
|
94
|
-
|
|
95
|
-
|
|
95
|
+
if parent && (attrs = parent.attributes) && attrs[:_id].true?
|
|
96
|
+
query[:"#{model.path[-3].singularize}_id"] = attrs[:_id]
|
|
97
|
+
end
|
|
96
98
|
end
|
|
97
|
-
end
|
|
98
99
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
100
|
+
@query_listener = @@query_pool.lookup(collection, query) do
|
|
101
|
+
# Create if it does not exist
|
|
102
|
+
QueryListener.new(@@query_pool, @tasks, collection, query)
|
|
103
|
+
end
|
|
103
104
|
|
|
104
|
-
|
|
105
|
-
|
|
105
|
+
@query_listener.add_store(self)
|
|
106
|
+
end
|
|
106
107
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
108
|
+
# Find can take either a query object, or a block that returns a query object. Use
|
|
109
|
+
# the block style if you need reactive updating queries
|
|
110
|
+
def find(query=nil, &block)
|
|
111
|
+
# Set a default query if there is no block
|
|
112
|
+
if block
|
|
113
|
+
if query
|
|
114
|
+
raise "Query should not be passed in to a find if a block is specified"
|
|
115
|
+
end
|
|
116
|
+
query = block
|
|
117
|
+
else
|
|
118
|
+
query ||= {}
|
|
114
119
|
end
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
query ||= {}
|
|
120
|
+
|
|
121
|
+
return Cursor.new([], @model.options.merge(:query => query))
|
|
118
122
|
end
|
|
119
123
|
|
|
120
|
-
|
|
121
|
-
|
|
124
|
+
# Returns a promise that is resolved/rejected when the query is complete. Any
|
|
125
|
+
# passed block will be passed to the promises then. Then will be passed the model.
|
|
126
|
+
def then(&block)
|
|
127
|
+
promise = Promise.new
|
|
122
128
|
|
|
123
|
-
|
|
124
|
-
# passed block will be passed to the promises then. Then will be passed the model.
|
|
125
|
-
def then(&block)
|
|
126
|
-
promise = Promise.new
|
|
129
|
+
promise = promise.then(&block) if block
|
|
127
130
|
|
|
128
|
-
|
|
131
|
+
if @state == :loaded
|
|
132
|
+
promise.resolve(@model)
|
|
133
|
+
else
|
|
134
|
+
@fetch_promises ||= []
|
|
135
|
+
@fetch_promises << promise
|
|
129
136
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
else
|
|
133
|
-
@fetch_promises ||= []
|
|
134
|
-
@fetch_promises << promise
|
|
137
|
+
load_data
|
|
138
|
+
end
|
|
135
139
|
|
|
136
|
-
|
|
140
|
+
return promise
|
|
137
141
|
end
|
|
138
142
|
|
|
139
|
-
|
|
140
|
-
|
|
143
|
+
# Called from backend
|
|
144
|
+
def add(index, data)
|
|
145
|
+
$loading_models = true
|
|
141
146
|
|
|
142
|
-
|
|
143
|
-
def add(index, data)
|
|
144
|
-
$loading_models = true
|
|
147
|
+
data_id = data[:_id]
|
|
145
148
|
|
|
146
|
-
|
|
149
|
+
# Don't add if the model is already in the ArrayModel
|
|
150
|
+
if !@model.array.find { |v| v._id == data_id }
|
|
151
|
+
# Find the existing model, or create one
|
|
152
|
+
new_model = @@identity_map.find(data_id) do
|
|
153
|
+
new_options = @model.options.merge(path: @model.path + [:[]], parent: @model)
|
|
154
|
+
@model.new_model(data, new_options, :loaded)
|
|
155
|
+
end
|
|
147
156
|
|
|
148
|
-
|
|
149
|
-
if !@model.array.find {|v| v._id == data_id }
|
|
150
|
-
# Find the existing model, or create one
|
|
151
|
-
new_model = @@identity_map.find(data_id) do
|
|
152
|
-
new_options = @model.options.merge(path: @model.path + [:[]], parent: @model)
|
|
153
|
-
@model.new_model(data, new_options, :loaded)
|
|
157
|
+
@model.insert(index, new_model)
|
|
154
158
|
end
|
|
155
159
|
|
|
156
|
-
|
|
160
|
+
$loading_models = false
|
|
157
161
|
end
|
|
158
162
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
del = @model.delete_at(index)
|
|
169
|
-
break
|
|
163
|
+
def remove(ids)
|
|
164
|
+
$loading_models = true
|
|
165
|
+
ids.each do |id|
|
|
166
|
+
# TODO: optimize this delete so we don't need to loop
|
|
167
|
+
@model.each_with_index do |model, index|
|
|
168
|
+
if model._id == id
|
|
169
|
+
del = @model.delete_at(index)
|
|
170
|
+
break
|
|
171
|
+
end
|
|
170
172
|
end
|
|
171
173
|
end
|
|
172
|
-
end
|
|
173
174
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
def channel_name
|
|
178
|
-
@model.path[-1]
|
|
179
|
-
end
|
|
175
|
+
$loading_models = false
|
|
176
|
+
end
|
|
180
177
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
def added(model, index)
|
|
184
|
-
if model.persistor
|
|
185
|
-
# Tell the persistor it was added
|
|
186
|
-
model.persistor.add_to_collection
|
|
178
|
+
def channel_name
|
|
179
|
+
@model.path[-1]
|
|
187
180
|
end
|
|
188
|
-
end
|
|
189
181
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
model.persistor
|
|
182
|
+
# When a model is added to this collection, we call its "changed"
|
|
183
|
+
# method. This should trigger a save.
|
|
184
|
+
def added(model, index)
|
|
185
|
+
if model.persistor
|
|
186
|
+
# Tell the persistor it was added
|
|
187
|
+
model.persistor.add_to_collection
|
|
188
|
+
end
|
|
194
189
|
end
|
|
195
190
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
191
|
+
def removed(model)
|
|
192
|
+
if model.persistor
|
|
193
|
+
# Tell the persistor it was removed
|
|
194
|
+
model.persistor.remove_from_collection
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
if defined?($loading_models) && $loading_models
|
|
198
|
+
return
|
|
199
|
+
else
|
|
200
|
+
StoreTasks.delete(channel_name, model.attributes[:_id])
|
|
201
|
+
end
|
|
200
202
|
end
|
|
201
|
-
end
|
|
202
203
|
|
|
204
|
+
end
|
|
203
205
|
end
|
|
204
206
|
end
|