Můžete vytvořit SQL dotaz na základě vašeho hashe. Nejobecnějším přístupem je nezpracovaný SQL, který lze spustit pomocí ActiveRecord
.
Zde je nějaký koncepční kód, který by vám měl poskytnout správnou představu:
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
Co to dělá:
query_select
určuje, jaké informace chcete mít ve výsledkuquery_where
vytvoří všechny podmínky vyhledávání a opustí vstup, aby zabránil injekcím SQLquery_tables
je seznam všech tabulek, které potřebujete prohledávattable_name = table.constantize.table_name
vám poskytne SQL název_tabulky, jak jej používá modelraw_query
je skutečný kombinovaný dotaz SQL z výše uvedených částíActiveRecord::Base.connection.execute(raw_query)
spustí sql v databázi
Ujistěte se, že každý vstup odeslaný uživatelem vložíte do uvozovek a správně jej uzavřete, abyste zabránili vkládání SQL.
Pro váš příklad bude vytvořený dotaz vypadat takto:
select * from companies, categories where 'companies'.'name' LIKE 'a%' AND 'companies'.'hq_city' = 'karachi' AND 'categories'.'name' NOT LIKE '%ECommerce%'
Tento přístup může vyžadovat další logiku pro spojování tabulek, které spolu souvisí. Ve vašem případě, pokud company
a category
máte přidružení, musíte něco takového přidat do query_where
"AND 'company'.'category_id' = 'categories'.'id'"
Snadný přístup: Můžete vytvořit hash pro všechny páry modelů/tabulek, které lze dotazovat, a uložit tam příslušnou podmínku spojení. Tento hash by neměl být příliš složitý ani pro středně velký projekt.
Tvrdý přístup: To lze provést automaticky, pokud máte has_many
, has_one
a belongs_to
správně definované ve vašich modelech. Asociace modelu můžete získat pomocí reflect_on_all_associations . Implementujte Breath-First-Search
nebo Depth-First Search
algoritmus a začněte s jakýmkoli modelem a vyhledejte odpovídající asociace s jinými modely ze svého vstupu json. Spusťte nové běhy BFS/DFS, dokud nezůstanou žádné nenavštívené modely ze vstupu json. Z nalezených informací můžete odvodit všechny podmínky spojení a poté je přidat jako výrazy v where
klauzule přístupu raw sql, jak je vysvětleno výše. Ještě složitější, ale také proveditelné by bylo čtení databáze schema
a pomocí podobného přístupu, jak je zde definován, vyhledáním foreign keys
.
Použití přidružení: Pokud jsou všechny spojeny s has_many
/ has_one
, můžete spojení zpracovat pomocí ActiveRecord
pomocí joins
metodou inject
na "nejvýznamnějším" modelu, jako je tento:
base_model = "Company".constantize
assocations = [:categories] # and so on
result = assocations.inject(base_model) { |model, assoc| model.joins(assoc) }.where(query_where)
Co to dělá:
- předá základní_model jako počáteční vstup do Enumerable.inject
, který bude opakovaně volat input.send(:joins, :assoc) (pro můj příklad by to udělalo
Company.send(:joins, :categories)
což je ekvivalentní k `Společnost.kategorie - při kombinovaném spojení provede podmínky where (vytvořené podle popisu výše)
Odmítnutí odpovědnosti Přesná syntaxe, kterou potřebujete, se může lišit v závislosti na implementaci SQL, kterou používáte.