Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,6 @@
.ruby-version
.env.dev
.env.development

.direnv/
.envrc
7 changes: 5 additions & 2 deletions apps/web/controllers/vacancies/index.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ class Index

include Import[
'libs.search_query_parser',
operation: 'vacancies.operations.list'
operation: 'vacancies.operations.list',
search_options_mapper: 'vacancies.mappers.search_options',

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

не принципиально, но тут лишняя запятая

]

EMPTY_SEARCH_QUERY = {}.freeze
Expand All @@ -35,7 +36,9 @@ def call(params)
private

def search_query
params[:query] ? search_query_parser.call(params[:query]) : EMPTY_SEARCH_QUERY
query_attributes = params[:query] ? search_query_parser.call(params[:query]) : EMPTY_SEARCH_QUERY
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

а еще лучше, я бы сделал так, что квери парсер возвращал бы сразу что надо, вне зависимости от того, что туда передать, что-то в таком духе:

query_attributes = search_query_parser.call(params[:query])

query_attributes # => attributes or initial_attributes

initial_attributes = { remote: nil, position_type: nil, location: nil }
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

я бы в константу это вынес

search_options_mapper.call(initial_attributes.merge(query_attributes))
end
end
end
Expand Down
25 changes: 21 additions & 4 deletions lib/core/queries/vacancy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,35 @@ def initialize(repo = VacancyRepository.new)
@repo = repo
end

def all_with_contact(limit:, page:)
all_with_contact_relation(limit: limit, page: page).to_a
def all_with_contact(limit:, page:, search_query:)
all_with_contact_relation(limit: limit, page: page, search_query: search_query).to_a
end

def pager_for_all_with_contact(limit:, page:)
def pager_for_all_with_contact(limit:, page:, search_query:)
Hanami::Pagination::Pager.new(
all_with_contact_relation(limit: limit, page: page).pager
all_with_contact_relation(limit: limit, page: page, search_query: search_query).pager
)
end

private

QUERY_MODIFIERS = {
remote: ->(query, filter_value) { query.where(remote_available: filter_value) },
position_type: ->(query, filter_value) { query.where(position_type: filter_value) },
location: ->(query, filter_value) { query.where { location.ilike("%#{filter_value}%") } }
}.freeze

def new_all_with_contact_relation(limit:, page:, search_query:)
query = repo.aggregate(:contact)
.where(published: true, archived: false, deleted_at: nil)
search_query.to_h.each do |key, value|
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

реально оптимизировать этот кусок? что бы при nil код не выполнялся?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Не совсем понял вопрос

Copy link

@JuPlutonic JuPlutonic Oct 13, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

может быть:

if search_query
 ...
end
search_query.to_h.each do |key, value|

modifier = QUERY_MODIFIERS[key]
query = modifier.call(query, value) if modifier && value
end
query.map_to(::Vacancy).order { created_at.desc }
.per_page(limit).page(page || 1)
end

def all_with_contact_relation(limit:, page:)
repo.aggregate(:contact)
.where(published: true, deleted_at: nil)
Expand Down
11 changes: 11 additions & 0 deletions lib/vacancies/entities/search_options.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# frozen_string_literal: true

module Vacancies
module Entities
class SearchOptions < Dry::Struct
attribute :remote, Core::Types::Strict::Bool.optional.default(nil)
attribute :position_type, Core::Types::VacancyPositionTypes.optional.default(nil)
attribute :location, Core::Types::Strict::String.optional.default(nil)
end
end
end
18 changes: 18 additions & 0 deletions lib/vacancies/mappers/search_options.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# frozen_string_literal: true

module Vacancies
module Mappers
Container = Module.new do
extend Transproc::Registry
import Transproc::HashTransformations
import Transproc::Coercions
import Transproc::ClassTransformations
end

class SearchOptions < Transproc::Transformer[Container]
symbolize_keys
map_value :remote, t(:to_boolean)
constructor_inject ::Vacancies::Entities::SearchOptions
end
end
end
10 changes: 7 additions & 3 deletions lib/vacancies/operations/list.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,13 @@ class List < ::Libs::Operation

PAGINATION_LIMIT = 10

def call(search_query: {}, page: 1) # rubocop:disable Lint/UnusedMethodArgument
pager = vacancy_query.pager_for_all_with_contact(limit: PAGINATION_LIMIT, page: page || 1)
result = vacancy_query.all_with_contact(limit: PAGINATION_LIMIT, page: page || 1)
def call(search_query: {}, page: 1)
pager = vacancy_query.pager_for_all_with_contact(
limit: PAGINATION_LIMIT,
page: page || 1,
search_query: search_query
)
result = vacancy_query.all_with_contact(limit: PAGINATION_LIMIT, page: page || 1, search_query: search_query)

Success(result: result, pager: pager)
end
Expand Down
56 changes: 54 additions & 2 deletions spec/core/queries/vacancy_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,27 @@

RSpec.describe Queries::Vacancy, type: :query do
let(:repo) { described_class.new }
let(:query_attributes) { return { remote: nil, position_type: nil, location: nil } }
let(:search_query) { Vacancies::Entities::SearchOptions.new }

describe '#all_with_contact' do
subject { repo.all_with_contact(limit: 10, page: 1) }
subject { repo.all_with_contact(limit: 10, page: 1, search_query: search_query) }

before { Fabricate.create(:vacancy, published: published, archived_at: archived_at, deleted_at: deleted_at) }
let(:remote_available) { nil }
let(:position_type) { nil }
let(:location) { nil }

before do
Fabricate.create(
:vacancy,
published: published,
archived: archived,
deleted_at: deleted_at,
remote_available: remote_available,
position_type: position_type,
location: location
)
end

context 'when vacancy published and not archived or deleted' do
let(:published) { true }
Expand All @@ -16,6 +32,42 @@
it { expect(subject.count).to eq(1) }
it { expect(subject).to all(be_a(Vacancy)) }
it { expect(subject.first.contact).to be_a(Contact) }

context 'and remote in search_query is true' do
let(:search_query) { Vacancies::Entities::SearchOptions.new(query_attributes.merge(remote: true)) }

it { expect(subject).to eq([]) }

context 'and remote_available in record is true as well' do
let(:remote_available) { true }

it { expect(subject.count).to eq(1) }
end
end

context 'and position_type in search_query is equal "other"' do
let(:search_query) { Vacancies::Entities::SearchOptions.new(query_attributes.merge(position_type: 'other')) }

it { expect(subject).to eq([]) }

context 'and position_type in record is "other" as well' do
let(:position_type) { 'other' }

it { expect(subject.count).to eq(1) }
end
end

context 'and location in search query is not empty' do
let(:search_query) { Vacancies::Entities::SearchOptions.new(query_attributes.merge(location: 'VASYUKI')) }

it { expect(subject).to eq([]) }

context 'and location in record includes location from search query' do
let(:location) { 'New Vasyuki' }

it { expect(subject.count).to eq(1) }
end
end
end

context 'when vacancy published and archived' do
Expand Down
17 changes: 17 additions & 0 deletions spec/vacancies/mappers/search_options_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# frozen_string_literal: true

RSpec.describe Vacancies::Mappers::SearchOptions, type: :mapper do
subject { described_class.new.call(search_options_hash) }

let(:search_options_hash) { { remote: nil, position_type: 'other', location: 'New Vasyuki' } }

it { expect(subject).to be_a(Vacancies::Entities::SearchOptions) }
it { expect(subject.position_type).to eq(search_options_hash[:position_type]) }
it { expect(subject.location).to eq(search_options_hash[:location]) }

context 'when remote is string equaled "true"' do
let(:search_options_hash) { { remote: 'true', position_type: nil, location: nil } }

it { expect(subject.remote).to be_truthy }
end
end
3 changes: 2 additions & 1 deletion spec/web/controllers/vacancies/index_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@

context 'when params inlcludes query param' do
let(:params) { { query: 'remote:true search text' } }
let(:search_query) { Vacancies::Entities::SearchOptions.new(remote: true, location: nil, position_type: nil) }

it { expect(subject).to be_success }

it do
expect(operation).to receive(:call).with(page: nil, search_query: { remote: 'true', text: 'search text' })
expect(operation).to receive(:call).with(page: nil, search_query: search_query)
subject
end
end
Expand Down