rider-kick 0.0.13 → 0.0.14

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.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +629 -25
  3. data/lib/generators/rider_kick/USAGE +2 -0
  4. data/lib/generators/rider_kick/base_generator.rb +190 -0
  5. data/lib/generators/rider_kick/clean_arch_generator.rb +235 -45
  6. data/lib/generators/rider_kick/clean_arch_generator_engine_spec.rb +359 -0
  7. data/lib/generators/rider_kick/clean_arch_generator_factory_bot_spec.rb +131 -0
  8. data/lib/generators/rider_kick/entity_type_mapping_spec.rb +22 -13
  9. data/lib/generators/rider_kick/errors.rb +42 -0
  10. data/lib/generators/rider_kick/factory_generator.rb +238 -0
  11. data/lib/generators/rider_kick/factory_generator_spec.rb +175 -0
  12. data/lib/generators/rider_kick/repositories_contract_spec.rb +95 -22
  13. data/lib/generators/rider_kick/scaffold_generator.rb +377 -62
  14. data/lib/generators/rider_kick/scaffold_generator_builder_uploaders_spec.rb +119 -14
  15. data/lib/generators/rider_kick/scaffold_generator_conditional_filtering_spec.rb +820 -0
  16. data/lib/generators/rider_kick/scaffold_generator_contracts_spec.rb +37 -10
  17. data/lib/generators/rider_kick/scaffold_generator_contracts_with_scope_spec.rb +40 -11
  18. data/lib/generators/rider_kick/scaffold_generator_engine_spec.rb +221 -0
  19. data/lib/generators/rider_kick/scaffold_generator_idempotent_spec.rb +38 -13
  20. data/lib/generators/rider_kick/scaffold_generator_list_spec_format_spec.rb +153 -0
  21. data/lib/generators/rider_kick/scaffold_generator_rspec_spec.rb +347 -0
  22. data/lib/generators/rider_kick/scaffold_generator_success_spec.rb +31 -12
  23. data/lib/generators/rider_kick/scaffold_generator_with_scope_spec.rb +32 -11
  24. data/lib/generators/rider_kick/structure_generator.rb +154 -43
  25. data/lib/generators/rider_kick/structure_generator_comprehensive_spec.rb +598 -0
  26. data/lib/generators/rider_kick/structure_generator_engine_spec.rb +279 -0
  27. data/lib/generators/rider_kick/structure_generator_spec.rb +3 -3
  28. data/lib/generators/rider_kick/structure_generator_success_spec.rb +33 -5
  29. data/lib/generators/rider_kick/structure_generator_unit_spec.rb +2202 -0
  30. data/lib/generators/rider_kick/templates/.rubocop.yml +5 -4
  31. data/lib/generators/rider_kick/templates/config/initializers/version.rb.tt +1 -1
  32. data/lib/generators/rider_kick/templates/db/migrate/20220613145533_init_database.rb +1 -1
  33. data/lib/generators/rider_kick/templates/db/structures/example.yaml.tt +140 -66
  34. data/lib/generators/rider_kick/templates/domains/core/builders/builder.rb.tt +36 -10
  35. data/lib/generators/rider_kick/templates/domains/core/builders/builder_spec.rb.tt +219 -0
  36. data/lib/generators/rider_kick/templates/domains/core/builders/error.rb.tt +2 -2
  37. data/lib/generators/rider_kick/templates/domains/core/builders/pagination.rb.tt +2 -2
  38. data/lib/generators/rider_kick/templates/domains/core/entities/entity.rb.tt +32 -14
  39. data/lib/generators/rider_kick/templates/domains/core/entities/error.rb.tt +1 -1
  40. data/lib/generators/rider_kick/templates/domains/core/entities/pagination.rb.tt +1 -1
  41. data/lib/generators/rider_kick/templates/domains/core/repositories/abstract_repository.rb.tt +4 -4
  42. data/lib/generators/rider_kick/templates/domains/core/repositories/create.rb.tt +2 -2
  43. data/lib/generators/rider_kick/templates/domains/core/repositories/create_spec.rb.tt +78 -0
  44. data/lib/generators/rider_kick/templates/domains/core/repositories/destroy.rb.tt +2 -2
  45. data/lib/generators/rider_kick/templates/domains/core/repositories/destroy_spec.rb.tt +88 -0
  46. data/lib/generators/rider_kick/templates/domains/core/repositories/fetch_by_id.rb.tt +3 -3
  47. data/lib/generators/rider_kick/templates/domains/core/repositories/fetch_by_id_spec.rb.tt +62 -0
  48. data/lib/generators/rider_kick/templates/domains/core/repositories/list.rb.tt +13 -8
  49. data/lib/generators/rider_kick/templates/domains/core/repositories/list_spec.rb.tt +190 -0
  50. data/lib/generators/rider_kick/templates/domains/core/repositories/update.rb.tt +4 -4
  51. data/lib/generators/rider_kick/templates/domains/core/repositories/update_spec.rb.tt +119 -0
  52. data/lib/generators/rider_kick/templates/domains/core/use_cases/contract/default.rb.tt +1 -1
  53. data/lib/generators/rider_kick/templates/domains/core/use_cases/contract/pagination.rb.tt +1 -1
  54. data/lib/generators/rider_kick/templates/domains/core/use_cases/create.rb.tt +3 -7
  55. data/lib/generators/rider_kick/templates/domains/core/use_cases/create_spec.rb.tt +71 -0
  56. data/lib/generators/rider_kick/templates/domains/core/use_cases/destroy.rb.tt +3 -7
  57. data/lib/generators/rider_kick/templates/domains/core/use_cases/destroy_spec.rb.tt +62 -0
  58. data/lib/generators/rider_kick/templates/domains/core/use_cases/fetch_by_id.rb.tt +3 -7
  59. data/lib/generators/rider_kick/templates/domains/core/use_cases/fetch_by_id_spec.rb.tt +62 -0
  60. data/lib/generators/rider_kick/templates/domains/core/use_cases/get_version.rb.tt +2 -2
  61. data/lib/generators/rider_kick/templates/domains/core/use_cases/list.rb.tt +3 -7
  62. data/lib/generators/rider_kick/templates/domains/core/use_cases/list_spec.rb.tt +64 -0
  63. data/lib/generators/rider_kick/templates/domains/core/use_cases/update.rb.tt +3 -7
  64. data/lib/generators/rider_kick/templates/domains/core/use_cases/update_spec.rb.tt +73 -0
  65. data/lib/generators/rider_kick/templates/domains/core/utils/abstract_utils.rb.tt +3 -3
  66. data/lib/generators/rider_kick/templates/domains/core/utils/request_methods.rb.tt +1 -1
  67. data/lib/generators/rider_kick/templates/env.development +1 -1
  68. data/lib/generators/rider_kick/templates/env.production +1 -1
  69. data/lib/generators/rider_kick/templates/env.test +1 -1
  70. data/lib/generators/rider_kick/templates/models/{application_record.rb → application_record.rb.tt} +3 -1
  71. data/lib/generators/rider_kick/templates/models/model_spec.rb.tt +68 -0
  72. data/lib/generators/rider_kick/templates/spec/factories/.gitkeep +19 -0
  73. data/lib/generators/rider_kick/templates/spec/factories/factory.rb.tt +8 -0
  74. data/lib/generators/rider_kick/templates/spec/rails_helper.rb +2 -0
  75. data/lib/generators/rider_kick/templates/spec/support/class_stubber.rb +148 -0
  76. data/lib/generators/rider_kick/templates/spec/support/factory_bot.rb +34 -0
  77. data/lib/generators/rider_kick/templates/spec/support/faker.rb +61 -0
  78. data/lib/rider-kick.rb +8 -6
  79. data/lib/rider_kick/builders/abstract_active_record_entity_builder_spec.rb +644 -0
  80. data/lib/rider_kick/configuration.rb +238 -0
  81. data/lib/rider_kick/configuration_engine_spec.rb +377 -0
  82. data/lib/rider_kick/entities/failure_details.rb +1 -1
  83. data/lib/rider_kick/entities/failure_details_spec.rb +1 -1
  84. data/lib/rider_kick/matchers/use_case_result.rb +1 -1
  85. data/lib/rider_kick/use_cases/abstract_use_case.rb +1 -1
  86. data/lib/rider_kick/version.rb +1 -1
  87. metadata +129 -8
  88. data/CHANGELOG.md +0 -5
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class Core::Entities::Error < Dry::Struct
3
+ class <%= domain_class_name %>::Entities::Error < Dry::Struct
4
4
  attribute :attribute, Types::Strict::String
5
5
  attribute :type, Types::Strict::String
6
6
  attribute :options, Types::Hash.optional
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class Core::Entities::Pagination < Dry::Struct
3
+ class <%= domain_class_name %>::Entities::Pagination < Dry::Struct
4
4
  attribute :total_count, Types::Strict::Integer
5
5
  attribute :page, Types::Strict::Integer
6
6
  attribute :per_page, Types::Strict::Integer
@@ -1,10 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class Core::Repositories::AbstractRepository
3
+ class <%= domain_class_name %>::Repositories::AbstractRepository
4
4
  include Dry::Monads[:result, :do]
5
5
 
6
6
  def http
7
- extend(Core::Utils::RequestMethods)
7
+ extend(<%= domain_class_name %>::Utils::RequestMethods)
8
8
  end
9
9
 
10
10
  def error_messages_for(record)
@@ -14,7 +14,7 @@ class Core::Repositories::AbstractRepository
14
14
  def build_errors(resource)
15
15
  errors = []
16
16
  resource.errors.each do |error|
17
- errors << Core::Builders::Error.new(error.as_json).build
17
+ errors << <%= domain_class_name %>::Builders::Error.new(error.as_json).build
18
18
  end
19
19
  errors
20
20
  end
@@ -28,7 +28,7 @@ class Core::Repositories::AbstractRepository
28
28
  end
29
29
 
30
30
  def paginate!(pagy)
31
- Core::Builders::Pagination.new(pagy).build
31
+ <%= domain_class_name %>::Builders::Pagination.new(pagy).build
32
32
  end
33
33
 
34
34
  def build_pagination_variable!(params)
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class Core::Repositories::<%= @scope_class %>::<%= @repository_class %> < Core::Repositories::AbstractRepository
3
+ class <%= domain_class_name %>::Repositories::<%= @scope_class %>::<%= @repository_class %> < <%= domain_class_name %>::Repositories::AbstractRepository
4
4
  def initialize(params:)
5
5
  @params = prepare! params, sanitize: true
6
6
  end
@@ -10,6 +10,6 @@ class Core::Repositories::<%= @scope_class %>::<%= @repository_class %> < Core::
10
10
  unless resource.save
11
11
  return Failure build_errors(resource)
12
12
  end
13
- Success Core::Builders::<%= @subject_class %>.new(resource).build
13
+ Success <%= domain_class_name %>::Builders::<%= @subject_class %>.new(resource).build
14
14
  end
15
15
  end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ RSpec.describe <%= domain_class_name %>::Repositories::<%= @scope_class %>::<%= @repository_class %>, type: :repository do
6
+ describe '#call' do
7
+ let(:builder) { instance_double(<%= domain_class_name %>::Builders::<%= @subject_class %>) }
8
+ let(:entity) { instance_double(<%= domain_class_name %>::Entities::<%= @subject_class %>) }
9
+ let(:<%= @variable_subject %>) { instance_double(<%= @model_class %>) }
10
+
11
+ let(:valid_params) do
12
+ Hashie::Mash.new({
13
+ <% if @resource_owner_id.present? -%>
14
+ <%= @resource_owner_id %>: '<%= @resource_owner_id %>_value',
15
+ <% end -%>
16
+ <% @fields.each_with_index do |field, index| -%>
17
+ <% next if @resource_owner_id.present? && field == @resource_owner_id -%>
18
+ <% field_meta = columns_meta.find { |col| col[:name] == field } -%>
19
+ <% if field_meta && [:datetime, :timestamp].include?(field_meta[:type]) -%>
20
+ <%= field %>: Time.zone.now<%= index < @fields.length - 1 ? ',' : '' %>
21
+ <% else -%>
22
+ <%= field %>: '<%= field %>_value'<%= index < @fields.length - 1 ? ',' : '' %>
23
+ <% end -%>
24
+ <% end -%>
25
+ })
26
+ end
27
+
28
+ let(:error_messages) do
29
+ [
30
+ { 'attribute' => '<%= @fields.first %>', 'type' => 'blank', 'options' => { 'message' => 'must be valid format' } },
31
+ { 'attribute' => '<%= @fields[1] || @fields.first %>', 'type' => 'invalid', 'options' => { 'message' => 'must be valid format' } }
32
+ ]
33
+ end
34
+
35
+ let(:active_model_errors) do
36
+ errors = double('errors')
37
+ allow(errors).to receive(:each).and_yield(
38
+ double(as_json: error_messages.first)
39
+ ).and_yield(
40
+ double(as_json: error_messages.last)
41
+ )
42
+ errors
43
+ end
44
+
45
+ subject(:repository) { described_class.new(params: valid_params) }
46
+
47
+ before do
48
+ allow(<%= domain_class_name %>::Builders::<%= @subject_class %>).to receive(:new).with(<%= @variable_subject %>).and_return(builder)
49
+ allow(builder).to receive(:build).and_return(entity)
50
+ end
51
+
52
+ context 'when creation is successful' do
53
+ it 'creates a new <%= @variable_subject %> and returns success with entity', :aggregate_failures do
54
+ allow(<%= @model_class %>).to receive(:new).with(valid_params.to_h).and_return(<%= @variable_subject %>)
55
+ allow(<%= @variable_subject %>).to receive(:save).and_return(true)
56
+
57
+ result = repository.call(builder: true)
58
+
59
+ expect(result).to be_success
60
+ expect(result.value!).to eq(entity)
61
+ end
62
+ end
63
+
64
+ context 'when creation fails' do
65
+ it 'returns failure with errors', :aggregate_failures do
66
+ allow(<%= @model_class %>).to receive(:new).with(valid_params.to_h).and_return(<%= @variable_subject %>)
67
+ allow(<%= @variable_subject %>).to receive(:save).and_return(false)
68
+ allow(<%= @variable_subject %>).to receive(:errors).and_return(active_model_errors)
69
+
70
+ result = repository.call(builder: true)
71
+
72
+ expect(result).to be_failure
73
+ # Verify error structure matches build_errors output
74
+ expect(result.failure).to be_an(Array)
75
+ end
76
+ end
77
+ end
78
+ end
@@ -1,13 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class Core::Repositories::<%= @scope_class %>::<%= @repository_class %> < Core::Repositories::AbstractRepository
3
+ class <%= domain_class_name %>::Repositories::<%= @scope_class %>::<%= @repository_class %> < <%= domain_class_name %>::Repositories::AbstractRepository
4
4
  def initialize(params:)
5
5
  @params = params
6
6
  @id = @params.id
7
7
  end
8
8
 
9
9
  def call(builder: true)
10
- <% if @resource_owner_id.present? -%>
10
+ <% if @resource_owner_id.present? && @has_resource_owner_id_in_destroy_contract -%>
11
11
  resource = <%= @model_class %>.find_by(id: @id, <%=@resource_owner_id%>: @params.<%=@resource_owner_id%>)
12
12
  <% else -%>
13
13
  resource = <%= @model_class %>.find_by(id: @id)
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ RSpec.describe <%= domain_class_name %>::Repositories::<%= @scope_class %>::<%= @repository_class %>, type: :repository do
6
+ describe '#call' do
7
+ let(:<%= @variable_subject %>) { instance_double(<%= @model_class %>) }
8
+ let(:<%= @variable_subject %>_id) { 'test-id-123' }
9
+
10
+ let(:valid_params) do
11
+ Hashie::Mash.new({
12
+ id: <%= @variable_subject %>_id<% if @resource_owner_id.present? && @has_resource_owner_id_in_destroy_contract %>,
13
+ <%= @resource_owner_id %>: '<%= @resource_owner_id %>_value'<% end %>
14
+ })
15
+ end
16
+
17
+ let(:error_messages) do
18
+ [
19
+ { 'attribute' => 'base', 'type' => 'cannot_destroy', 'options' => { 'message' => 'must be valid format' } }
20
+ ]
21
+ end
22
+
23
+ let(:active_model_errors) do
24
+ errors = double('errors')
25
+ allow(errors).to receive(:each).and_yield(
26
+ double(as_json: error_messages.first)
27
+ )
28
+ errors
29
+ end
30
+
31
+ subject(:repository) { described_class.new(params: valid_params) }
32
+
33
+ context 'when <%= @variable_subject %> exists' do
34
+ before do
35
+ <% if @resource_owner_id.present? && @has_resource_owner_id_in_destroy_contract -%>
36
+ allow(<%= @model_class %>).to receive(:find_by).with(
37
+ id: <%= @variable_subject %>_id,
38
+ <%= @resource_owner_id %>: valid_params.<%= @resource_owner_id %>
39
+ ).and_return(<%= @variable_subject %>)
40
+ <% else -%>
41
+ allow(<%= @model_class %>).to receive(:find_by).with(id: <%= @variable_subject %>_id).and_return(<%= @variable_subject %>)
42
+ <% end -%>
43
+ end
44
+
45
+ context 'when destroy is successful' do
46
+ it 'destroys the <%= @variable_subject %> and returns success message', :aggregate_failures do
47
+ allow(<%= @variable_subject %>).to receive(:destroy).and_return(true)
48
+
49
+ result = repository.call(builder: true)
50
+
51
+ expect(result).to be_success
52
+ expect(result.value!).to eq('<%= @subject_class%> Destroyed.')
53
+ end
54
+ end
55
+
56
+ context 'when destroy fails' do
57
+ it 'returns failure with errors', :aggregate_failures do
58
+ allow(<%= @variable_subject %>).to receive(:destroy).and_return(false)
59
+ allow(<%= @variable_subject %>).to receive(:errors).and_return(active_model_errors)
60
+
61
+ result = repository.call(builder: true)
62
+
63
+ expect(result).to be_failure
64
+ # Verify error structure matches build_errors output
65
+ expect(result.failure).to be_an(Array)
66
+ end
67
+ end
68
+ end
69
+
70
+ context 'when <%= @variable_subject %> does not exist' do
71
+ it 'returns failure with not found message', :aggregate_failures do
72
+ <% if @resource_owner_id.present? && @has_resource_owner_id_in_destroy_contract -%>
73
+ allow(<%= @model_class %>).to receive(:find_by).with(
74
+ id: <%= @variable_subject %>_id,
75
+ <%= @resource_owner_id %>: valid_params.<%= @resource_owner_id %>
76
+ ).and_return(nil)
77
+ <% else -%>
78
+ allow(<%= @model_class %>).to receive(:find_by).with(id: <%= @variable_subject %>_id).and_return(nil)
79
+ <% end -%>
80
+
81
+ result = repository.call(builder: true)
82
+
83
+ expect(result).to be_failure
84
+ expect(result.failure).to eq('<%= @subject_class %> not found')
85
+ end
86
+ end
87
+ end
88
+ end
@@ -1,18 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class Core::Repositories::<%= @scope_class %>::<%= @repository_class %> < Core::Repositories::AbstractRepository
3
+ class <%= domain_class_name %>::Repositories::<%= @scope_class %>::<%= @repository_class %> < <%= domain_class_name %>::Repositories::AbstractRepository
4
4
  def initialize(params:)
5
5
  @params = params
6
6
  @id = @params.id
7
7
  end
8
8
 
9
9
  def call(builder: true)
10
- <% if @resource_owner_id.present? -%>
10
+ <% if @resource_owner_id.present? && @has_resource_owner_id_in_fetch_by_id_contract -%>
11
11
  resource = <%= @model_class %>.find_by(id: @id, <%=@resource_owner_id%>: @params.<%=@resource_owner_id%>)
12
12
  <% else -%>
13
13
  resource = <%= @model_class %>.find_by(id: @id)
14
14
  <% end -%>
15
15
  return Failure '<%= @subject_class %> not found' unless resource.present?
16
- Success Core::Builders::<%= @subject_class %>.new(resource).build
16
+ Success <%= domain_class_name %>::Builders::<%= @subject_class %>.new(resource).build
17
17
  end
18
18
  end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ RSpec.describe <%= domain_class_name %>::Repositories::<%= @scope_class %>::<%= @repository_class %>, type: :repository do
6
+ describe '#call' do
7
+ let(:builder) { instance_double(<%= domain_class_name %>::Builders::<%= @subject_class %>) }
8
+ let(:entity) { instance_double(<%= domain_class_name %>::Entities::<%= @subject_class %>) }
9
+ let(:<%= @variable_subject %>) { instance_double(<%= @model_class %>) }
10
+ let(:<%= @variable_subject %>_id) { 'test-id-123' }
11
+
12
+ let(:valid_params) do
13
+ Hashie::Mash.new({
14
+ id: <%= @variable_subject %>_id<% if @resource_owner_id.present? && @has_resource_owner_id_in_fetch_by_id_contract %>,
15
+ <%= @resource_owner_id %>: '<%= @resource_owner_id %>_value'<% end %>
16
+ })
17
+ end
18
+
19
+ subject(:repository) { described_class.new(params: valid_params) }
20
+
21
+ before do
22
+ allow(<%= domain_class_name %>::Builders::<%= @subject_class %>).to receive(:new).with(<%= @variable_subject %>).and_return(builder)
23
+ allow(builder).to receive(:build).and_return(entity)
24
+ end
25
+
26
+ context 'when <%= @variable_subject %> exists' do
27
+ it 'fetches the <%= @variable_subject %> and returns success with entity', :aggregate_failures do
28
+ <% if @resource_owner_id.present? && @has_resource_owner_id_in_fetch_by_id_contract -%>
29
+ allow(<%= @model_class %>).to receive(:find_by).with(
30
+ id: <%= @variable_subject %>_id,
31
+ <%= @resource_owner_id %>: valid_params.<%= @resource_owner_id %>
32
+ ).and_return(<%= @variable_subject %>)
33
+ <% else -%>
34
+ allow(<%= @model_class %>).to receive(:find_by).with(id: <%= @variable_subject %>_id).and_return(<%= @variable_subject %>)
35
+ <% end -%>
36
+
37
+ result = repository.call(builder: true)
38
+
39
+ expect(result).to be_success
40
+ expect(result.value!).to eq(entity)
41
+ end
42
+ end
43
+
44
+ context 'when <%= @variable_subject %> does not exist' do
45
+ it 'returns failure with not found message' do
46
+ <% if @resource_owner_id.present? && @has_resource_owner_id_in_fetch_by_id_contract -%>
47
+ allow(<%= @model_class %>).to receive(:find_by).with(
48
+ id: <%= @variable_subject %>_id,
49
+ <%= @resource_owner_id %>: valid_params.<%= @resource_owner_id %>
50
+ ).and_return(nil)
51
+ <% else -%>
52
+ allow(<%= @model_class %>).to receive(:find_by).with(id: <%= @variable_subject %>_id).and_return(nil)
53
+ <% end -%>
54
+
55
+ result = repository.call(builder: true)
56
+
57
+ expect(result).to be_failure
58
+ expect(result.failure).to eq('<%= @subject_class %> not found')
59
+ end
60
+ end
61
+ end
62
+ end
@@ -1,23 +1,28 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class Core::Repositories::<%= @scope_class %>::<%= @repository_class%> < Core::Repositories::AbstractRepository
3
+ class <%= domain_class_name %>::Repositories::<%= @scope_class %>::<%= @repository_class %> < <%= domain_class_name %>::Repositories::AbstractRepository
4
+ include Pagy::Backend
5
+
4
6
  def initialize(params:)
5
7
  @params = prepare! params, sanitize: true
6
8
  build_pagination_variable! @params
7
9
  end
8
10
 
9
11
  def call(builder: true)
10
- <% if @resource_owner_id.present? -%>
11
- resources = <%= @model_class %>.where(<%=@resource_owner_id%>: @params.<%=@resource_owner_id%>)
12
+ <% if @resource_owner_id.present? && @has_resource_owner_id_in_list_contract -%>
13
+ resources = <%= @model_class %>.where(<%= @resource_owner_id %>: @params.<%= @resource_owner_id %>)
12
14
  <% else -%>
13
15
  resources = <%= @model_class %>
14
16
  <% end -%>
15
- if @search.present? && @search_able.any?
16
- resources = resources.where("<%= @search_able.map { |f| "LOWER(#{f}) LIKE :search" }.join(' OR ') %>", search: "%#{@search.to_s.downcase}%")
17
+ <% if @search_able.present? && @search_able.any? -%>
18
+ if @search.present?
19
+ resources = resources.where("<%= (@search_able || []).map { |f| "LOWER(#{f}) LIKE :search" }.join(' OR ') %>", search: "%#{@search.to_s.downcase}%")
17
20
  end
18
- return Success Hashie::Mash.new(response: [], meta: {}) unless resources.present?
21
+ <% end -%>
22
+ return Success Hashie::Mash.new({response: [], meta: {}}) unless resources.present?
19
23
  pagy, results = pagy(resources.order(created_at: :desc), limit: @per_page, page: @page)
20
- response = results.map { |result| Core::Builders::<%= @subject_class %>.new(result).build }
21
- Success Hashie::Mash.new(response: response, meta: paginate!(pagy))
24
+ response = results.map { |result| <%= domain_class_name %>::Builders::<%= @subject_class %>.new(result).build }
25
+ Success Hashie::Mash.new({response: response, meta: paginate!(pagy)})
22
26
  end
27
+
23
28
  end
@@ -0,0 +1,190 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ RSpec.describe <%= domain_class_name %>::Repositories::<%= @scope_class %>::<%= @repository_class %>, type: :repository do
6
+ describe '#call' do
7
+ let(:params) do
8
+ {
9
+ <% if @resource_owner_id.present? -%>
10
+ <%= @resource_owner_id %>: SecureRandom.uuid,
11
+ <% end -%>
12
+ page: 1,
13
+ items: 10
14
+ }
15
+ end
16
+
17
+ let(:repository) { described_class }
18
+
19
+ context 'when fetching list successfully' do
20
+ before do
21
+ <% if @resource_owner_id.present? -%>
22
+ create_list(:<%= @variable_subject %>, 3, <%= @resource_owner_id %>: params[:<%= @resource_owner_id %>])
23
+ <% else -%>
24
+ create_list(:<%= @variable_subject %>, 3)
25
+ <% end -%>
26
+ end
27
+ it 'returns paginated <%= @scope_path %>', :aggregate_failures do
28
+ result = repository.new(params: params).call
29
+
30
+ expect(result.success[:response]).to be_an(Array)
31
+ end
32
+
33
+ it 'returns correct number of items per page' do
34
+ result = repository.new(params: params).call
35
+
36
+ expect(result.success[:response].length).to be <= params[:items]
37
+ end
38
+ end
39
+
40
+ <% if @search_able.present? && @search_able.any? -%>
41
+ context 'with search filters' do
42
+ <% @search_able.each do |search_field| -%>
43
+ it 'filters by <%= search_field %>', :aggregate_failures do
44
+ <% if @resource_owner_id.present? -%>
45
+ # Create items with matching and non-matching <%= search_field %>
46
+ matching_item = create(:<%= @variable_subject %>, <%= @resource_owner_id %>: params[:<%= @resource_owner_id %>], <%= search_field %>: 'SearchTerm123')
47
+ non_matching_item = create(:<%= @variable_subject %>, <%= @resource_owner_id %>: params[:<%= @resource_owner_id %>], <%= search_field %>: 'DifferentValue')
48
+ <% else -%>
49
+ # Create items with matching and non-matching <%= search_field %>
50
+ matching_item = create(:<%= @variable_subject %>, <%= search_field %>: 'SearchTerm123')
51
+ non_matching_item = create(:<%= @variable_subject %>, <%= search_field %>: 'DifferentValue')
52
+ <% end -%>
53
+
54
+ params[:search] = 'searchterm'
55
+ result = repository.new(params: params).call
56
+
57
+ expect(result.success[:response]).to be_an(Array)
58
+ expect(result.success[:meta]).to be_present
59
+ # Verify that matching item is included
60
+ response_ids = result.success[:response].map { |item| item[:id] }
61
+ expect(response_ids).to include(matching_item.id)
62
+ # Verify that non-matching item is not included
63
+ expect(response_ids).not_to include(non_matching_item.id)
64
+ end
65
+
66
+ <% end -%>
67
+ it 'performs case-insensitive search', :aggregate_failures do
68
+ <% if @resource_owner_id.present? -%>
69
+ item = create(:<%= @variable_subject %>, <%= @resource_owner_id %>: params[:<%= @resource_owner_id %>], <%= @search_able.first %>: 'UPPERCASE_VALUE')
70
+ <% else -%>
71
+ item = create(:<%= @variable_subject %>, <%= @search_able.first %>: 'UPPERCASE_VALUE')
72
+ <% end -%>
73
+
74
+ params[:search] = 'uppercase'
75
+ result = repository.new(params: params).call
76
+
77
+ expect(result.success[:response]).to be_present
78
+ response_ids = result.success[:response].map { |item| item[:id] }
79
+ expect(response_ids).to include(item.id)
80
+ end
81
+
82
+ it 'returns empty result when no matches found' do
83
+ params[:search] = 'NonExistentValue12345'
84
+ result = repository.new(params: params).call
85
+
86
+ expect(result.success[:response]).to be_an(Array)
87
+ expect(result.success[:response]).to be_empty
88
+ expect(result.success[:meta]).to be_empty
89
+ end
90
+ end
91
+ <% else -%>
92
+ context 'with search filters' do
93
+ # Add search filter tests here if needed
94
+ end
95
+ <% end -%>
96
+
97
+ <% if @resource_owner_id.present? -%>
98
+ context 'with resource owner filter' do
99
+ let(:other_owner_id) { SecureRandom.uuid }
100
+
101
+ before do
102
+ # Create items for different owners
103
+ create_list(:<%= @variable_subject %>, 2, <%= @resource_owner_id %>: params[:<%= @resource_owner_id %>])
104
+ create_list(:<%= @variable_subject %>, 2, <%= @resource_owner_id %>: other_owner_id)
105
+ end
106
+
107
+ it 'filters by resource owner', :aggregate_failures do
108
+ result = repository.new(params: params).call
109
+
110
+ expect(result.success[:response]).to be_present
111
+ expect(result.success[:response]).to be_an(Array)
112
+ # Verify all returned items belong to the specified owner
113
+ result.success[:response].each do |item|
114
+ expect(item[:<%= @resource_owner_id %>]).to eq(params[:<%= @resource_owner_id %>])
115
+ end
116
+ expect(result.success[:meta][:total_count]).to eq(2)
117
+ end
118
+ end
119
+ <% end -%>
120
+
121
+ context 'with pagination' do
122
+ before do
123
+ <% if @resource_owner_id.present? -%>
124
+ # Create 10 items for pagination testing
125
+ create_list(:<%= @variable_subject %>, 10, <%= @resource_owner_id %>: params[:<%= @resource_owner_id %>])
126
+ <% else -%>
127
+ # Create 10 items for pagination testing
128
+ create_list(:<%= @variable_subject %>, 10)
129
+ <% end -%>
130
+ end
131
+
132
+ it 'paginates correctly with page 3 and items 3', :aggregate_failures do
133
+ params[:page] = 3
134
+ params[:items] = 3
135
+
136
+ result = repository.new(params: params).call
137
+
138
+ expect(result.success[:response]).to be_an(Array)
139
+ expect(result.success[:meta][:page]).to eq(3)
140
+ expect(result.success[:meta][:total_count]).to eq(10)
141
+ end
142
+
143
+ it 'returns empty array for page beyond available pages' do
144
+ params[:page] = 999
145
+ params[:items] = 10
146
+
147
+ result = repository.new(params: params).call
148
+
149
+ expect(result.success[:response]).to be_an(Array)
150
+ expect(result.success[:response]).to be_empty
151
+ expect(result.success[:meta][:total_count]).to eq(10)
152
+ end
153
+ end
154
+
155
+ context 'with sorting' do
156
+ before do
157
+ <% if @resource_owner_id.present? -%>
158
+ create_list(:<%= @variable_subject %>, 3, <%= @resource_owner_id %>: params[:<%= @resource_owner_id %>])
159
+ <% else -%>
160
+ create_list(:<%= @variable_subject %>, 3)
161
+ <% end -%>
162
+ end
163
+
164
+ it 'sorts by created_at descending by default', :aggregate_failures do
165
+ result = repository.new(params: params).call
166
+
167
+ expect(result.success[:response]).to be_present
168
+ expect(result.success[:response].length).to be > 0
169
+
170
+ # Verify descending order (newest first)
171
+ timestamps = result.success[:response].map { |item| item[:created_at] }
172
+ expect(timestamps).to eq(timestamps.sort.reverse)
173
+ end
174
+ end
175
+
176
+ context 'when no resources exist' do
177
+ before do
178
+ <%= @model_class %>.destroy_all
179
+ end
180
+
181
+ it 'returns empty response with zero count', :aggregate_failures do
182
+ result = repository.new(params: params).call
183
+
184
+ expect(result.success[:response]).to be_an(Array)
185
+ expect(result.success[:response]).to be_empty
186
+ expect(result.success[:meta]).to be_empty
187
+ end
188
+ end
189
+ end
190
+ end
@@ -1,13 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class Core::Repositories::<%= @scope_class %>::<%= @repository_class %> < Core::Repositories::AbstractRepository
3
+ class <%= domain_class_name %>::Repositories::<%= @scope_class %>::<%= @repository_class %> < <%= domain_class_name %>::Repositories::AbstractRepository
4
4
  def initialize(params:)
5
5
  @id = params.id
6
6
  @params = prepare! params.except(:id), sanitize: true
7
7
  end
8
8
 
9
9
  def call(builder: true)
10
- <% if @resource_owner_id.present? -%>
10
+ <% if @resource_owner_id.present? && @has_resource_owner_id_in_update_contract -%>
11
11
  resource = <%= @model_class %>.find_by(id: @id, <%=@resource_owner_id%>: @params.<%=@resource_owner_id%>)
12
12
  <% else -%>
13
13
  resource = <%= @model_class %>.find_by(id: @id)
@@ -16,12 +16,12 @@ class Core::Repositories::<%= @scope_class %>::<%= @repository_class %> < Core::
16
16
  <% if @uploaders.present? -%>
17
17
  # Remove the existing images if a new one is being uploaded
18
18
  <% @uploaders.each do |uplaoder| -%>
19
- resource.<%=uplaoder %>.purge if @params.<%=uplaoder %>.present? && resource.<%=uplaoder %>.attached?
19
+ resource.<%=uplaoder.name %>.purge if @params.<%=uplaoder.name %>.present? && resource.<%=uplaoder.name %>.attached?
20
20
  <% end -%>
21
21
  <% end -%>
22
22
  unless resource.update(@params.to_h)
23
23
  return Failure build_errors(resource)
24
24
  end
25
- Success Core::Builders::<%= @subject_class %>.new(resource).build
25
+ Success <%= domain_class_name %>::Builders::<%= @subject_class %>.new(resource).build
26
26
  end
27
27
  end