Puoi creare una query SQL basata sul tuo hash. L'approccio più generico è l'SQL grezzo, che può essere eseguito da ActiveRecord
.
Ecco qualche codice concettuale che dovrebbe darti l'idea giusta:
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
A cosa serve:
query_select
specifica quali informazioni desideri nel risultatoquery_where
crea tutte le condizioni di ricerca ed esegue l'escape dell'input per prevenire iniezioni SQLquery_tables
è un elenco di tutte le tabelle che devi cercaretable_name = table.constantize.table_name
ti darà il nome_tabella SQL usato dal modelloraw_query
è la query sql combinata effettiva dalle parti precedentiActiveRecord::Base.connection.execute(raw_query)
esegue sql sul database
Assicurati di mettere tra virgolette l'input inviato dall'utente ed evitarlo correttamente per evitare iniezioni SQL.
Per il tuo esempio la query creata sarà simile a questa:
select * from companies, categories where 'companies'.'name' LIKE 'a%' AND 'companies'.'hq_city' = 'karachi' AND 'categories'.'name' NOT LIKE '%ECommerce%'
Questo approccio potrebbe richiedere una logica aggiuntiva per unire le tabelle correlate. Nel tuo caso, se company
e category
hai un'associazione, devi aggiungere qualcosa di simile a query_where
"AND 'company'.'category_id' = 'categories'.'id'"
Approccio facile: È possibile creare un hash per tutte le coppie di modelli/tabelle che possono essere interrogate e memorizzare lì la condizione di join appropriata. Questo Hash non dovrebbe essere troppo complesso nemmeno per un progetto di medie dimensioni.
Approccio difficile: Questo può essere fatto automaticamente, se hai has_many
, has_one
e belongs_to
correttamente definito nei tuoi modelli. Puoi ottenere le associazioni di un modello utilizzando reflect_on_all_associations . Implementa una Breath-First-Search
o Depth-First Search
algoritmo e inizia con qualsiasi modello e cerca le associazioni corrispondenti ad altri modelli dal tuo input json. Avvia nuove esecuzioni BFS/DFS finché non sono rimasti modelli non visitati dall'input json. Dalle informazioni trovate, puoi derivare tutte le condizioni di unione e quindi aggiungerle come espressioni nel where
clausola dell'approccio sql grezzo come spiegato sopra. Ancora più complesso, ma anche fattibile sarebbe la lettura del database schema
e utilizzando un approccio simile, come definito qui, cercando foreign keys
.
Utilizzo delle associazioni: Se tutti sono associati a has_many
/ has_one
, puoi gestire i join con ActiveRecord
utilizzando i joins
metodo con inject
sul modello "più significativo" come questo:
base_model = "Company".constantize
assocations = [:categories] # and so on
result = assocations.inject(base_model) { |model, assoc| model.joins(assoc) }.where(query_where)
A cosa serve:
- passa il base_model come input iniziale a Enumerable.inject
, che chiamerà ripetutamente input.send(:joins, :assoc) (per il mio esempio questo farebbe
Company.send(:joins, :categories)
che equivale a `Company.categories - sul join combinato, esegue le condizioni where (costruite come descritto sopra)
Disclaimer L'esatta sintassi di cui hai bisogno potrebbe variare in base all'implementazione SQL che utilizzi.