Puede crear una consulta SQL basada en su hash. El enfoque más genérico es SQL sin procesar, que puede ser ejecutado por ActiveRecord
.
Aquí hay un código de concepto que debería darle la idea correcta:
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é hace esto:
query_select
especifica qué información desea en el resultadoquery_where
crea todas las condiciones de búsqueda y escapa de la entrada para evitar inyecciones de SQLquery_tables
es una lista de todas las tablas que necesita buscartable_name = table.constantize.table_name
le dará el nombre de la tabla SQL tal como lo usa el modeloraw_query
es la consulta sql combinada real de las partes anterioresActiveRecord::Base.connection.execute(raw_query)
ejecuta el sql en la base de datos
Asegúrese de poner cualquier entrada enviada por el usuario entre comillas y escapar correctamente para evitar inyecciones de SQL.
Para su ejemplo, la consulta creada se verá así:
select * from companies, categories where 'companies'.'name' LIKE 'a%' AND 'companies'.'hq_city' = 'karachi' AND 'categories'.'name' NOT LIKE '%ECommerce%'
Este enfoque podría necesitar lógica adicional para unir tablas que están relacionadas. En su caso, si company
y category
tiene una asociación, debe agregar algo como esto a query_where
"AND 'company'.'category_id' = 'categories'.'id'"
Enfoque fácil: Puede crear un Hash para todos los pares de modelos/tablas que se pueden consultar y almacenar allí la condición de combinación adecuada. Este Hash no debería ser demasiado complejo incluso para un proyecto de tamaño mediano.
Enfoque difícil: Esto se puede hacer automáticamente, si tiene has_many
, has_one
y belongs_to
definido correctamente en sus modelos. Puede obtener las asociaciones de un modelo usando reflect_on_all_associations . Implementar un Breath-First-Search
o Depth-First Search
algoritmo y comience con cualquier modelo y busque asociaciones coincidentes con otros modelos desde su entrada json. Inicie nuevas ejecuciones de BFS/DFS hasta que no queden modelos no visitados de la entrada json. A partir de la información encontrada, puede derivar todas las condiciones de unión y luego agregarlas como expresiones en el where
cláusula del enfoque sql sin procesar como se explicó anteriormente. Aún más complejo, pero también factible, sería leer la base de datos schema
y usando un enfoque similar al definido aquí buscando foreign keys
.
Uso de asociaciones: Si todos ellos están asociados con has_many
/ has_one
, puede manejar las uniones con ActiveRecord
usando las joins
método con inject
en el modelo "más significativo" como este:
base_model = "Company".constantize
assocations = [:categories] # and so on
result = assocations.inject(base_model) { |model, assoc| model.joins(assoc) }.where(query_where)
Qué hace esto:
- pasa el modelo base como entrada inicial a Enumerable.inyectar
, que llamará repetidamente a input.send(:joins, :assoc) (para mi ejemplo, esto haría
Company.send(:joins, :categories)
que es equivalente a `Company.categories - en la unión combinada, ejecuta las condiciones where (construidas como se describe arriba)
Descargo de responsabilidad La sintaxis exacta que necesita puede variar según la implementación de SQL que utilice.