Anda dapat membuat kueri SQL berdasarkan hash Anda. Pendekatan yang paling umum adalah SQL mentah, yang dapat dieksekusi oleh ActiveRecord
.
Berikut adalah beberapa kode konsep yang seharusnya memberi Anda ide yang tepat:
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
Fungsinya:
query_select
menentukan informasi apa yang Anda inginkan dalam hasilquery_where
membangun semua kondisi pencarian dan menghindari input untuk mencegah injeksi SQLquery_tables
adalah daftar semua tabel yang perlu Anda caritable_name = table.constantize.table_name
akan memberi Anda SQL table_name seperti yang digunakan oleh modelraw_query
adalah kueri sql gabungan yang sebenarnya dari bagian di atasActiveRecord::Base.connection.execute(raw_query)
mengeksekusi sql pada database
Pastikan untuk memasukkan input yang dikirimkan pengguna dalam tanda kutip dan menghindarinya dengan benar untuk mencegah injeksi SQL.
Untuk contoh Anda, kueri yang dibuat akan terlihat seperti ini:
select * from companies, categories where 'companies'.'name' LIKE 'a%' AND 'companies'.'hq_city' = 'karachi' AND 'categories'.'name' NOT LIKE '%ECommerce%'
Pendekatan ini mungkin memerlukan logika tambahan untuk menggabungkan tabel yang terkait. Dalam kasus Anda, jika company
dan category
memiliki asosiasi, Anda harus menambahkan sesuatu seperti ini ke query_where
"AND 'company'.'category_id' = 'categories'.'id'"
Pendekatan mudah: Anda dapat membuat Hash untuk semua pasangan model/tabel yang dapat di-query dan menyimpan kondisi join yang sesuai di sana. Hash ini tidak boleh terlalu rumit bahkan untuk proyek berukuran sedang.
Pendekatan keras: Ini dapat dilakukan secara otomatis, jika Anda memiliki has_many
, has_one
dan belongs_to
didefinisikan dengan benar dalam model Anda. Anda bisa mendapatkan asosiasi model menggunakan reflect_on_all_associations . Terapkan Breath-First-Search
atau Depth-First Search
algoritma dan mulai dengan model apa pun dan cari asosiasi yang cocok dengan model lain dari input json Anda. Mulai menjalankan BFS/DFS baru hingga tidak ada model yang belum dikunjungi dari input json yang tersisa. Dari informasi yang ditemukan, Anda dapat memperoleh semua kondisi gabungan dan kemudian menambahkannya sebagai ekspresi di where
klausa pendekatan sql mentah seperti yang dijelaskan di atas. Bahkan lebih kompleks, tetapi juga bisa dilakukan dengan membaca schema
database dan menggunakan pendekatan serupa seperti yang didefinisikan di sini dengan mencari foreign keys
.
Menggunakan pengaitan: Jika semuanya terkait dengan has_many
/ has_one
, Anda dapat menangani penggabungan dengan ActiveRecord
dengan menggunakan joins
metode dengan inject
pada model "paling signifikan" seperti ini:
base_model = "Company".constantize
assocations = [:categories] # and so on
result = assocations.inject(base_model) { |model, assoc| model.joins(assoc) }.where(query_where)
Fungsinya:
- melewati base_model sebagai input awal ke Enumerable.inject
, yang akan berulang kali memanggil input.send(:joins, :assoc) (sebagai contoh saya ini akan melakukan
Company.send(:joins, :categories)
yang setara dengan `Company.categories - pada gabungan gabungan, ia mengeksekusi kondisi where (dibangun seperti dijelaskan di atas)
Penafian Sintaks persis yang Anda butuhkan mungkin berbeda berdasarkan implementasi SQL yang Anda gunakan.