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
|
@@ -1,93 +1,133 @@
|
|
|
1
1
|
# Provides a method to setup a field on a model.
|
|
2
|
-
module
|
|
3
|
-
|
|
2
|
+
module Volt
|
|
3
|
+
module FieldHelpers
|
|
4
|
+
class InvalidFieldClass < RuntimeError; end
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
NUMERIC_CAST = lambda do |convert_method, val|
|
|
7
|
+
begin
|
|
8
|
+
orig = val
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
val = send(convert_method, val)
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
if RUBY_PLATFORM == 'opal'
|
|
13
|
+
# Opal has a bug in 0.7.2 that gives us back NaN without an
|
|
14
|
+
# error sometimes.
|
|
15
|
+
val = orig if val.nan?
|
|
16
|
+
end
|
|
17
|
+
rescue TypeError, ArgumentError => e
|
|
18
|
+
# ignore, unmatched types will be caught below.
|
|
19
|
+
val = orig
|
|
15
20
|
end
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
val = orig
|
|
21
|
+
|
|
22
|
+
return val
|
|
19
23
|
end
|
|
20
24
|
|
|
21
|
-
|
|
22
|
-
|
|
25
|
+
FIELD_CASTS = {
|
|
26
|
+
String => :to_s.to_proc,
|
|
27
|
+
Fixnum => lambda {|val| NUMERIC_CAST[:Integer, val] },
|
|
28
|
+
Numeric => lambda {|val| NUMERIC_CAST[:Float, val] },
|
|
29
|
+
Float => lambda {|val| NUMERIC_CAST[:Float, val] },
|
|
30
|
+
TrueClass => nil,
|
|
31
|
+
FalseClass => nil,
|
|
32
|
+
NilClass => nil,
|
|
33
|
+
Volt::Boolean => nil
|
|
34
|
+
}
|
|
23
35
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
# field lets you declare your fields instead of using the underscore syntax.
|
|
39
|
-
# An optional class restriction can be passed in.
|
|
40
|
-
def field(name, klasses = nil, options = {})
|
|
41
|
-
if klasses
|
|
42
|
-
klasses = [klasses].flatten
|
|
43
|
-
|
|
44
|
-
unless klasses.any? {|kl| FIELD_CASTS.key?(kl) }
|
|
45
|
-
klass_names = FIELD_CASTS.keys.map(&:to_s).join(', ')
|
|
46
|
-
msg = "valid field types is currently limited to #{klass_names}, you passed: #{klasses.inspect}"
|
|
47
|
-
fail FieldHelpers::InvalidFieldClass, msg
|
|
48
|
-
end
|
|
36
|
+
# If VoltTime has already been required by the time we load this class, we
|
|
37
|
+
# add it to the field casts:
|
|
38
|
+
if defined?(VoltTime)
|
|
39
|
+
FIELD_CASTS[VoltTime] = nil
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
module ClassMethods
|
|
43
|
+
# field lets you declare your fields instead of using the underscore syntax.
|
|
44
|
+
# An optional class restriction can be passed in.
|
|
45
|
+
|
|
46
|
+
def field(name, klasses = nil, options = {})
|
|
47
|
+
name = name.to_sym
|
|
48
|
+
if klasses
|
|
49
|
+
klasses = [klasses].flatten
|
|
49
50
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
unless klasses.any? {|kl| FIELD_CASTS.key?(kl) }
|
|
52
|
+
klass_names = FIELD_CASTS.keys.map(&:to_s).join(', ')
|
|
53
|
+
msg = "valid field types is currently limited to #{klass_names}, you passed: #{klasses.inspect}"
|
|
54
|
+
fail FieldHelpers::InvalidFieldClass, msg
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# defined in associations.rb
|
|
58
|
+
check_name_in_use(name)
|
|
59
|
+
|
|
60
|
+
# Add NilClass as an allowed type unless nil: false was passed.
|
|
61
|
+
unless options[:nil] == false
|
|
62
|
+
options.delete(:nil)
|
|
63
|
+
klasses << NilClass
|
|
64
|
+
end
|
|
53
65
|
end
|
|
54
|
-
end
|
|
55
66
|
|
|
56
|
-
|
|
57
|
-
|
|
67
|
+
# Normalize default
|
|
68
|
+
options.delete(:default) if options[:default] == nil
|
|
58
69
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
unless klasses.include?(String)
|
|
63
|
-
validate name, type: klasses
|
|
70
|
+
# Store the field defaults
|
|
71
|
+
if (default_val = options[:default])
|
|
72
|
+
self.defaults[name] = default_val
|
|
64
73
|
end
|
|
65
|
-
end
|
|
66
74
|
|
|
67
|
-
|
|
68
|
-
get(name)
|
|
69
|
-
end
|
|
75
|
+
self.fields[name] = [klasses, options]
|
|
70
76
|
|
|
71
|
-
define_method(:"#{name}=") do |val|
|
|
72
|
-
# Check if the value assigned matches the class restriction
|
|
73
77
|
if klasses
|
|
74
|
-
#
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
78
|
+
# Add type validation, execpt for String, since anything can be cast to
|
|
79
|
+
# a string.
|
|
80
|
+
unless klasses.include?(String)
|
|
81
|
+
validate name, type: klasses
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
# define the fields getter
|
|
87
|
+
define_method(name) do
|
|
88
|
+
get(name)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
define_method(:"#{name}=") do |val|
|
|
92
|
+
# Check if the value assigned matches the class restriction
|
|
93
|
+
if klasses
|
|
94
|
+
# Cast to the right type
|
|
95
|
+
klasses.each do |kl|
|
|
96
|
+
if (func = FIELD_CASTS[kl])
|
|
97
|
+
# Cast on the first available caster
|
|
98
|
+
val = func[val]
|
|
99
|
+
break
|
|
100
|
+
end
|
|
80
101
|
end
|
|
81
102
|
end
|
|
103
|
+
|
|
104
|
+
set(name, val)
|
|
82
105
|
end
|
|
106
|
+
end
|
|
83
107
|
|
|
84
|
-
|
|
108
|
+
def index(columns, options={})
|
|
109
|
+
# Columns is stored in an array
|
|
110
|
+
columns = [columns].flatten.map {|c| c.to_sym }
|
|
111
|
+
|
|
112
|
+
options[:columns] = columns
|
|
113
|
+
|
|
114
|
+
# Add in default name
|
|
115
|
+
name = (options.delete(:name) || "#{collection_name}_#{columns.join('_')}_index").to_sym
|
|
116
|
+
self.indexes[name] = options
|
|
85
117
|
end
|
|
86
118
|
end
|
|
87
|
-
end
|
|
88
119
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
120
|
+
def self.included(base)
|
|
121
|
+
base.class_attribute :fields
|
|
122
|
+
base.fields = {}
|
|
123
|
+
|
|
124
|
+
base.class_attribute :indexes
|
|
125
|
+
base.indexes = {}
|
|
126
|
+
|
|
127
|
+
base.class_attribute :defaults
|
|
128
|
+
base.defaults = {}
|
|
129
|
+
|
|
130
|
+
base.send :extend, ClassMethods
|
|
131
|
+
end
|
|
92
132
|
end
|
|
93
133
|
end
|
|
@@ -84,7 +84,6 @@ module Volt
|
|
|
84
84
|
# process_class_name is defined by Model/ArrayModel as
|
|
85
85
|
# singularize/pluralize
|
|
86
86
|
klass_name = process_class_name(klass_name = path[index]).camelize
|
|
87
|
-
|
|
88
87
|
begin
|
|
89
88
|
# Lookup the class
|
|
90
89
|
klass = Object.const_get(klass_name)
|
|
@@ -121,6 +120,14 @@ module Volt
|
|
|
121
120
|
|
|
122
121
|
def self.included(base)
|
|
123
122
|
base.send :extend, ClassMethods
|
|
123
|
+
# Used for testing
|
|
124
|
+
def base.temporary
|
|
125
|
+
@temporary = true
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def base.is_temporary
|
|
129
|
+
@temporary
|
|
130
|
+
end
|
|
124
131
|
end
|
|
125
132
|
|
|
126
133
|
end
|
|
@@ -5,7 +5,9 @@ module Volt
|
|
|
5
5
|
module Helpers
|
|
6
6
|
module ChangeHelpers
|
|
7
7
|
def self.included(base)
|
|
8
|
-
base.setup_action_helpers_in_class(
|
|
8
|
+
base.setup_action_helpers_in_class(
|
|
9
|
+
:before_create, :before_update, :before_save, :before_validate
|
|
10
|
+
)
|
|
9
11
|
end
|
|
10
12
|
|
|
11
13
|
# Called when something in the model changes. Saves
|
|
@@ -18,10 +20,23 @@ module Volt
|
|
|
18
20
|
# no_validate mode should only be used internally. no_validate mode is a
|
|
19
21
|
# performance optimization that prevents validation from running after each
|
|
20
22
|
# change when assigning multile attributes.
|
|
21
|
-
|
|
23
|
+
if Volt.in_mode?(:no_validate)
|
|
24
|
+
# Didn't run validations, return the model
|
|
25
|
+
self.then
|
|
26
|
+
else
|
|
22
27
|
# Run the validations for all fields
|
|
23
28
|
result = nil
|
|
24
29
|
return validate!.then do
|
|
30
|
+
# Buffers only persist on .save!
|
|
31
|
+
if buffer?
|
|
32
|
+
nil
|
|
33
|
+
else
|
|
34
|
+
# valid model. Save, then return the model
|
|
35
|
+
persist_changes(attribute_name)
|
|
36
|
+
end.then { self }
|
|
37
|
+
# ^ return the model
|
|
38
|
+
end.fail do |errors|
|
|
39
|
+
# invalid model
|
|
25
40
|
# Buffers are allowed to be in an invalid state
|
|
26
41
|
unless buffer?
|
|
27
42
|
# First check that all local validations pass. Any time any
|
|
@@ -29,27 +44,24 @@ module Volt
|
|
|
29
44
|
# persist. However, we want to be able to move the model
|
|
30
45
|
# towards a valid state one change at a time.
|
|
31
46
|
if error_in_changed_attributes?
|
|
32
|
-
# Some errors are present
|
|
47
|
+
# Some errors are present in something that we changed.
|
|
33
48
|
revert_changes!
|
|
34
49
|
|
|
35
|
-
# After we revert, we need to validate again to get the error
|
|
50
|
+
# After we revert, we need to validate again to get the error
|
|
51
|
+
# messages back.
|
|
36
52
|
# TODO: Could probably cache the previous errors.
|
|
37
53
|
result = validate!.then do
|
|
38
54
|
# Reject the promise with the errors
|
|
39
55
|
Promise.new.reject(errs)
|
|
40
56
|
end
|
|
41
57
|
else
|
|
42
|
-
result = persist_changes(attribute_name)
|
|
58
|
+
result = persist_changes(attribute_name).then
|
|
43
59
|
end
|
|
44
60
|
end
|
|
45
61
|
|
|
46
|
-
|
|
47
|
-
result.then { self }
|
|
62
|
+
result
|
|
48
63
|
end
|
|
49
64
|
end
|
|
50
|
-
|
|
51
|
-
# Didn't run validations
|
|
52
|
-
self.then
|
|
53
65
|
end
|
|
54
66
|
|
|
55
67
|
|
|
@@ -66,8 +78,15 @@ module Volt
|
|
|
66
78
|
# skip validations when running before_save, this prevents n+1, and allows
|
|
67
79
|
# the before_save to put the model into an invalid state, which you want
|
|
68
80
|
# sometimes.
|
|
69
|
-
|
|
70
|
-
|
|
81
|
+
unless buffer?
|
|
82
|
+
Volt::Model.no_validate do
|
|
83
|
+
if new?
|
|
84
|
+
run_callbacks(:before_create)
|
|
85
|
+
else
|
|
86
|
+
run_callbacks(:before_update)
|
|
87
|
+
end
|
|
88
|
+
run_callbacks(:before_save)
|
|
89
|
+
end
|
|
71
90
|
end
|
|
72
91
|
|
|
73
92
|
# the changed method on a persistor should return a promise that will
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module Volt
|
|
2
|
+
module Models
|
|
3
|
+
module Helpers
|
|
4
|
+
module Defaults
|
|
5
|
+
def setup_defaults
|
|
6
|
+
self.class.defaults.each_pair do |field_name, default_value|
|
|
7
|
+
unless @attributes.has_key?(field_name)
|
|
8
|
+
@attributes[field_name] = default_value
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
data/lib/volt/models/location.rb
CHANGED
|
@@ -1,9 +1,23 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
module Volt
|
|
2
|
+
class Location
|
|
3
|
+
def host
|
|
4
|
+
if RUBY_PLATFORM == 'opal'
|
|
5
|
+
`document.location.host`
|
|
6
|
+
else
|
|
7
|
+
Volt.config.domain
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def protocol
|
|
12
|
+
scheme + ':'
|
|
13
|
+
end
|
|
5
14
|
|
|
6
|
-
|
|
7
|
-
|
|
15
|
+
def scheme
|
|
16
|
+
if RUBY_PLATFORM == 'opal'
|
|
17
|
+
`document.location.protocol`[0..-2]
|
|
18
|
+
else
|
|
19
|
+
Volt.config.scheme || 'http'
|
|
20
|
+
end
|
|
21
|
+
end
|
|
8
22
|
end
|
|
9
23
|
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# This is the base class for migrations.
|
|
2
|
+
require 'volt/reactive/eventable'
|
|
3
|
+
|
|
4
|
+
module Volt
|
|
5
|
+
class Migration
|
|
6
|
+
extend Eventable
|
|
7
|
+
def self.inherited(klass)
|
|
8
|
+
trigger!('inherited', klass)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def store
|
|
12
|
+
Volt.current_app.store
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def up
|
|
16
|
+
raise "An up migration was not provided"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def down
|
|
20
|
+
raise "A down migration was not provided"
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# The migration runner runs the migrations and tracks the versions that have
|
|
2
|
+
# been run.
|
|
3
|
+
require 'volt/models/migrations/migration'
|
|
4
|
+
|
|
5
|
+
module Volt
|
|
6
|
+
class DuplicateMigrationTimestamp < RuntimeError ; end
|
|
7
|
+
|
|
8
|
+
class MigrationRunner
|
|
9
|
+
# The args are passed to each Volt::Migration, (typically just the @db)
|
|
10
|
+
def initialize(*args)
|
|
11
|
+
@args = args
|
|
12
|
+
ensure_migration_versions_table
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Runs all migrations up
|
|
16
|
+
def run(direction=:up, util_version=nil)
|
|
17
|
+
# Get the disk versions
|
|
18
|
+
disk_version_paths = self.disk_versions
|
|
19
|
+
disk_versions = disk_version_paths.map {|v| v[0] }
|
|
20
|
+
|
|
21
|
+
# Get the db versions
|
|
22
|
+
ran_versions = self.all_versions
|
|
23
|
+
|
|
24
|
+
if direction == :up
|
|
25
|
+
# Run all that are on disk, but haven't been run (from the db)
|
|
26
|
+
need_to_run_versions = disk_versions - ran_versions
|
|
27
|
+
|
|
28
|
+
if util_version
|
|
29
|
+
# remove any versions > the util_version, since the user is saying run
|
|
30
|
+
# "up" migrations until we hit version X
|
|
31
|
+
need_to_run_versions.reject! {|version| version > util_version }
|
|
32
|
+
end
|
|
33
|
+
else
|
|
34
|
+
# Run down on all versions that are in the db. If the file doesn't exist
|
|
35
|
+
need_to_run_versions = ran_versions
|
|
36
|
+
|
|
37
|
+
if util_version
|
|
38
|
+
# remove any versions < the util_version, since the user is saying run
|
|
39
|
+
# "up" migrations until we hit version X
|
|
40
|
+
need_to_run_versions.reject! {|version| version < util_version }
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
need_to_run_versions.each do |version|
|
|
45
|
+
path = disk_version_paths[version]
|
|
46
|
+
|
|
47
|
+
unless path
|
|
48
|
+
raise "The database has a migration version of #{version}, but no matching migration file could be found for the down migration"
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
run_migration(path, direction)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Grab the version numbers and files for each migration on disk. Raises an
|
|
56
|
+
# exception if two migrations have the same number
|
|
57
|
+
def disk_versions
|
|
58
|
+
versions = {}
|
|
59
|
+
Dir["#{Volt.root}/config/db/migrations/*.rb"].map do |path|
|
|
60
|
+
version = version_for_path(path)
|
|
61
|
+
|
|
62
|
+
if (path2 = versions[version])
|
|
63
|
+
raise DuplicateMigrationTimestamp, "Two migrations have the same version number: #{path} and #{path2}"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
versions[version] = path
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
versions
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def version_for_path(path)
|
|
73
|
+
File.basename(path)[/^[0-9]+/].to_i
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Get the number for all versions that have been run
|
|
77
|
+
def ran_versions
|
|
78
|
+
migration_versions.all.sync.map {|v| v.version }
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def run_migration(path, direction=:up)
|
|
82
|
+
Volt.logger.info("Run #{direction} migration #{File.basename(path)}")
|
|
83
|
+
version = version_for_path(path)
|
|
84
|
+
|
|
85
|
+
# When we require, we use the inherited callback to figure out what class
|
|
86
|
+
# was loaded.
|
|
87
|
+
migration_klass = nil
|
|
88
|
+
listener = Volt::Migration.on('inherited') do |klass|
|
|
89
|
+
migration_klass = klass
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
require(path)
|
|
93
|
+
|
|
94
|
+
# Remove the inherited listener
|
|
95
|
+
listener.remove
|
|
96
|
+
|
|
97
|
+
unless migration_klass
|
|
98
|
+
raise "No class inheriting from Volt::Migration was defined in #{path}"
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
unless [:up, :down].include?(direction)
|
|
102
|
+
raise "Only up and down migrations are supported"
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Run the up migration
|
|
106
|
+
migration_klass.new(*@args).send(direction)
|
|
107
|
+
|
|
108
|
+
# Remove the object
|
|
109
|
+
Object.send(:remove_const, migration_klass.name.to_sym)
|
|
110
|
+
|
|
111
|
+
# Remove the require
|
|
112
|
+
$LOADED_FEATURES.reject! {|p| p == path }
|
|
113
|
+
|
|
114
|
+
if direction == :up
|
|
115
|
+
# Track that it ran
|
|
116
|
+
add_version(version)
|
|
117
|
+
else
|
|
118
|
+
# Remove that it ran
|
|
119
|
+
remove_version(version)
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Implement the following in your data provider to allow migrations. We
|
|
124
|
+
# can't use Volt::Model until after the reconcile step has happened, so
|
|
125
|
+
# these methods need to work directly with the database.
|
|
126
|
+
def ensure_migration_versions_table
|
|
127
|
+
raise "not implemented"
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def add_version(version)
|
|
131
|
+
raise "not implemented"
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def has_version?(version)
|
|
135
|
+
raise "not implemented"
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def remove_version(version)
|
|
139
|
+
raise "not implemented"
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def all_versions
|
|
143
|
+
raise "not implemented"
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|