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_selecturčuje, jaké informace chcete mít ve výsledkuquery_wherevytvoří všechny podmínky vyhledávání a opustí vstup, aby zabránil injekcím SQLquery_tablesje seznam všech tabulek, které potřebujete prohledávattable_name = table.constantize.table_namevám poskytne SQL název_tabulky, jak jej používá modelraw_queryje 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.