api_maker 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (135) hide show
  1. checksums.yaml +4 -4
  2. data/app/api_maker/api_helpers/api_maker_helpers.rb +5 -0
  3. data/app/api_maker/services/can_can/load_abilities.rb +30 -0
  4. data/app/api_maker/services/devise/sign_in.rb +64 -0
  5. data/app/api_maker/services/devise/sign_out.rb +9 -0
  6. data/app/api_maker/services/models/find_or_create_by.rb +18 -0
  7. data/app/channels/api_maker/subscriptions_channel.rb +33 -2
  8. data/app/controllers/api_maker/base_controller.rb +7 -3
  9. data/app/controllers/api_maker/commands_controller.rb +26 -4
  10. data/app/controllers/api_maker/session_statuses_controller.rb +1 -1
  11. data/app/services/api_maker/abilities_loader.rb +104 -0
  12. data/app/services/api_maker/application_service.rb +2 -1
  13. data/app/services/api_maker/base_command.rb +248 -0
  14. data/app/services/api_maker/collection_command_service.rb +29 -15
  15. data/app/services/api_maker/collection_loader.rb +124 -0
  16. data/app/services/api_maker/command_failed_error.rb +3 -0
  17. data/app/services/api_maker/command_response.rb +17 -6
  18. data/app/services/api_maker/command_service.rb +3 -3
  19. data/app/services/api_maker/create_command.rb +11 -26
  20. data/app/services/api_maker/create_command_service.rb +3 -3
  21. data/app/services/api_maker/database_type.rb +9 -0
  22. data/app/services/api_maker/deep_merge_params.rb +26 -0
  23. data/app/services/api_maker/deserializer.rb +35 -0
  24. data/app/services/api_maker/destroy_command.rb +15 -21
  25. data/app/services/api_maker/destroy_command_service.rb +3 -3
  26. data/app/services/api_maker/generate_react_native_api_service.rb +3 -19
  27. data/app/services/api_maker/include_helpers.rb +17 -0
  28. data/app/services/api_maker/index_command.rb +8 -88
  29. data/app/services/api_maker/index_command_service.rb +5 -5
  30. data/app/services/api_maker/js_method_namer_service.rb +1 -1
  31. data/app/services/api_maker/locals_from_controller.rb +14 -0
  32. data/app/services/api_maker/member_command_service.rb +15 -13
  33. data/app/services/api_maker/model_classes_java_script_generator_service.rb +37 -0
  34. data/app/services/api_maker/model_content_generator_service.rb +17 -21
  35. data/app/services/api_maker/models/save.rb +29 -0
  36. data/app/services/api_maker/models_finder_service.rb +6 -2
  37. data/app/services/api_maker/models_generator_service.rb +6 -43
  38. data/app/services/api_maker/move_components_to_routes.rb +50 -0
  39. data/app/services/api_maker/primary_id_for_model.rb +6 -0
  40. data/app/services/api_maker/reset_indexed_db_service.rb +36 -0
  41. data/app/services/api_maker/routes_file_reloader.rb +20 -0
  42. data/app/services/api_maker/select_columns_on_collection.rb +78 -0
  43. data/app/services/api_maker/select_parser.rb +32 -0
  44. data/app/services/api_maker/service_command.rb +27 -0
  45. data/app/services/api_maker/service_command_service.rb +14 -0
  46. data/app/services/api_maker/simple_model_errors.rb +52 -0
  47. data/app/services/api_maker/update_command.rb +8 -24
  48. data/app/services/api_maker/update_command_service.rb +3 -3
  49. data/app/services/api_maker/valid_command.rb +4 -13
  50. data/app/services/api_maker/valid_command_service.rb +3 -3
  51. data/app/services/api_maker/validation_errors_generator_service.rb +146 -0
  52. data/app/views/api_maker/_data.html.erb +17 -11
  53. data/config/routes.rb +0 -2
  54. data/lib/api_maker/ability.rb +22 -7
  55. data/lib/api_maker/ability_loader.rb +9 -6
  56. data/lib/api_maker/base_collection_instance.rb +15 -0
  57. data/lib/api_maker/base_resource.rb +135 -9
  58. data/lib/api_maker/base_service.rb +14 -0
  59. data/lib/api_maker/collection_serializer.rb +95 -34
  60. data/lib/api_maker/command_spec_helper.rb +41 -11
  61. data/lib/api_maker/configuration.rb +31 -4
  62. data/lib/api_maker/expect_to_able_to_helper.rb +31 -0
  63. data/lib/api_maker/individual_command.rb +24 -9
  64. data/lib/api_maker/javascript/model-template.js.erb +39 -25
  65. data/lib/api_maker/javascript/models.js.erb +6 -0
  66. data/lib/api_maker/loader.rb +1 -1
  67. data/lib/api_maker/memory_storage.rb +1 -1
  68. data/lib/api_maker/model_extensions.rb +34 -18
  69. data/lib/api_maker/permitted_params_argument.rb +5 -1
  70. data/lib/api_maker/preloader.rb +71 -32
  71. data/lib/api_maker/preloader_base.rb +108 -0
  72. data/lib/api_maker/preloader_belongs_to.rb +34 -33
  73. data/lib/api_maker/preloader_has_many.rb +45 -39
  74. data/lib/api_maker/preloader_has_one.rb +30 -47
  75. data/lib/api_maker/railtie.rb +3 -11
  76. data/lib/api_maker/relationship_preloader.rb +42 -0
  77. data/lib/api_maker/resource_routing.rb +18 -4
  78. data/lib/api_maker/result_parser.rb +34 -20
  79. data/lib/api_maker/serializer.rb +53 -22
  80. data/lib/api_maker/spec_helper/browser_logs.rb +14 -0
  81. data/lib/api_maker/spec_helper/execute_collection_command.rb +46 -0
  82. data/lib/api_maker/spec_helper/execute_member_command.rb +52 -0
  83. data/lib/api_maker/spec_helper/expect_no_browser_errors.rb +18 -0
  84. data/lib/api_maker/spec_helper/wait_for_expect.rb +20 -0
  85. data/lib/api_maker/spec_helper/wait_for_flash_message.rb +21 -0
  86. data/lib/api_maker/spec_helper.rb +112 -48
  87. data/lib/api_maker/version.rb +1 -1
  88. data/lib/api_maker.rb +7 -3
  89. metadata +108 -89
  90. data/README.md +0 -476
  91. data/app/controllers/api_maker/devise_controller.rb +0 -60
  92. data/lib/api_maker/base_command.rb +0 -81
  93. data/lib/api_maker/javascript/api.js +0 -92
  94. data/lib/api_maker/javascript/base-model.js +0 -543
  95. data/lib/api_maker/javascript/bootstrap/attribute-row.jsx +0 -16
  96. data/lib/api_maker/javascript/bootstrap/attribute-rows.jsx +0 -47
  97. data/lib/api_maker/javascript/bootstrap/card.jsx +0 -79
  98. data/lib/api_maker/javascript/bootstrap/checkbox.jsx +0 -127
  99. data/lib/api_maker/javascript/bootstrap/checkboxes.jsx +0 -105
  100. data/lib/api_maker/javascript/bootstrap/live-table.jsx +0 -168
  101. data/lib/api_maker/javascript/bootstrap/money-input.jsx +0 -136
  102. data/lib/api_maker/javascript/bootstrap/radio-buttons.jsx +0 -80
  103. data/lib/api_maker/javascript/bootstrap/select.jsx +0 -168
  104. data/lib/api_maker/javascript/bootstrap/string-input.jsx +0 -203
  105. data/lib/api_maker/javascript/cable-connection-pool.js +0 -169
  106. data/lib/api_maker/javascript/cable-subscription-pool.js +0 -111
  107. data/lib/api_maker/javascript/cable-subscription.js +0 -33
  108. data/lib/api_maker/javascript/collection.js +0 -186
  109. data/lib/api_maker/javascript/commands-pool.js +0 -123
  110. data/lib/api_maker/javascript/custom-error.js +0 -14
  111. data/lib/api_maker/javascript/deserializer.js +0 -35
  112. data/lib/api_maker/javascript/devise.js.erb +0 -113
  113. data/lib/api_maker/javascript/error-logger.js +0 -119
  114. data/lib/api_maker/javascript/event-connection.jsx +0 -24
  115. data/lib/api_maker/javascript/event-created.jsx +0 -26
  116. data/lib/api_maker/javascript/event-destroyed.jsx +0 -26
  117. data/lib/api_maker/javascript/event-emitter-listener.jsx +0 -32
  118. data/lib/api_maker/javascript/event-listener.jsx +0 -41
  119. data/lib/api_maker/javascript/event-updated.jsx +0 -26
  120. data/lib/api_maker/javascript/form-data-to-object.js +0 -70
  121. data/lib/api_maker/javascript/included.js +0 -39
  122. data/lib/api_maker/javascript/key-value-store.js +0 -47
  123. data/lib/api_maker/javascript/logger.js +0 -23
  124. data/lib/api_maker/javascript/model-name.js +0 -21
  125. data/lib/api_maker/javascript/models-response-reader.js +0 -43
  126. data/lib/api_maker/javascript/paginate.jsx +0 -128
  127. data/lib/api_maker/javascript/params.js +0 -68
  128. data/lib/api_maker/javascript/resource-route.jsx +0 -75
  129. data/lib/api_maker/javascript/resource-routes.jsx +0 -36
  130. data/lib/api_maker/javascript/result.js +0 -25
  131. data/lib/api_maker/javascript/session-status-updater.js +0 -113
  132. data/lib/api_maker/javascript/sort-link.jsx +0 -88
  133. data/lib/api_maker/javascript/updated-attribute.jsx +0 -60
  134. data/lib/api_maker/preloader_through.rb +0 -101
  135. data/lib/api_maker/relationship_includer.rb +0 -42
@@ -1,24 +1,38 @@
1
1
  class ApiMaker::CollectionCommandService < ApiMaker::CommandService
2
- def execute
3
- authorize!
2
+ def perform
3
+ ApiMaker::Configuration.profile(-> { "CollectionCommand: #{namespace}::#{command_name}" }) do
4
+ if authorized?
5
+ constant.execute_in_thread!(
6
+ ability: ability,
7
+ api_maker_args: api_maker_args,
8
+ collection: nil,
9
+ commands: commands,
10
+ command_response: command_response,
11
+ controller: controller
12
+ )
13
+ else
14
+ fail_with_no_access
15
+ end
4
16
 
5
- constant.execute_in_thread!(
6
- ability: ability,
7
- args: args,
8
- collection: nil,
9
- commands: commands,
10
- command_response: command_response,
11
- controller: controller
12
- )
13
-
14
- ServicePattern::Response.new(success: true)
17
+ succeed!
18
+ end
15
19
  end
16
20
 
17
- def authorize!
18
- raise CanCan::AccessDenied, "No access to '#{@command_name}' on '#{model_class.name}'" unless @ability.can?(@command_name.to_sym, model_class)
21
+ def authorized?
22
+ ability.can?(command_name.to_sym, model_class)
19
23
  end
20
24
 
21
25
  def constant
22
- @constant ||= "Commands::#{namespace}::#{@command_name.camelize}".constantize
26
+ @constant ||= "Commands::#{namespace}::#{command_name.camelize}".constantize
27
+ end
28
+
29
+ def fail_with_no_access
30
+ commands.each_key do |command_id|
31
+ command_response.error_for_command(
32
+ command_id,
33
+ success: false,
34
+ errors: ["No access to '#{command_name}' on '#{model_class.name}'"]
35
+ )
36
+ end
23
37
  end
24
38
  end
@@ -0,0 +1,124 @@
1
+ class ApiMaker::CollectionLoader < ApiMaker::ApplicationService
2
+ attr_reader :ability, :api_maker_args, :collection, :locals, :params
3
+
4
+ def initialize(ability:, api_maker_args:, collection:, locals: nil, params: {})
5
+ @ability = ability
6
+ @api_maker_args = api_maker_args
7
+ @collection = collection
8
+ @locals = locals || api_maker_args&.dig(:locals) || {}
9
+ @params = params
10
+ end
11
+
12
+ def perform
13
+ set_query
14
+
15
+ if params[:count]
16
+ count = @query.count
17
+ count = count.length if count.is_a?(Hash)
18
+
19
+ succeed!(count: count)
20
+ else
21
+ collection = collection_from_query(@query)
22
+ response = collection.as_json
23
+ include_pagination_data(response, @query)
24
+
25
+ succeed!(response)
26
+ end
27
+ end
28
+
29
+ def filter_custom_accessible_by(collection)
30
+ return collection if params[:accessible_by].blank?
31
+
32
+ collection.accessible_by(ability, params[:accessible_by].to_sym)
33
+ end
34
+
35
+ def collection_from_query(collection)
36
+ ApiMaker::CollectionSerializer.new(
37
+ ability: ability,
38
+ api_maker_args: api_maker_args,
39
+ collection: collection,
40
+ locals: locals,
41
+ query_params: params
42
+ ).result
43
+ end
44
+
45
+ def distinct_query
46
+ @query = @query.distinct if params[:distinct]
47
+ end
48
+
49
+ def group_query
50
+ return if params[:group_by].blank?
51
+
52
+ params[:group_by].each do |group_by|
53
+ if group_by.is_a?(Array)
54
+ raise "Expected table and column but array length was wrong: #{group_by.length}" unless group_by.length == 2
55
+
56
+ resource_class = group_by[0]
57
+ column_name = group_by[1]
58
+ model_class = resource_class.model_class
59
+ raise "Not a valid column name: #{column_name}" unless model_class.column_names.include?(column_name)
60
+
61
+ arel_column = model_class.arel_table[column_name]
62
+ else
63
+ arel_column = collection.klass.arel_table[group_by]
64
+ raise "Not a valid column name: #{group_by}" unless collection.klass.column_names.include?(group_by)
65
+ end
66
+
67
+ @query = @query.group(arel_column)
68
+ end
69
+ end
70
+
71
+ def limit_query
72
+ @query = @query.limit(params[:limit]) if params[:limit].present?
73
+ end
74
+
75
+ def include_pagination_data(response, collection)
76
+ return if params[:page].blank?
77
+
78
+ countable_collection = collection.except(:distinct).except(:group).except(:select).except(:order)
79
+
80
+ Rails.logger.debug { "API maker: CollectionLoader total pages for #{model_class.name}" }
81
+ total_pages = countable_collection.total_pages
82
+
83
+ Rails.logger.debug { "API maker: CollectionLoader total count for #{model_class.name}" }
84
+ total_count = countable_collection.try(:total_count) || countable_collection.total_entries
85
+
86
+ response[:meta] = {
87
+ currentPage: collection.current_page,
88
+ perPage: collection.try(:per_page) || collection.limit_value,
89
+ totalCount: total_count,
90
+ totalPages: total_pages
91
+ }
92
+ end
93
+
94
+ def manage_through_relationship
95
+ return if params[:through].blank?
96
+
97
+ through_model_class = params[:through][:model].safe_constantize
98
+ through_model = through_model_class.accessible_by(ability).find_by(through_model_class.primary_key => params[:through][:id])
99
+
100
+ return if through_model.nil?
101
+
102
+ association = ActiveRecord::Associations::Association.new(through_model, through_model_class.reflections.fetch(params[:through][:reflection]))
103
+
104
+ query_through = association.scope
105
+ query_through = query_through.accessible_by(ability)
106
+
107
+ filter_custom_accessible_by(query_through)
108
+ end
109
+
110
+ def model_class
111
+ @model_class ||= collection.klass
112
+ end
113
+
114
+ def set_query
115
+ @query = manage_through_relationship || collection
116
+ group_query
117
+ distinct_query
118
+ @query = @query.ransack(params[:q]).result
119
+ limit_query
120
+ @query = @query.page(params[:page]) if params[:page].present?
121
+ @query = @query.per_page(params[:per]) if params[:per].present?
122
+ @query = filter_custom_accessible_by(@query)
123
+ end
124
+ end
@@ -0,0 +1,3 @@
1
+ class ApiMaker::CommandFailedError < RuntimeError
2
+ attr_accessor :api_maker_args, :api_maker_block
3
+ end
@@ -47,21 +47,32 @@ class ApiMaker::CommandResponse
47
47
 
48
48
  private
49
49
 
50
- def spawn_thread
50
+ def spawn_thread(&blk)
51
+ parent_thread = Thread.current
52
+
51
53
  @threads << Thread.new do
54
+ child_thread = Thread.current
55
+
52
56
  Rails.application.executor.wrap do
53
- I18n.with_locale(locale) do
54
- yield
57
+ ApiMaker::Configuration.current.on_thread_callbacks&.each do |on_thread_callback|
58
+ on_thread_callback.call(parent_thread: parent_thread, child_thread: child_thread)
55
59
  end
60
+
61
+ I18n.with_locale(locale, &blk)
56
62
  end
57
63
  rescue => e # rubocop:disable Style/RescueStandardError
58
64
  puts e.inspect
59
- puts e.backtrace
65
+ puts Rails.backtrace_cleaner.clean(e.backtrace)
60
66
 
61
67
  Rails.logger.error e.message
62
- Rails.logger.error e.backtrace.join("\n")
68
+ Rails.logger.error Rails.backtrace_cleaner.clean(e.backtrace).join("\n")
63
69
 
64
- ApiMaker::Configuration.current.report_error(controller: controller, error: e)
70
+ ApiMaker::Configuration.current.report_error(
71
+ command: nil,
72
+ controller: controller,
73
+ error: e,
74
+ response: nil
75
+ )
65
76
  end
66
77
  end
67
78
  end
@@ -1,9 +1,9 @@
1
1
  class ApiMaker::CommandService < ApiMaker::ApplicationService
2
- attr_reader :ability, :args, :commands, :command_name, :command_response, :controller, :resource_name
2
+ attr_reader :ability, :api_maker_args, :commands, :command_name, :command_response, :controller, :resource_name
3
3
 
4
- def initialize(ability:, args:, commands:, command_name:, command_response:, controller:, resource_name:)
4
+ def initialize(ability:, api_maker_args:, commands:, command_name:, command_response:, controller:, resource_name:)
5
5
  @ability = ability
6
- @args = args
6
+ @api_maker_args = api_maker_args
7
7
  @command_name = command_name
8
8
  @command_response = command_response
9
9
  @commands = commands
@@ -1,38 +1,27 @@
1
1
  class ApiMaker::CreateCommand < ApiMaker::BaseCommand
2
- attr_reader :command, :model, :params, :serializer
2
+ attr_reader :model, :serializer
3
3
 
4
4
  def execute!
5
- each_command do |command|
6
- @command = command
5
+ ApiMaker::Configuration.profile(-> { "CreateCommand: #{model_class.name}" }) do
7
6
  @model = collection.klass.new
8
- @params = command.args || {}
9
7
  @serializer = serialized_resource(model)
10
- @model.assign_attributes(sanitize_parameters)
8
+ sanitized_parameters = sanitize_parameters
9
+ @model.assign_attributes(sanitized_parameters)
11
10
 
12
- if !current_ability.can?(:create, @model)
13
- failure_response(["No access to create that resource"])
14
- elsif @model.save
11
+ if !current_ability.can?(:create, model)
12
+ failure_response(errors: ["No access to create that resource"])
13
+ elsif model.save
15
14
  success_response
16
15
  else
17
- failure_response(model.errors.full_messages)
16
+ failure_save_response(model: model, params: sanitized_parameters)
18
17
  end
19
18
  end
20
-
21
- ServicePattern::Response.new(success: true)
22
19
  end
23
20
 
24
21
  def api_maker_resource_class
25
22
  @api_maker_resource_class ||= "Resources::#{collection.klass.name}Resource".constantize
26
23
  end
27
24
 
28
- def failure_response(errors)
29
- command.fail(
30
- model: serializer.result,
31
- success: false,
32
- errors: errors
33
- )
34
- end
35
-
36
25
  def resource_instance_class_name
37
26
  @resource_instance_class_name ||= self.class.name.split("::").last.gsub(/Controller$/, "").singularize
38
27
  end
@@ -46,16 +35,12 @@ class ApiMaker::CreateCommand < ApiMaker::BaseCommand
46
35
  end
47
36
 
48
37
  def sanitize_parameters
49
- serializer.resource_instance.permitted_params(ApiMaker::PermittedParamsArgument.new(command: command, model: model))
50
- end
51
-
52
- def serialized_resource(model)
53
- ApiMaker::Serializer.new(ability: current_ability, args: api_maker_args, model: model)
38
+ serializer.resource_instance.permitted_params(ApiMaker::PermittedParamsArgument.new(command: self, model: model))
54
39
  end
55
40
 
56
41
  def success_response
57
- command.result(
58
- model: serializer.result,
42
+ succeed!(
43
+ model: serialized_model(model),
59
44
  success: true
60
45
  )
61
46
  end
@@ -1,15 +1,15 @@
1
1
  class ApiMaker::CreateCommandService < ApiMaker::CommandService
2
- def execute
2
+ def perform
3
3
  ApiMaker::CreateCommand.execute_in_thread!(
4
4
  ability: ability,
5
- args: args,
5
+ api_maker_args: api_maker_args,
6
6
  collection: collection,
7
7
  commands: commands,
8
8
  command_response: command_response,
9
9
  controller: controller
10
10
  )
11
11
 
12
- ServicePattern::Response.new(success: true)
12
+ succeed!
13
13
  end
14
14
 
15
15
  def collection
@@ -0,0 +1,9 @@
1
+ class ApiMaker::DatabaseType
2
+ def self.postgres?
3
+ adapter_name == :postgresql
4
+ end
5
+
6
+ def self.adapter_name
7
+ @adapter_name ||= ApplicationRecord.connection.adapter_name.downcase.to_sym
8
+ end
9
+ end
@@ -0,0 +1,26 @@
1
+ class ApiMaker::DeepMergeParams < ApiMaker::ApplicationService
2
+ attr_reader :hash1, :hash2
3
+
4
+ def initialize(hash1, hash2)
5
+ @hash1 = hash1
6
+ @hash2 = hash2
7
+ end
8
+
9
+ def perform
10
+ merged_hash = hash1.deep_merge(hash2) do |_key, this_val, other_val|
11
+ if this_val.is_a?(Array) && other_val.is_a?(Array) && this_val.length == other_val.length
12
+ this_val.zip(other_val).collect do |a, b|
13
+ if a.is_a?(Hash) && b.is_a?(Hash)
14
+ a.deep_merge(b)
15
+ else
16
+ other_val
17
+ end
18
+ end
19
+ else
20
+ other_val
21
+ end
22
+ end
23
+
24
+ succeed! merged_hash
25
+ end
26
+ end
@@ -0,0 +1,35 @@
1
+ class ApiMaker::Deserializer < ApiMaker::ApplicationService
2
+ attr_reader :arg
3
+
4
+ def initialize(arg:)
5
+ @arg = arg
6
+ end
7
+
8
+ def perform
9
+ succeed! deserialize
10
+ end
11
+
12
+ def deserialize
13
+ if arg.is_a?(Array)
14
+ arg.map { |value| ApiMaker::Deserializer.execute!(arg: value) }
15
+ elsif arg.is_a?(Hash) || arg.is_a?(ActionController::Parameters)
16
+ if arg["api_maker_type"] == "resource"
17
+ "Resources::#{arg.fetch("name")}Resource".safe_constantize
18
+ elsif arg["api_maker_type"] == "datetime"
19
+ Time.zone.parse(arg.fetch("value"))
20
+ else
21
+ new_hash = arg.class.new
22
+ arg.each do |key, value|
23
+ deserialized_key = ApiMaker::Deserializer.execute!(arg: key)
24
+ deserialized_value = ApiMaker::Deserializer.execute!(arg: value)
25
+
26
+ new_hash[deserialized_key] = deserialized_value
27
+ end
28
+
29
+ new_hash
30
+ end
31
+ else
32
+ arg
33
+ end
34
+ end
35
+ end
@@ -1,38 +1,32 @@
1
1
  class ApiMaker::DestroyCommand < ApiMaker::BaseCommand
2
- attr_reader :command, :model, :params, :serializer
2
+ attr_reader :serializer
3
3
 
4
4
  def execute!
5
- each_command do |command|
6
- @command = command
7
- @model = command.model
8
- @params = command.args || {}
9
- @serializer = serialized_resource(model)
5
+ @serializer = serialized_resource(model)
10
6
 
11
- if command.model.destroy
12
- success_response
13
- else
14
- failure_response
15
- end
7
+ if command.model.destroy
8
+ success_response
9
+ else
10
+ failure_response
16
11
  end
12
+ end
17
13
 
18
- ServicePattern::Response.new(success: true)
14
+ def errors_for_model
15
+ ActiveRecordBetterDependentErrorMessages::DestroyValidator.(model: model) if model.errors.full_messages.empty?
16
+ model.errors.full_messages
19
17
  end
20
18
 
21
19
  def failure_response
22
- command.fail(
23
- model: serializer.result,
20
+ fail!(
21
+ model: serialized_model(model),
24
22
  success: false,
25
- errors: model.errors.full_messages
23
+ errors: errors_for_model
26
24
  )
27
25
  end
28
26
 
29
- def serialized_resource(model)
30
- ApiMaker::Serializer.new(ability: current_ability, args: api_maker_args, model: model)
31
- end
32
-
33
27
  def success_response
34
- command.result(
35
- model: serializer.result,
28
+ succeed!(
29
+ model: serialized_model(model),
36
30
  success: true
37
31
  )
38
32
  end
@@ -1,15 +1,15 @@
1
1
  class ApiMaker::DestroyCommandService < ApiMaker::CommandService
2
- def execute
2
+ def perform
3
3
  ApiMaker::DestroyCommand.execute_in_thread!(
4
4
  ability: ability,
5
- args: args,
5
+ api_maker_args: api_maker_args,
6
6
  collection: collection,
7
7
  commands: commands,
8
8
  command_response: command_response,
9
9
  controller: controller
10
10
  )
11
11
 
12
- ServicePattern::Response.new(success: true)
12
+ succeed!
13
13
  end
14
14
 
15
15
  def collection
@@ -1,10 +1,10 @@
1
1
  class ApiMaker::GenerateReactNativeApiService < ApiMaker::ApplicationService
2
- def execute
2
+ def perform
3
3
  check_if_root_folder_defined
4
4
  create_root_folder
5
5
  create_model_files
6
6
 
7
- ServicePattern::Response.new(success: true)
7
+ succeed!
8
8
  end
9
9
 
10
10
  def root_folder
@@ -21,20 +21,6 @@ class ApiMaker::GenerateReactNativeApiService < ApiMaker::ApplicationService
21
21
  Dir.mkdir(root_folder) unless Dir.exist?(root_folder)
22
22
  end
23
23
 
24
- def create_model_files
25
- model_generator_service.models.each do |model|
26
- next if model_generator_service.ignore_model?(model)
27
-
28
- model_content_response = ApiMaker::ModelContentGeneratorService.execute!(model: model)
29
-
30
- if model_content_response.success?
31
- File.open(model_file(model), "w") { |fp| fp.write(model_content_response.result) }
32
- else
33
- puts model_content_response.errors.join(". ")
34
- end
35
- end
36
- end
37
-
38
24
  def model_generator_service
39
25
  @model_generator_service ||= ApiMaker::ModelsGeneratorService.new
40
26
  end
@@ -50,9 +36,7 @@ class ApiMaker::GenerateReactNativeApiService < ApiMaker::ApplicationService
50
36
 
51
37
  def copy_base_model
52
38
  files = %w[
53
- api.js base-model.js cable-connection-pool.js cable-subscription.js cable-subscription-pool.js
54
- collection.js commands-pool.js devise.js event-listener.jsx error-logger.js form-data-to-object.js logger.js
55
- model-name.js models-response-reader.js result.js event-connection.jsx
39
+ devise.js event-connection.jsx
56
40
  ]
57
41
  path = File.join(__dir__, "..", "..", "..", "lib", "api_maker", "javascript")
58
42
 
@@ -0,0 +1,17 @@
1
+ require_relative "../../api_maker/api_helpers/api_maker_helpers" # Sometimes this file isn't auto-loaded so it needs to be manually required
2
+
3
+ class ApiMaker::IncludeHelpers < ApiMaker::ApplicationService
4
+ attr_reader :klass
5
+
6
+ def initialize(klass:)
7
+ @klass = klass
8
+ end
9
+
10
+ def perform
11
+ ::ApiHelpers.constants(false).each do |constant|
12
+ klass.include ApiHelpers.const_get(constant)
13
+ end
14
+
15
+ succeed!
16
+ end
17
+ end
@@ -1,96 +1,16 @@
1
1
  class ApiMaker::IndexCommand < ApiMaker::BaseCommand
2
- attr_reader :params
3
-
4
2
  def execute!
5
- ApiMaker::Configuration.profile("IndexCommand execute") do
6
- each_command do |command|
7
- @params = command.args || {}
8
-
9
- set_collection
10
-
11
- if params[:count]
12
- count = @query.count
13
- count = count.length if count.is_a?(Hash)
14
-
15
- command.result(count: count)
16
- else
17
- collection = collection_from_query(@query.fix)
18
- response = collection.as_json
19
- include_pagination_data(response, @query)
20
-
21
- command.result(response)
22
- end
23
- end
24
- end
25
-
26
- ServicePattern::Response.new(success: true)
27
- end
28
-
29
- def filter_custom_accessible_by(collection)
30
- return collection if params[:accessible_by].blank?
31
-
32
- collection.accessible_by(current_ability, params[:accessible_by].to_sym)
33
- end
3
+ ApiMaker::Configuration.profile(-> { "IndexCommand: #{model_class.name}" }) do
4
+ Rails.logger.debug { "API maker: IndexCommand execute: #{model_class.name} with Ransack: #{command.args&.dig(:q)&.permit!&.to_h}" }
34
5
 
35
- def collection_from_query(collection)
36
- ApiMaker::Configuration.profile("IndexCommand collection_from_query") do
37
- select = parse_select(params[:select]&.permit!&.to_hash) if params[:select]
38
-
39
- ApiMaker::CollectionSerializer.new(
6
+ result = ApiMaker::CollectionLoader.execute!(
40
7
  ability: current_ability,
41
- args: api_maker_args,
8
+ api_maker_args: api_maker_args,
42
9
  collection: collection,
43
- include_param: params[:include],
44
- select: select
45
- ).result
10
+ locals: locals,
11
+ params: command.args || {}
12
+ )
13
+ succeed!(result)
46
14
  end
47
15
  end
48
-
49
- def include_pagination_data(response, collection)
50
- return if params[:page].blank?
51
-
52
- response[:meta] = {
53
- currentPage: collection.current_page,
54
- totalCount: collection.try(:total_count) || collection.try(:total_entries),
55
- totalPages: collection.total_pages
56
- }
57
- end
58
-
59
- def manage_through_relationship
60
- return if params[:through].blank?
61
-
62
- model_class = params[:through][:model].safe_constantize
63
- through_model = model_class.accessible_by(current_ability).find(params[:through][:id])
64
- association = ActiveRecord::Associations::Association.new(through_model, model_class.reflections.fetch(params[:through][:reflection]))
65
-
66
- query_through = association.scope
67
- query_through = query_through.accessible_by(current_ability)
68
- query_through = filter_custom_accessible_by(query_through)
69
- query_through
70
- end
71
-
72
- # This converts the list of attributes to a hash that contains the data needed for the serializer (so the serializer doesn't have to do it for each model)
73
- def parse_select(select)
74
- new_select = {}
75
-
76
- select.each do |model_collection_name, attributes|
77
- model_class = model_collection_name.underscore.singularize.camelize
78
- resource = "Resources::#{model_class}Resource".safe_constantize
79
- raise "Resource not found for: #{model_collection_name}" unless resource
80
-
81
- new_attributes = resource._attributes.select { |key| attributes.include?(key.to_s) }
82
- new_select[resource.model_class] = new_attributes
83
- end
84
-
85
- new_select
86
- end
87
-
88
- def set_collection
89
- @query = manage_through_relationship || collection
90
- @query = @query.distinct if params[:distinct]
91
- @query = @query.ransack(params[:q]).result
92
- @query = @query.limit(params[:limit]) if params[:limit].present?
93
- @query = @query.page(params[:page]) if params[:page].present?
94
- @query = filter_custom_accessible_by(@query)
95
- end
96
16
  end
@@ -1,22 +1,22 @@
1
1
  class ApiMaker::IndexCommandService < ApiMaker::CommandService
2
- def execute
2
+ def perform
3
3
  ApiMaker::IndexCommand.execute_in_thread!(
4
4
  ability: ability,
5
- args: args,
5
+ api_maker_args: api_maker_args,
6
6
  collection: collection,
7
7
  commands: commands,
8
8
  command_response: command_response,
9
9
  controller: controller
10
10
  )
11
11
 
12
- ServicePattern::Response.new(success: true)
12
+ succeed!
13
13
  end
14
14
 
15
15
  def collection
16
- @collection ||= model_class.accessible_by(@ability)
16
+ @collection ||= model_class.accessible_by(ability)
17
17
  end
18
18
 
19
19
  def ids
20
- @ids ||= @commands.values.map { |command| command.fetch("primary_key") }
20
+ @ids ||= commands.values.map { |command| command.fetch("primary_key") }
21
21
  end
22
22
  end
@@ -3,7 +3,7 @@ class ApiMaker::JsMethodNamerService < ApiMaker::ApplicationService
3
3
  @name = name
4
4
  end
5
5
 
6
- def execute
6
+ def perform
7
7
  camelized = @name.to_s.camelize
8
8
  new_name = "#{camelized[0..0].downcase}#{camelized[1..camelized.length]}"
9
9
  ServicePattern::Response.new(result: new_name)