U kunt een SQL-query maken op basis van uw hash. De meest generieke benadering is onbewerkte SQL, die kan worden uitgevoerd door ActiveRecord
.
Hier is wat conceptcode die u het juiste idee zou moeten geven:
query_select = "select * from "
query_where = ""
tables = [] # for selecting from all tables
hash.each do |table, values|
table_name = table.constantize.table_name
tables << table_name
values.each do |q|
query_where += " AND " unless query_string.empty?
query_where += "'#{ActiveRecord::Base.connection.quote(table_name)}'."
query_where += "'#{ActiveRecord::Base.connection.quote(q[fieldName)}'"
if q[:operator] == "starts with" # this should be done with an appropriate method
query_where += " LIKE '#{ActiveRecord::Base.connection.quote(q[val)}%'"
end
end
end
query_tables = tables.join(", ")
raw_query = query_select + query_tables + " where " + query_where
result = ActiveRecord::Base.connection.execute(raw_query)
result.to_h # not required, but raw results are probably easier to handle as a hash
Wat dit doet:
query_select
specificeert welke informatie u in het resultaat wilt hebbenquery_where
bouwt alle zoekvoorwaarden op en ontsnapt aan invoer om SQL-injecties te voorkomenquery_tables
is een lijst van alle tabellen die je nodig hebt om te zoekentable_name = table.constantize.table_name
geeft u de SQL-tabelnaam zoals gebruikt door het modelraw_query
is de daadwerkelijke gecombineerde SQL-query uit de bovenstaande delenActiveRecord::Base.connection.execute(raw_query)
voert de sql uit op de database
Zorg ervoor dat alle door de gebruiker ingediende invoer tussen aanhalingstekens wordt geplaatst en op de juiste manier wordt ontsnapt om SQL-injecties te voorkomen.
Voor uw voorbeeld ziet de gemaakte zoekopdracht er als volgt uit:
select * from companies, categories where 'companies'.'name' LIKE 'a%' AND 'companies'.'hq_city' = 'karachi' AND 'categories'.'name' NOT LIKE '%ECommerce%'
Voor deze aanpak is mogelijk extra logica nodig om tabellen samen te voegen die gerelateerd zijn. In uw geval, als company
en category
een associatie hebt, moet je zoiets toevoegen aan de query_where
"AND 'company'.'category_id' = 'categories'.'id'"
Eenvoudige aanpak: U kunt een hash maken voor alle paren van modellen/tabellen die kunnen worden opgevraagd en de juiste join-voorwaarde daar opslaan. Deze hash zou zelfs voor een middelgroot project niet te ingewikkeld moeten zijn.
Harde aanpak: Dit kan automatisch worden gedaan, als u has_many
. heeft , has_one
en belongs_to
goed gedefinieerd in uw modellen. U kunt de associaties van een model verkrijgen met behulp van reflect_on_all_associations . Implementeer een Breath-First-Search
of Depth-First Search
algoritme en begin met elk model en zoek naar overeenkomende associaties met andere modellen vanuit uw json-invoer. Start nieuwe BFS/DFS-runs totdat er geen niet-bezochte modellen van de json-invoer meer zijn. Uit de gevonden informatie kunt u alle voorwaarden voor deelname afleiden en deze vervolgens als expressies toevoegen aan de where
clausule van de ruwe sql-aanpak zoals hierboven uitgelegd. Nog ingewikkelder, maar ook goed te doen, is het lezen van de database schema
en met behulp van een vergelijkbare benadering zoals hier gedefinieerd door te zoeken naar foreign keys
.
Associaties gebruiken: Als ze allemaal zijn gekoppeld aan has_many
/ has_one
, kunt u de joins afhandelen met ActiveRecord
door gebruik te maken van de joins
methode met inject
op het "meest significante" model als volgt:
base_model = "Company".constantize
assocations = [:categories] # and so on
result = assocations.inject(base_model) { |model, assoc| model.joins(assoc) }.where(query_where)
Wat dit doet:
- het geeft het basismodel door als startinvoer aan Enumerable.inject
, die herhaaldelijk input.send(:joins, :assoc) zal aanroepen (in mijn voorbeeld zou dit
Company.send(:joins, :categories)
doen wat gelijk is aan `Bedrijf.categorie - op de gecombineerde join voert het de waar-voorwaarden uit (geconstrueerd zoals hierboven beschreven)
Disclaimer De exacte syntaxis die u nodig heeft, kan variëren, afhankelijk van de SQL-implementatie die u gebruikt.