api_maker 0.0.1 → 0.0.2
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/app/api_maker/api_helpers/api_maker_helpers.rb +5 -0
- data/app/api_maker/services/can_can/load_abilities.rb +30 -0
- data/app/api_maker/services/devise/sign_in.rb +64 -0
- data/app/api_maker/services/devise/sign_out.rb +9 -0
- data/app/api_maker/services/models/find_or_create_by.rb +18 -0
- data/app/channels/api_maker/subscriptions_channel.rb +33 -2
- data/app/controllers/api_maker/base_controller.rb +7 -3
- data/app/controllers/api_maker/commands_controller.rb +26 -4
- data/app/controllers/api_maker/session_statuses_controller.rb +1 -1
- data/app/services/api_maker/abilities_loader.rb +104 -0
- data/app/services/api_maker/application_service.rb +2 -1
- data/app/services/api_maker/base_command.rb +248 -0
- data/app/services/api_maker/collection_command_service.rb +29 -15
- data/app/services/api_maker/collection_loader.rb +124 -0
- data/app/services/api_maker/command_failed_error.rb +3 -0
- data/app/services/api_maker/command_response.rb +17 -6
- data/app/services/api_maker/command_service.rb +3 -3
- data/app/services/api_maker/create_command.rb +11 -26
- data/app/services/api_maker/create_command_service.rb +3 -3
- data/app/services/api_maker/database_type.rb +9 -0
- data/app/services/api_maker/deep_merge_params.rb +26 -0
- data/app/services/api_maker/deserializer.rb +35 -0
- data/app/services/api_maker/destroy_command.rb +15 -21
- data/app/services/api_maker/destroy_command_service.rb +3 -3
- data/app/services/api_maker/generate_react_native_api_service.rb +3 -19
- data/app/services/api_maker/include_helpers.rb +17 -0
- data/app/services/api_maker/index_command.rb +8 -88
- data/app/services/api_maker/index_command_service.rb +5 -5
- data/app/services/api_maker/js_method_namer_service.rb +1 -1
- data/app/services/api_maker/locals_from_controller.rb +14 -0
- data/app/services/api_maker/member_command_service.rb +15 -13
- data/app/services/api_maker/model_classes_java_script_generator_service.rb +37 -0
- data/app/services/api_maker/model_content_generator_service.rb +17 -21
- data/app/services/api_maker/models/save.rb +29 -0
- data/app/services/api_maker/models_finder_service.rb +6 -2
- data/app/services/api_maker/models_generator_service.rb +6 -43
- data/app/services/api_maker/move_components_to_routes.rb +50 -0
- data/app/services/api_maker/primary_id_for_model.rb +6 -0
- data/app/services/api_maker/reset_indexed_db_service.rb +36 -0
- data/app/services/api_maker/routes_file_reloader.rb +20 -0
- data/app/services/api_maker/select_columns_on_collection.rb +78 -0
- data/app/services/api_maker/select_parser.rb +32 -0
- data/app/services/api_maker/service_command.rb +27 -0
- data/app/services/api_maker/service_command_service.rb +14 -0
- data/app/services/api_maker/simple_model_errors.rb +52 -0
- data/app/services/api_maker/update_command.rb +8 -24
- data/app/services/api_maker/update_command_service.rb +3 -3
- data/app/services/api_maker/valid_command.rb +4 -13
- data/app/services/api_maker/valid_command_service.rb +3 -3
- data/app/services/api_maker/validation_errors_generator_service.rb +146 -0
- data/app/views/api_maker/_data.html.erb +17 -11
- data/config/routes.rb +0 -2
- data/lib/api_maker/ability.rb +22 -7
- data/lib/api_maker/ability_loader.rb +9 -6
- data/lib/api_maker/base_collection_instance.rb +15 -0
- data/lib/api_maker/base_resource.rb +135 -9
- data/lib/api_maker/base_service.rb +14 -0
- data/lib/api_maker/collection_serializer.rb +95 -34
- data/lib/api_maker/command_spec_helper.rb +41 -11
- data/lib/api_maker/configuration.rb +31 -4
- data/lib/api_maker/expect_to_able_to_helper.rb +31 -0
- data/lib/api_maker/individual_command.rb +24 -9
- data/lib/api_maker/javascript/model-template.js.erb +39 -25
- data/lib/api_maker/javascript/models.js.erb +6 -0
- data/lib/api_maker/loader.rb +1 -1
- data/lib/api_maker/memory_storage.rb +1 -1
- data/lib/api_maker/model_extensions.rb +34 -18
- data/lib/api_maker/permitted_params_argument.rb +5 -1
- data/lib/api_maker/preloader.rb +71 -32
- data/lib/api_maker/preloader_base.rb +108 -0
- data/lib/api_maker/preloader_belongs_to.rb +34 -33
- data/lib/api_maker/preloader_has_many.rb +45 -39
- data/lib/api_maker/preloader_has_one.rb +30 -47
- data/lib/api_maker/railtie.rb +3 -11
- data/lib/api_maker/relationship_preloader.rb +42 -0
- data/lib/api_maker/resource_routing.rb +18 -4
- data/lib/api_maker/result_parser.rb +34 -20
- data/lib/api_maker/serializer.rb +53 -22
- data/lib/api_maker/spec_helper/browser_logs.rb +14 -0
- data/lib/api_maker/spec_helper/execute_collection_command.rb +46 -0
- data/lib/api_maker/spec_helper/execute_member_command.rb +52 -0
- data/lib/api_maker/spec_helper/expect_no_browser_errors.rb +18 -0
- data/lib/api_maker/spec_helper/wait_for_expect.rb +20 -0
- data/lib/api_maker/spec_helper/wait_for_flash_message.rb +21 -0
- data/lib/api_maker/spec_helper.rb +112 -48
- data/lib/api_maker/version.rb +1 -1
- data/lib/api_maker.rb +7 -3
- metadata +108 -89
- data/README.md +0 -476
- data/app/controllers/api_maker/devise_controller.rb +0 -60
- data/lib/api_maker/base_command.rb +0 -81
- data/lib/api_maker/javascript/api.js +0 -92
- data/lib/api_maker/javascript/base-model.js +0 -543
- data/lib/api_maker/javascript/bootstrap/attribute-row.jsx +0 -16
- data/lib/api_maker/javascript/bootstrap/attribute-rows.jsx +0 -47
- data/lib/api_maker/javascript/bootstrap/card.jsx +0 -79
- data/lib/api_maker/javascript/bootstrap/checkbox.jsx +0 -127
- data/lib/api_maker/javascript/bootstrap/checkboxes.jsx +0 -105
- data/lib/api_maker/javascript/bootstrap/live-table.jsx +0 -168
- data/lib/api_maker/javascript/bootstrap/money-input.jsx +0 -136
- data/lib/api_maker/javascript/bootstrap/radio-buttons.jsx +0 -80
- data/lib/api_maker/javascript/bootstrap/select.jsx +0 -168
- data/lib/api_maker/javascript/bootstrap/string-input.jsx +0 -203
- data/lib/api_maker/javascript/cable-connection-pool.js +0 -169
- data/lib/api_maker/javascript/cable-subscription-pool.js +0 -111
- data/lib/api_maker/javascript/cable-subscription.js +0 -33
- data/lib/api_maker/javascript/collection.js +0 -186
- data/lib/api_maker/javascript/commands-pool.js +0 -123
- data/lib/api_maker/javascript/custom-error.js +0 -14
- data/lib/api_maker/javascript/deserializer.js +0 -35
- data/lib/api_maker/javascript/devise.js.erb +0 -113
- data/lib/api_maker/javascript/error-logger.js +0 -119
- data/lib/api_maker/javascript/event-connection.jsx +0 -24
- data/lib/api_maker/javascript/event-created.jsx +0 -26
- data/lib/api_maker/javascript/event-destroyed.jsx +0 -26
- data/lib/api_maker/javascript/event-emitter-listener.jsx +0 -32
- data/lib/api_maker/javascript/event-listener.jsx +0 -41
- data/lib/api_maker/javascript/event-updated.jsx +0 -26
- data/lib/api_maker/javascript/form-data-to-object.js +0 -70
- data/lib/api_maker/javascript/included.js +0 -39
- data/lib/api_maker/javascript/key-value-store.js +0 -47
- data/lib/api_maker/javascript/logger.js +0 -23
- data/lib/api_maker/javascript/model-name.js +0 -21
- data/lib/api_maker/javascript/models-response-reader.js +0 -43
- data/lib/api_maker/javascript/paginate.jsx +0 -128
- data/lib/api_maker/javascript/params.js +0 -68
- data/lib/api_maker/javascript/resource-route.jsx +0 -75
- data/lib/api_maker/javascript/resource-routes.jsx +0 -36
- data/lib/api_maker/javascript/result.js +0 -25
- data/lib/api_maker/javascript/session-status-updater.js +0 -113
- data/lib/api_maker/javascript/sort-link.jsx +0 -88
- data/lib/api_maker/javascript/updated-attribute.jsx +0 -60
- data/lib/api_maker/preloader_through.rb +0 -101
- data/lib/api_maker/relationship_includer.rb +0 -42
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
class ApiMaker::LocalsFromController < ApiMaker::ApplicationService
|
|
2
|
+
attr_reader :controller
|
|
3
|
+
|
|
4
|
+
def initialize(controller:)
|
|
5
|
+
@controller = controller
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def perform
|
|
9
|
+
variable_name = :@api_maker_locals
|
|
10
|
+
controller.instance_variable_set(variable_name, {}) unless controller.instance_variable_defined?(variable_name)
|
|
11
|
+
variable = controller.instance_variable_get(variable_name)
|
|
12
|
+
succeed! variable
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -1,22 +1,24 @@
|
|
|
1
1
|
class ApiMaker::MemberCommandService < ApiMaker::CommandService
|
|
2
|
-
def
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
def perform
|
|
3
|
+
ApiMaker::Configuration.profile(-> { "MemberCommand execute: #{model_class.name}##{command_name}" }) do
|
|
4
|
+
ability_name = command_name.to_sym
|
|
5
|
+
collection = model_class.accessible_by(@ability, ability_name).where(model_class.primary_key => ids)
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
7
|
+
constant.execute_in_thread!(
|
|
8
|
+
ability: ability,
|
|
9
|
+
api_maker_args: api_maker_args,
|
|
10
|
+
collection: collection,
|
|
11
|
+
commands: commands,
|
|
12
|
+
command_response: command_response,
|
|
13
|
+
controller: controller
|
|
14
|
+
)
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
succeed!
|
|
17
|
+
end
|
|
16
18
|
end
|
|
17
19
|
|
|
18
20
|
def constant
|
|
19
|
-
@constant ||= "Commands::#{namespace}::#{
|
|
21
|
+
@constant ||= "Commands::#{namespace}::#{command_name.camelize}".constantize
|
|
20
22
|
end
|
|
21
23
|
|
|
22
24
|
def ids
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
class ApiMaker::ModelClassesJavaScriptGeneratorService < ApiMaker::ApplicationService
|
|
2
|
+
def perform
|
|
3
|
+
javascript_code = ""
|
|
4
|
+
resource_names = []
|
|
5
|
+
|
|
6
|
+
models.each do |model|
|
|
7
|
+
next if ignore_model?(model)
|
|
8
|
+
|
|
9
|
+
javascript_code << ApiMaker::ModelContentGeneratorService.execute!(model: model)
|
|
10
|
+
javascript_code << "\n\n"
|
|
11
|
+
|
|
12
|
+
resource = resource_for_model(model)
|
|
13
|
+
resource_names << resource.short_name
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
javascript_code << "export {#{resource_names.sort.join(", ")}}\n"
|
|
17
|
+
|
|
18
|
+
succeed! javascript_code
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def ignore_model?(model)
|
|
22
|
+
model.name.end_with?("::Translation", "::ApplicationRecord")
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def models
|
|
26
|
+
@models ||= ApiMaker::ModelsFinderService.execute!
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def model_file(model)
|
|
30
|
+
resource_class = ApiMaker::MemoryStorage.current.resource_for_model(model)
|
|
31
|
+
api_maker_root_path.join("models", "#{resource_class.short_name.underscore.dasherize}.js")
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def resource_for_model(model)
|
|
35
|
+
ApiMaker::MemoryStorage.current.resource_for_model(model)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -5,11 +5,11 @@ class ApiMaker::ModelContentGeneratorService < ApiMaker::ApplicationService
|
|
|
5
5
|
@model = model
|
|
6
6
|
end
|
|
7
7
|
|
|
8
|
-
def
|
|
8
|
+
def perform
|
|
9
9
|
if resource
|
|
10
|
-
|
|
10
|
+
succeed! model_content
|
|
11
11
|
else
|
|
12
|
-
|
|
12
|
+
fail! "No resource defined for #{model.name}"
|
|
13
13
|
end
|
|
14
14
|
end
|
|
15
15
|
|
|
@@ -17,7 +17,7 @@ private
|
|
|
17
17
|
|
|
18
18
|
def attributes
|
|
19
19
|
resource._attributes.map do |attribute, _data|
|
|
20
|
-
{name: attribute
|
|
20
|
+
{name: attribute}
|
|
21
21
|
end
|
|
22
22
|
end
|
|
23
23
|
|
|
@@ -41,13 +41,6 @@ private
|
|
|
41
41
|
File.join(__dir__, "..", "..", "..", "lib", "api_maker", "javascript", "model-template.js.erb")
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
-
def model_type(attribute_name)
|
|
45
|
-
model_type = model.columns_hash[attribute_name.to_s]&.type
|
|
46
|
-
model_type = :money if monetized_attributes.include?(attribute_name.to_s)
|
|
47
|
-
model_type ||= :unknown
|
|
48
|
-
model_type
|
|
49
|
-
end
|
|
50
|
-
|
|
51
44
|
def monetized_attributes
|
|
52
45
|
@monetized_attributes ||= @model.try(:monetized_attributes).try(:map) { |attribute| attribute[0] } || []
|
|
53
46
|
end
|
|
@@ -55,7 +48,10 @@ private
|
|
|
55
48
|
def reflections
|
|
56
49
|
@reflections ||= resource._relationships.map do |name, _data|
|
|
57
50
|
reflection = model.reflections.values.find { |reflection_i| reflection_i.name == name }
|
|
58
|
-
|
|
51
|
+
|
|
52
|
+
unless reflection
|
|
53
|
+
raise "Couldnt find reflection by that name: #{name} on the model: #{model.name}. Reflections found: #{model.reflections.keys.join(", ")}"
|
|
54
|
+
end
|
|
59
55
|
|
|
60
56
|
reflection
|
|
61
57
|
end
|
|
@@ -66,8 +62,7 @@ private
|
|
|
66
62
|
reflectionName: reflection.name,
|
|
67
63
|
model: "{{this}}",
|
|
68
64
|
modelName: reflection.class_name,
|
|
69
|
-
modelClass: "{{modelClass}}"
|
|
70
|
-
targetPathName: "/api_maker/#{reflection.klass.model_name.route_key}"
|
|
65
|
+
modelClass: "{{modelClass}}"
|
|
71
66
|
}
|
|
72
67
|
end
|
|
73
68
|
|
|
@@ -83,21 +78,22 @@ private
|
|
|
83
78
|
}
|
|
84
79
|
}
|
|
85
80
|
else
|
|
86
|
-
{
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
-
}
|
|
81
|
+
ransack = {"#{reflection.foreign_key}_eq" => "{{id}}"}
|
|
82
|
+
ransack["#{reflection.options[:as]}_type_eq"] = reflection.active_record.name if reflection.options[:as]
|
|
83
|
+
{ransack: ransack}
|
|
91
84
|
end
|
|
92
85
|
end
|
|
93
86
|
|
|
94
87
|
def reflections_for_model_class_data
|
|
95
88
|
@reflections_for_model_class_data ||= reflections.map do |reflection|
|
|
89
|
+
resource = ApiMaker::MemoryStorage.current.resource_for_model(reflection.klass)
|
|
90
|
+
|
|
96
91
|
{
|
|
97
92
|
className: reflection.class_name,
|
|
98
|
-
collectionName:
|
|
93
|
+
collectionName: resource.collection_name,
|
|
99
94
|
name: reflection.name,
|
|
100
|
-
macro: reflection.macro
|
|
95
|
+
macro: reflection.macro,
|
|
96
|
+
resource_name: resource.short_name
|
|
101
97
|
}
|
|
102
98
|
end
|
|
103
99
|
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
class ApiMaker::Models::Save < ApiMaker::ApplicationService
|
|
2
|
+
attr_reader :models, :simple_model_errors
|
|
3
|
+
|
|
4
|
+
def initialize(models:, simple_model_errors: false)
|
|
5
|
+
@models = models
|
|
6
|
+
@simple_model_errors = simple_model_errors
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def perform
|
|
10
|
+
errors = []
|
|
11
|
+
|
|
12
|
+
models.first.transaction do
|
|
13
|
+
models.each do |model|
|
|
14
|
+
next if model.save
|
|
15
|
+
|
|
16
|
+
if simple_model_errors
|
|
17
|
+
errors += ApiMaker::SimpleModelErrors.execute!(model: model)
|
|
18
|
+
else
|
|
19
|
+
errors += models.map(&:errors).map(&:full_messages).flatten
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
raise ActiveRecord::Rollback if errors.any?
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
fail! errors.uniq if errors.any?
|
|
27
|
+
succeed!
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
class ApiMaker::ModelsFinderService < ApiMaker::ApplicationService
|
|
2
|
-
def
|
|
2
|
+
def perform
|
|
3
3
|
ServicePattern::Response.new(result: models)
|
|
4
4
|
end
|
|
5
5
|
|
|
@@ -7,7 +7,7 @@ private
|
|
|
7
7
|
|
|
8
8
|
def models
|
|
9
9
|
result = []
|
|
10
|
-
|
|
10
|
+
files.each do |model_path|
|
|
11
11
|
next unless model_path.start_with?(Rails.root.to_s)
|
|
12
12
|
|
|
13
13
|
path_name = model_path.gsub(/\A#{Regexp.escape(Rails.root.to_s)}\/app\/api_maker\/resources\//, "").gsub(/\.rb\Z/, "")
|
|
@@ -19,4 +19,8 @@ private
|
|
|
19
19
|
|
|
20
20
|
result
|
|
21
21
|
end
|
|
22
|
+
|
|
23
|
+
def files
|
|
24
|
+
@files ||= Dir.glob(Rails.root.join("app/api_maker/resources/**/*_resource.rb"))
|
|
25
|
+
end
|
|
22
26
|
end
|
|
@@ -1,29 +1,14 @@
|
|
|
1
1
|
class ApiMaker::ModelsGeneratorService < ApiMaker::ApplicationService
|
|
2
|
-
def
|
|
2
|
+
def perform
|
|
3
3
|
create_base_structure
|
|
4
4
|
copy_base_model
|
|
5
|
-
copy_base_controllers
|
|
6
|
-
|
|
7
|
-
models.each do |model|
|
|
8
|
-
next if ignore_model?(model)
|
|
9
|
-
|
|
10
|
-
model_content_response = ApiMaker::ModelContentGeneratorService.execute(model: model)
|
|
11
|
-
|
|
12
|
-
if model_content_response.success?
|
|
13
|
-
File.open(model_file(model), "w") { |fp| fp.write(model_content_response.result) }
|
|
14
|
-
else
|
|
15
|
-
puts model_content_response.errors.join(". ")
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
5
|
|
|
19
6
|
ApiMaker::GenerateReactNativeApiService.execute! if ApiMaker::Configuration.current.react_native_path.present?
|
|
20
|
-
|
|
7
|
+
succeed!
|
|
21
8
|
end
|
|
22
9
|
|
|
23
10
|
def ignore_model?(model)
|
|
24
|
-
model.name.end_with?("::Translation")
|
|
25
|
-
model.name.start_with?("ActiveStorage::") ||
|
|
26
|
-
model.name.end_with?("::ApplicationRecord")
|
|
11
|
+
model.name.end_with?("::Translation", "::ApplicationRecord")
|
|
27
12
|
end
|
|
28
13
|
|
|
29
14
|
def models
|
|
@@ -33,31 +18,15 @@ class ApiMaker::ModelsGeneratorService < ApiMaker::ApplicationService
|
|
|
33
18
|
private
|
|
34
19
|
|
|
35
20
|
def api_maker_root_path
|
|
36
|
-
Rails.root.join("app
|
|
21
|
+
Rails.root.join("app/javascript/api-maker")
|
|
37
22
|
end
|
|
38
23
|
|
|
39
24
|
def controller_path
|
|
40
|
-
Rails.root.join("app
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
def copy_base_controllers
|
|
44
|
-
files = %w[devise_controller.rb]
|
|
45
|
-
path = File.join(__dir__, "..", "..", "controllers", "api_maker")
|
|
46
|
-
target_path = Rails.root.join("app", "controllers", "api_maker")
|
|
47
|
-
|
|
48
|
-
copy_base_files(files, path, target_path)
|
|
25
|
+
Rails.root.join("app/controllers/api_maker")
|
|
49
26
|
end
|
|
50
27
|
|
|
51
28
|
def copy_base_model
|
|
52
|
-
files = %w[
|
|
53
|
-
api.js base-model.js cable-connection-pool.js cable-subscription.js cable-subscription-pool.js collection.js
|
|
54
|
-
commands-pool.js event-created.jsx custom-error.js deserializer.js devise.js event-destroyed.jsx event-emitter-listener.jsx event-listener.jsx
|
|
55
|
-
event-updated.jsx error-logger.js form-data-to-object.js included.js key-value-store.js logger.js model-name.js models-response-reader.js
|
|
56
|
-
params.js result.js event-connection.jsx paginate.jsx sort-link.jsx updated-attribute.jsx resource-routes.jsx resource-route.jsx
|
|
57
|
-
session-status-updater.js bootstrap/attribute-row.jsx bootstrap/attribute-rows.jsx bootstrap/card.jsx
|
|
58
|
-
bootstrap/checkbox.jsx bootstrap/checkboxes.jsx bootstrap/money-input.jsx bootstrap/radio-buttons.jsx
|
|
59
|
-
bootstrap/select.jsx bootstrap/string-input.jsx bootstrap/live-table.jsx
|
|
60
|
-
]
|
|
29
|
+
files = %w[models.js.erb]
|
|
61
30
|
path = File.join(__dir__, "..", "..", "..", "lib", "api_maker", "javascript")
|
|
62
31
|
target_path = api_maker_root_path
|
|
63
32
|
|
|
@@ -93,12 +62,6 @@ private
|
|
|
93
62
|
# Dont remove all the files. It messes up running Webpack Dev Servers which forces you to restart all the time.
|
|
94
63
|
# FileUtils.rm_rf(api_maker_root_path) if File.exist?(api_maker_root_path)
|
|
95
64
|
|
|
96
|
-
FileUtils.mkdir_p(api_maker_root_path.join("models"))
|
|
97
65
|
FileUtils.mkdir_p(controller_path) unless File.exist?(controller_path)
|
|
98
66
|
end
|
|
99
|
-
|
|
100
|
-
def model_file(model)
|
|
101
|
-
resource_class = ApiMaker::MemoryStorage.current.resource_for_model(model)
|
|
102
|
-
api_maker_root_path.join("models", "#{resource_class.short_name.underscore.dasherize}.js")
|
|
103
|
-
end
|
|
104
67
|
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
class ApiMaker::MoveComponentsToRoutes < ApplicationService
|
|
2
|
+
attr_reader :prepend_path, :routes_path
|
|
3
|
+
|
|
4
|
+
def initialize(prepend_path:, routes_path:)
|
|
5
|
+
@prepend_path = prepend_path
|
|
6
|
+
@routes_path = routes_path
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def perform
|
|
10
|
+
routes.each do |route|
|
|
11
|
+
path = "#{prepend_path}#{route.fetch("component")}"
|
|
12
|
+
full_path = "app/javascript/components/#{path}"
|
|
13
|
+
new_path = "app/javascript/routes/#{path}"
|
|
14
|
+
|
|
15
|
+
full_path_with_jsx = "#{full_path}.jsx"
|
|
16
|
+
new_path_with_jsx = "#{new_path}.jsx"
|
|
17
|
+
|
|
18
|
+
if !File.exist?(full_path_with_jsx) && File.exist?("#{full_path}/index.jsx")
|
|
19
|
+
full_path_with_jsx = "#{full_path}/index.jsx"
|
|
20
|
+
new_path_with_jsx = "#{new_path}/index.jsx"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
if File.exist?(full_path_with_jsx)
|
|
24
|
+
new_dir = File.dirname(new_path_with_jsx)
|
|
25
|
+
FileUtils.mkdir_p(new_dir) unless File.exist?(new_dir)
|
|
26
|
+
File.rename(full_path_with_jsx, new_path_with_jsx)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
old_dir = File.dirname(full_path_with_jsx)
|
|
30
|
+
|
|
31
|
+
Dir.unlink(old_dir) if File.exist?(old_dir) && dir_empty?(old_dir)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
succeed!
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def routes
|
|
38
|
+
@routes = JSON.parse(File.read(routes_path)).fetch("routes")
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def dir_empty?(path)
|
|
42
|
+
Dir.foreach(path) do |file|
|
|
43
|
+
next if file == "." || file == ".."
|
|
44
|
+
|
|
45
|
+
return false
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
true
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
class ApiMaker::ResetIndexedDbService < ApiMaker::ApplicationService
|
|
2
|
+
attr_reader :context
|
|
3
|
+
|
|
4
|
+
delegate :browser_firefox?, :browser_logs, :execute_script, to: :context
|
|
5
|
+
|
|
6
|
+
def initialize(context:)
|
|
7
|
+
@context = context
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def perform
|
|
11
|
+
# Firefox doesnt support 'indexedDB.databases()'
|
|
12
|
+
reset_indexed_db unless browser_firefox?
|
|
13
|
+
|
|
14
|
+
succeed!
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def reset_indexed_db
|
|
18
|
+
execute_script "
|
|
19
|
+
indexedDB.databases().then(function(databases) {
|
|
20
|
+
var promises = []
|
|
21
|
+
for(var database of databases) {
|
|
22
|
+
promises.push(indexedDB.deleteDatabase(database.name))
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
Promise.all(promises).then(function() {
|
|
26
|
+
console.error('All databases were deleted')
|
|
27
|
+
})
|
|
28
|
+
})
|
|
29
|
+
"
|
|
30
|
+
|
|
31
|
+
WaitUtil.wait_for_condition("databases to be deleted", delay_sec: 0.2, timeout_sec: 6) do
|
|
32
|
+
logs_text = browser_logs.map(&:message).join("\n")
|
|
33
|
+
logs_text.include?("\"All databases were deleted\"")
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
class ApiMaker::RoutesFileReloader < ApiMaker::ApplicationService
|
|
2
|
+
attr_reader :file_paths
|
|
3
|
+
|
|
4
|
+
def initialize(file_paths:)
|
|
5
|
+
@file_paths = file_paths
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def perform
|
|
9
|
+
reloader = Rails.application.config.file_watcher.new(file_paths) do
|
|
10
|
+
Rails.application.reload_routes!
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
Rails.application.reloaders << reloader
|
|
14
|
+
Rails.application.reloader.to_run do
|
|
15
|
+
reloader.execute_if_updated
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
succeed!
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
class ApiMaker::SelectColumnsOnCollection < ApiMaker::ApplicationService
|
|
2
|
+
attr_reader :collection, :model_class, :select_attributes, :select_columns, :table_name
|
|
3
|
+
|
|
4
|
+
def initialize(collection:, model_class: nil, select_attributes:, select_columns:, table_name: nil)
|
|
5
|
+
raise "No collection was given" unless collection
|
|
6
|
+
|
|
7
|
+
@collection = collection
|
|
8
|
+
@model_class = model_class || collection.model
|
|
9
|
+
@select_attributes = select_attributes&.dig(@model_class)
|
|
10
|
+
@select_columns = select_columns
|
|
11
|
+
@table_name = table_name || @model_class.table_name
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def perform
|
|
15
|
+
new_collection = collection
|
|
16
|
+
return succeed! new_collection if new_collection.is_a?(Array)
|
|
17
|
+
|
|
18
|
+
arel_table = Arel::Table.new(@table_name)
|
|
19
|
+
|
|
20
|
+
if selected_columns
|
|
21
|
+
all_columns_to_select.each do |column_name|
|
|
22
|
+
validate_column_name!(column_name)
|
|
23
|
+
new_collection = new_collection.select(arel_table[column_name])
|
|
24
|
+
end
|
|
25
|
+
else
|
|
26
|
+
new_collection = prepend_table_wildcard(new_collection) unless table_wildcard_prepended?(new_collection)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
succeed! new_collection
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Selected attributes might require columns to be selected which is automatically resolved here
|
|
33
|
+
def all_columns_to_select
|
|
34
|
+
required_columns = []
|
|
35
|
+
|
|
36
|
+
select_attributes&.each_value do |attribute_args|
|
|
37
|
+
requires_columns = attribute_args.dig(:args, :requires_columns)
|
|
38
|
+
required_columns += requires_columns if requires_columns
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
(selected_columns + required_columns).map(&:to_s).uniq
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def param_name
|
|
45
|
+
@param_name ||= model_class.model_name.param_key
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Prepends 'table_name.*' to the query. It needs to be pre-pended in case a `COUNT` or another aggregate function has been added to work with `DISTINCT`.
|
|
49
|
+
def prepend_table_wildcard(query)
|
|
50
|
+
old_select = query.values[:select] || []
|
|
51
|
+
old_select = old_select.keep_if { |select_statement| select_statement != select_table_wildcard_sql }
|
|
52
|
+
|
|
53
|
+
query = query.except(:select).select(select_table_wildcard_sql)
|
|
54
|
+
|
|
55
|
+
old_select.each do |select_statement|
|
|
56
|
+
query = query.select(select_statement)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
query
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def selected_columns
|
|
63
|
+
@selected_columns ||= select_columns&.dig(param_name)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def select_table_wildcard_sql
|
|
67
|
+
@select_table_wildcard_sql ||= "#{table_name}.*"
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def table_wildcard_prepended?(query)
|
|
71
|
+
query.values[:select]&.first == select_table_wildcard_sql
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Checks that the given column exists to avoid injections
|
|
75
|
+
def validate_column_name!(column_name)
|
|
76
|
+
raise "Invalid column on #{model_class.name}: #{column_name}" unless model_class.columns_hash.key?(column_name.to_s)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
class ApiMaker::SelectParser < ApiMaker::ApplicationService
|
|
2
|
+
attr_reader :select
|
|
3
|
+
|
|
4
|
+
def initialize(select:)
|
|
5
|
+
@select = select
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def perform
|
|
9
|
+
new_select = {}
|
|
10
|
+
|
|
11
|
+
select.each do |model_collection_name, attributes|
|
|
12
|
+
model_class = model_collection_name.underscore.singularize.camelize
|
|
13
|
+
resource = "Resources::#{model_class}Resource".safe_constantize
|
|
14
|
+
raise "Resource not found for: #{model_collection_name}" unless resource
|
|
15
|
+
|
|
16
|
+
selects = {}
|
|
17
|
+
new_select[resource.model_class] ||= selects
|
|
18
|
+
resource_attributes = resource._attributes_with_string_keys
|
|
19
|
+
|
|
20
|
+
attributes.each do |attribute|
|
|
21
|
+
resource_attribute = resource_attributes[attribute]
|
|
22
|
+
raise "Attribute not found on the #{resource.short_name} resource: #{attribute}" unless resource_attribute
|
|
23
|
+
|
|
24
|
+
selects[attribute.to_sym] = resource_attribute
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
new_select[resource.model_class] = selects
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
succeed! new_select
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
class ApiMaker::ServiceCommand < ApiMaker::BaseCommand
|
|
2
|
+
def execute!
|
|
3
|
+
service_name = args.fetch(:service_name)
|
|
4
|
+
|
|
5
|
+
ApiMaker::Configuration.profile(-> { "ServiceCommand: #{service_name}" }) do
|
|
6
|
+
service_constant_name = "Services::#{service_name}"
|
|
7
|
+
service_constant = service_constant_name.constantize
|
|
8
|
+
service_args = args.fetch(:service_args)&.permit!&.to_h
|
|
9
|
+
response = service_constant.execute(
|
|
10
|
+
ability: current_ability,
|
|
11
|
+
args: service_args,
|
|
12
|
+
api_maker_args: api_maker_args,
|
|
13
|
+
controller: controller
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
if response.success?
|
|
17
|
+
succeed!(response.result)
|
|
18
|
+
else
|
|
19
|
+
errors = response.errors.map do |error|
|
|
20
|
+
{message: error.message, type: error.type}
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
fail!(errors: errors)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
class ApiMaker::ServiceCommandService < ApiMaker::CommandService
|
|
2
|
+
def perform
|
|
3
|
+
ApiMaker::ServiceCommand.execute_in_thread!(
|
|
4
|
+
ability: ability,
|
|
5
|
+
api_maker_args: api_maker_args,
|
|
6
|
+
collection: nil,
|
|
7
|
+
commands: commands,
|
|
8
|
+
command_response: command_response,
|
|
9
|
+
controller: controller
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
succeed!
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
class ApiMaker::SimpleModelErrors < ApiMaker::ApplicationService
|
|
2
|
+
attr_reader :additional_attributes, :errors, :model, :models_inspected
|
|
3
|
+
|
|
4
|
+
def initialize(additional_attributes: [], model:)
|
|
5
|
+
@additional_attributes = additional_attributes
|
|
6
|
+
@model = model
|
|
7
|
+
@errors = []
|
|
8
|
+
@models_inspected = []
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def perform
|
|
12
|
+
inspect_model(model)
|
|
13
|
+
succeed! errors
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def inspect_model(model_to_inspect)
|
|
17
|
+
return if models_inspected.include?(model_to_inspect)
|
|
18
|
+
|
|
19
|
+
model_to_inspect.valid? if model_to_inspect.errors.empty? # Generates the errors on the model so we can detect them
|
|
20
|
+
models_inspected << model_to_inspect
|
|
21
|
+
|
|
22
|
+
model_to_inspect.errors.messages.each do |attribute_name, attribute_errors|
|
|
23
|
+
if attribute_name == :base
|
|
24
|
+
@errors += attribute_errors
|
|
25
|
+
else
|
|
26
|
+
next if model_to_inspect.attribute_names.exclude?(attribute_name.to_s) && additional_attributes.exclude?(attribute_name)
|
|
27
|
+
|
|
28
|
+
attribute_errors.each do |message|
|
|
29
|
+
errors << "#{model_to_inspect.class.human_attribute_name(attribute_name)} #{message}"
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
collect_errors_from_associations(model_to_inspect)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def collect_errors_from_associations(model_to_scan_reflections_on)
|
|
40
|
+
model_to_scan_reflections_on._reflections.each_key do |association_name|
|
|
41
|
+
target = model_to_scan_reflections_on.association(association_name.to_sym).target
|
|
42
|
+
|
|
43
|
+
if target.is_a?(ActiveRecord::Base)
|
|
44
|
+
inspect_model(target)
|
|
45
|
+
else
|
|
46
|
+
target&.each do |sub_model|
|
|
47
|
+
inspect_model(sub_model)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|