Vous pouvez créer une requête SQL basée sur votre hachage. L'approche la plus générique est le SQL brut, qui peut être exécuté par ActiveRecord
.
Voici un code conceptuel qui devrait vous donner la bonne idée :
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
Qu'est-ce que cela fait :
query_select
spécifie quelles informations vous voulez dans le résultatquery_where
construit toutes les conditions de recherche et échappe les entrées pour empêcher les injections SQLquery_tables
est une liste de toutes les tables que vous devez recherchertable_name = table.constantize.table_name
vous donnera le nom_table SQL tel qu'utilisé par le modèleraw_query
est la requête SQL combinée réelle des parties ci-dessusActiveRecord::Base.connection.execute(raw_query)
exécute le sql sur la base de données
Assurez-vous de placer toute entrée soumise par l'utilisateur entre guillemets et de l'échapper correctement pour éviter les injections SQL.
Pour votre exemple, la requête créée ressemblera à ceci :
select * from companies, categories where 'companies'.'name' LIKE 'a%' AND 'companies'.'hq_city' = 'karachi' AND 'categories'.'name' NOT LIKE '%ECommerce%'
Cette approche peut nécessiter une logique supplémentaire pour joindre des tables liées. Dans votre cas, si company
et category
avoir une association, vous devez ajouter quelque chose comme ceci au query_where
"AND 'company'.'category_id' = 'categories'.'id'"
Approche simple : Vous pouvez créer un hachage pour toutes les paires de modèles/tables pouvant être interrogées et y stocker la condition de jointure appropriée. Ce hachage ne devrait pas être trop complexe, même pour un projet de taille moyenne.
Approche dure : Cela peut être fait automatiquement, si vous avez has_many
, has_one
et belongs_to
correctement définis dans vos modèles. Vous pouvez obtenir les associations d'un modèle en utilisant reflect_on_all_associations . Implémenter une Breath-First-Search
ou Depth-First Search
algorithm et commencez par n'importe quel modèle et recherchez les associations correspondantes avec d'autres modèles à partir de votre entrée json. Démarrez de nouvelles exécutions BFS/DFS jusqu'à ce qu'il ne reste plus de modèles non visités à partir de l'entrée json. À partir des informations trouvées, vous pouvez dériver toutes les conditions de jointure, puis les ajouter en tant qu'expressions dans le where
clause de l'approche SQL brute comme expliqué ci-dessus. Encore plus complexe, mais aussi faisable serait de lire la base de données schema
et en utilisant une approche similaire à celle définie ici en recherchant des foreign keys
.
Utiliser des associations : Si tous sont associés à has_many
/ has_one
, vous pouvez gérer les jointures avec ActiveRecord
en utilisant les joins
méthode avec inject
sur le modèle "le plus significatif" comme ceci :
base_model = "Company".constantize
assocations = [:categories] # and so on
result = assocations.inject(base_model) { |model, assoc| model.joins(assoc) }.where(query_where)
Qu'est-ce que cela fait :
- il passe le modèle de base comme entrée de départ à Enumerable.inject
, qui appellera à plusieurs reprises input.send(:joins, :assoc) (pour mon exemple, cela ferait
Company.send(:joins, :categories)
qui équivaut à `Company.categories - sur la jointure combinée, il exécute les conditions where (construites comme décrit ci-dessus)
Avis de non-responsabilité La syntaxe exacte dont vous avez besoin peut varier en fonction de l'implémentation SQL que vous utilisez.