puts “Hello Folks!”
This week, I was working on several small things. Firstly, I was working on perfecting the improvements PR #402 (awaiting feedback). The current structure that I’ve proposed follows the adapter design pattern. The basic idea is having two different adapters for solr
and pg
and doing dependency injection in the search module with the required adapter according to the production environment.
class Adapter
def initialize(relation)
@relation = relation
# Condition to change adapters will go here
@adapter = ENV['USE_SOLR'] == 'true' ? SolrAdapter : PGAdapter
end
def call(query)
@adapter.send("search_#{@relation.name.downcase}", @relation, query)
end
End
class PGAdapter
def self.search_project(relation, query)
# pg specific search logic for project
end
def self.search_user(relation, query)
# pg specific search logic for users
end
end
# Similarly, a SolrAdapter will be defined
This adapter will be used inside the query object for the model like so:
# inside constructor of ProjectQuery
@adapter = Adapter.new(relation)
# Querying a resource
@adapter.call(query)
This method of adapter implementation scales very easily across no of adapters and query models. It also follows the SOLID rule of developement. All the changes regarding this proposal can be found in #8345f3
So now the search operates basically in 4 layers -
SearchController
- Here, SearchHelper
is used to get the search result.
SearchHelper
- Acts as a factory for query objects corresponding to each model. The factory design pattern is also very common in Java.
ProjectQuery
& UserQuery
- Calls on instance of Adapter
to execute query.
Adapter
- Has either of PGAdapter
or SolrAdapter
injected, which have the environment-specific logic for querying.
Before arriving at this approach, I experimented with a lot of different approaches and as it is so rightly said,
Failure is simply an opportunity to begin again, this time more intelligently.
I would like to talk about one another approach that I implemented in #6c93d8 using Ruby mixins.
module GenericQuery
MAX_RESULTS_PER_PAGE = 5
def call(query_params, relation = nil)
object = relation.present? ? new(relation) : new
object.query(query_params[:q]).paginate(page: query_params[:page],
per_page: MAX_RESULTS_PER_PAGE)
end
end
class ProjectsQuery
extend GenericQuery
attr_reader :relation
def initialize(relation = Project.all)
@relation = relation
end
def query(query)
relation.includes(:author, :tags).search(query).
select("id,author_id,image_preview,name,description,view")
end
end
Now projects can be queried like so:
ProjectsQuery.call(query_params, Project.public_and_not_forked)
But, Ruby mixins are in essence, similar to inheritance, and composition (used in the previous approach) is usually preferred over inheritance in software development. More about it here.
rake interactive_book:ci:install
The Interactive-Book, is an awesome effort CircuitVerse to provide the youngsters with a comprehensive understanding of digital logic design through various plug and play demonstrations. It is also open-source and is being worked on by Aman Singla. I worked on adding a basic circle-ci config #11 to tests builds against various contributions that are being made to it.
Work.next?
The second evaluation begins from today and ends on the 26th. Meanwhile, I’ll be working on my bucket list #412. The first task in the list that I’ll be tackling is:
Until the next update,
Written on July 22nd , 2019 by Ankit KatariaHasta la vista!