我正在尝试构建一个在查询中给定表的字段中搜索词条的函数。
对于类似
的查询initial_query =
Answer
|> join(:left, [a], q in assoc(a, :question), as: :question)
|> join(:left, [a, q], s in assoc(a, :survey), as: :survey)
我希望能够在:question
和:survey
所引用的表中进行搜索。
现在,此代码有效:
initial_query
|> or_where(
[question: t], #:question hard coded
fragment(
"CAST(? AS varchar) ILIKE ?",
field(t, ^field),
^"%#{search_term}%"
)
)
但是,我想拥有一个将命名绑定作为参数的函数,但是我找不到解决方法。
我的尝试
defp search_field(initial_query, table, field, search_term) do
initial_query
|> or_where(
[{table, t}],
fragment(
"CAST(? AS varchar) ILIKE ?",
field(t, ^field),
^"%#{search_term}%"
)
)
end
给出错误
**(Ecto.Query.CompileError)查询中的未绑定变量
t
。如果您要插值,请使用^ var 扩展宏:Ecto.Query.or_where / 3
当这样调用时:
search_field(initial_query, :question, :text, search_text)
和
defp search_field(initial_query, table, field, search_term) do
initial_query
|> or_where(
[{^table, t}],
fragment(
"CAST(? AS varchar) ILIKE ?",
field(t, ^field),
^"%#{search_term}%"
)
)
end
给予
**(Ecto.Query.CompileError)绑定列表应仅包含变量或
{as, var}
元组,得到:{^ table,t} 扩展宏:Ecto.Query.or_where / 3
有没有一种方法可以使用变量来引用Ecto查询中的命名绑定?
答案 0 :(得分:2)
因此,此问题的答案似乎是Ecto没有支持的方法来执行此操作。 @maartenvanvliet解决方案效果很好,但缺点是依赖于内部实现。
我对这个问题的解决方案是使用here描述的search_field
语法,使函数...
始终在最后一个联接表中进行搜索:
# Searches for the `search_term` in the `field` in the last joined table in `initial_query`.
defp search_field(initial_query, field, search_term) do
initial_query
|> or_where(
[..., t],
fragment(
"CAST(? AS varchar) ILIKE ?",
field(t, ^field),
^"%#{search_term}%"
)
)
end
所以该函数将像这样使用:
Answer
|> join(:left, [a], q in assoc(a, :question), as: :question)
|> search_field(:text, search_text)
|> join(:left, [a, q], s in assoc(a, :survey), as: :survey)
|> search_field(:title, search_text)
在我看来,这仍然读起来不错,其缺点是要求我们能够更改initial_query
。
答案 1 :(得分:1)
诀窍是检索命名绑定在绑定中的位置。命名的绑定存储在 from tkinter import *
from tkinter import messagebox
import time
#pop up
def spam():
global spamreturn
spamreturn = False
def closed():
if messagebox.askokcancel("Quit", "Do you really wish to quit?"):
mibox.destroy()
return True
mibox = Tk()
topframe = Frame(mibox)
miLabel = Label(mibox, text="Call 1-800-273-8255")
mibutton = Button(topframe, text="Your Computer has been infected")
mibutton2 = Button(topframe, text="Please call 1-800-273-8255 for Assistance")
miLabel.pack()
mibutton.pack()
mibutton2.pack()
topframe.pack()
mibox.geometry("300x100+500+250")
mibox.protocol("WM_DELETE_WINDOW", closed)
mibox.mainloop()
if closed():
spamreturn = True
spam()
if spamreturn == True:
print("worked")
time.sleep(3)
字段中。
%Ecto.Query{aliases: aliases}
我们首先在query.aliases中查找命名绑定的位置。然后使用此位置构建查询。
现在,当我们打电话
def named_binding_position(query, binding) do
Map.get(query.aliases, binding)
end
def search_field(query, table, field, search_term) do
position = named_binding_position(query, table)
query
|> or_where(
[{t, position}],
fragment(
"CAST(? AS varchar) ILIKE ?",
field(t, ^field),
^"%#{search_term}%"
)
)
end
它应该产生类似
Answer
|> join(:left, [a], q in assoc(a, :question), as: :question)
|> join(:left, [a, q], s in assoc(a, :survey), as: :survey)
|> search_field(:question, :text, "bogus")
值得注意的是,#Ecto.Query<from a in Answer,
left_join: q in assoc(a, :question), as: :question,
or_where: fragment("CAST(? AS varchar) ILIKE ?", q.text, ^"%bogus%")>
元组以%Query.aliases来指代命名结合的位置是一个内部实现的,不能记录。因此,可能会有所变化。有关更多信息,请参见https://github.com/elixir-ecto/ecto/issues/2832