Class: Volt::ArrayModel

Inherits:
ReactiveArray show all
Includes:
ModelHelpers, ModelWrapper, StateHelpers, StateManager
Defined in:
lib/volt/models/array_model.rb

Direct Known Subclasses

Cursor

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from StateHelpers

#loaded?, #loaded_state

Methods included from StateManager

#change_state_to, #state_for

Methods included from ModelHelpers

#deep_unwrap, #event_added, #event_removed, included

Methods included from ModelWrapper

#wrap_value, #wrap_values

Methods inherited from ReactiveArray

#==, #[], #[]=, #all?, #any?, #clear, #count, #delete_at, #each, #empty?, #insert, #method_missing, #select, #size

Methods included from Eventable

#on, #remove_listener, #trigger!

Constructor Details

#initialize(array = [], options = {}) ⇒ ArrayModel

Returns a new instance of ArrayModel.



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/volt/models/array_model.rb', line 46

def initialize(array = [], options = {})
  @options   = options
  @parent    = options[:parent]
  @path      = options[:path] || []
  @persistor = setup_persistor(options[:persistor])

  array = wrap_values(array)

  super(array)

  if @persistor
    @persistor.loaded
  else
    change_state_to(:loaded_state, :loaded, false)
  end
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class Volt::ReactiveArray

Instance Attribute Details

#arrayObject (readonly)

Returns the value of attribute array.



15
16
17
# File 'lib/volt/models/array_model.rb', line 15

def array
  @array
end

#optionsObject (readonly)

Returns the value of attribute options.



15
16
17
# File 'lib/volt/models/array_model.rb', line 15

def options
  @options
end

#parentObject (readonly)

Returns the value of attribute parent.



15
16
17
# File 'lib/volt/models/array_model.rb', line 15

def parent
  @parent
end

#pathObject (readonly)

Returns the value of attribute path.



15
16
17
# File 'lib/volt/models/array_model.rb', line 15

def path
  @path
end

#persistorObject (readonly)

Returns the value of attribute persistor.



15
16
17
# File 'lib/volt/models/array_model.rb', line 15

def persistor
  @persistor
end

Class Method Details

.proxy_to_persistor(*method_names) ⇒ Object

Some methods get passed down to the persistor.



31
32
33
34
35
36
37
38
39
40
41
# File 'lib/volt/models/array_model.rb', line 31

def self.proxy_to_persistor(*method_names)
  method_names.each do |method_name|
    define_method(method_name) do |*args, &block|
      if @persistor.respond_to?(method_name)
        @persistor.send(method_name, *args, &block)
      else
        fail "this model's persistance layer does not support #{method_name}, try using store"
      end
    end
  end
end

.proxy_with_root_dep(*method_names) ⇒ Object

For many methods, we want to call load data as soon as the model is interacted with, so we proxy the method, then call super.



19
20
21
22
23
24
25
26
27
28
# File 'lib/volt/models/array_model.rb', line 19

def self.proxy_with_root_dep(*method_names)
  method_names.each do |method_name|
    define_method(method_name) do |*args|
      # track on the root dep
      persistor.try(:root_dep).try(:depend)

      super(*args)
    end
  end
end

Instance Method Details

#+(*args) ⇒ Object

Make sure it gets wrapped



168
169
170
171
# File 'lib/volt/models/array_model.rb', line 168

def +(*args)
  args = wrap_values(args)
  super(*args)
end

#<<(model) ⇒ Object

Make sure it gets wrapped



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/volt/models/array_model.rb', line 68

def <<(model)
  if model.is_a?(Model)
    # Set the new path
    model.options = @options.merge(path: @options[:path] + [:[]])
  else
    model = wrap_values([model]).first
  end

  if model.is_a?(Model) && !model.can_create?
    raise "permissions did not allow create for #{model.inspect}"
  end

  super(model)

  if @persistor
    promise = @persistor.added(model, @array.size - 1)
    if promise && promise.is_a?(Promise)
      return promise.then do
        # Mark the model as loaded
        model.change_state_to(:loaded_state, :loaded)

        # return the model
        model
      end.fail do |err|
        # remove from the collection because it failed to save on the server
        @array.delete(model)

        # TODO: the model might be in at a different position already, so we should use a full delete
        trigger_removed!(@array.size - 1)
        trigger_size_change!
        #
        # re-raise, err might not be an Error object, so we use a rejected promise to re-raise
        Promise.new.reject(err)
      end
    end
  end

  # Return this model
  Promise.new.resolve(model)
end

#append(model) ⇒ Object

Works like << except it always returns a promise



110
111
112
113
114
115
# File 'lib/volt/models/array_model.rb', line 110

def append(model)
  # Wrap results in a promise
  Promise.new.resolve(nil).then do
    send(:<<, model)
  end
end

#attributesObject



63
64
65
# File 'lib/volt/models/array_model.rb', line 63

def attributes
  self
end

#buffer(attrs = {}) ⇒ Object



204
205
206
207
208
209
210
211
212
# File 'lib/volt/models/array_model.rb', line 204

def buffer(attrs={})
  model_path  = options[:path] + [:[]]
  model_klass = Volt::Model.class_at_path(model_path)

  new_options = options.merge(path: model_path, save_to: self, buffer: true).reject { |k, _| k.to_sym == :persistor }
  model       = model_klass.new(attrs, new_options)

  model
end

#delete(val) ⇒ Object



117
118
119
120
121
122
123
124
125
# File 'lib/volt/models/array_model.rb', line 117

def delete(val)
  # Check to make sure the models are allowed to be deleted
  if !val.is_a?(Model) || val.can_delete?
    result = super
    Promise.new.resolve(result)
  else
    Promise.new.reject("permissions did not allow delete for #{val.inspect}.")
  end
end

#fetch_first(&block) ⇒ Object

returns a promise to fetch the first instance



140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/volt/models/array_model.rb', line 140

def fetch_first(&block)
  persistor = self.persistor

  if persistor && persistor.is_a?(Persistors::ArrayStore)
    # On array store, we wait for the result to be loaded in.
    promise = limit(1).fetch do |res|
      result = res.first

      result
    end
  else
    # On all other persistors, it should be loaded already
    promise = Promise.new.resolve(first)
  end

  # Run any passed in blocks after fetch
  promise = promise.then(&block) if block

  promise
end

#find_one(*args, &block) ⇒ Object

Find one does a query, but only returns the first item or nil if there is no match. Unlike #find, #find_one does not return another cursor that you can call .then on.



130
131
132
# File 'lib/volt/models/array_model.rb', line 130

def find_one(*args, &block)
  find(*args, &block).limit(1)[0]
end

#firstObject



134
135
136
# File 'lib/volt/models/array_model.rb', line 134

def first
  self[0]
end

#inject(*args) ⇒ Object

Make sure it gets wrapped



162
163
164
165
# File 'lib/volt/models/array_model.rb', line 162

def inject(*args)
  args = wrap_values(args)
  super(*args)
end

#inspectObject



191
192
193
194
195
196
197
198
199
200
201
202
# File 'lib/volt/models/array_model.rb', line 191

def inspect
  Computation.run_without_tracking do
    # Track on size
    @size_dep.depend
    str = "#<#{self.class}:#{object_id} #{loaded_state}"
    str += " path:#{path.join('.')}" if path
    # str += " persistor:#{persistor.inspect}" if persistor
    str += " #{@array.inspect}>"

    str
  end
end

#new_array_model(*args) ⇒ Object



177
178
179
# File 'lib/volt/models/array_model.rb', line 177

def new_array_model(*args)
  ArrayModel.new(*args)
end

#new_model(*args) ⇒ Object



173
174
175
# File 'lib/volt/models/array_model.rb', line 173

def new_model(*args)
  Volt::Model.class_at_path(options[:path]).new(*args)
end

#to_aObject

Convert the model to an array all of the way down



182
183
184
185
186
187
188
189
# File 'lib/volt/models/array_model.rb', line 182

def to_a
  @size_dep.depend
  array = []
  attributes.size.times do |index|
    array << deep_unwrap(self[index])
  end
  array
end