通过过滤然后排序定义一个 QueryBuilder
Define a QueryBuilder by filtering then sorting
过滤
控制器动作中的以下代码:
students <- case searchString' of
Nothing -> query @Student |> fetch
(Just str) -> query @Student
|> queryOr
(filterWhereILike (#lastName, "%" <> str <> "%"))
(filterWhereILike (#firstMidName, "%" <> str <> "%"))
|> fetch
会:
- 如果
searchString'
可用,return 学生的 lastName
或 firstMidName
匹配 searchString'
- 否则,return所有学生
效果很好!
正在排序
过滤后,我想按照另一个Maybe Text
排序。我想做这样的事情:
设置 queryBuilder
并完成过滤步骤:
let queryBuilder = case searchString' of
Nothing -> query @Student
(Just str) -> query @Student
|> queryOr
(filterWhereILike (#lastName, "%" <> str <> "%"))
(filterWhereILike (#firstMidName, "%" <> str <> "%"))
然后进行排序:
students <- case sortOrder of
(Just "NameAsc") -> queryBuilder |> orderByAsc #lastName |> fetch
(Just "NameDsc") -> queryBuilder |> orderByDesc #lastName |> fetch
(Just "DateAsc") -> queryBuilder |> orderByAsc #enrollmentDate |> fetch
(Just "DateDsc") -> queryBuilder |> orderByDesc #enrollmentDate |> fetch
Nothing -> queryBuilder |> orderByAsc #lastName |> fetch
_ -> queryBuilder |> orderByAsc #lastName |> fetch
然而,这(可以理解)导致以下结果:
• Couldn't match expected type ‘QueryBuilder "students"’
with actual type ‘NoJoinQueryBuilderWrapper "students"’
• In the expression:
query @Student
|>
queryOr
(filterWhereILike (#lastName, "%" <> str <> "%"))
(filterWhereILike (#firstMidName, "%" <> str <> "%"))
In a case alternative:
(Just str)
-> query @Student
|>
queryOr
(filterWhereILike (#lastName, "%" <> str <> "%"))
(filterWhereILike (#firstMidName, "%" <> str <> "%"))
In the expression:
case searchString' of
Nothing -> query @Student
(Just str)
-> query @Student
|>
queryOr
(filterWhereILike (#lastName, "%" <> str <> "%"))
(filterWhereILike (#firstMidName, "%" <> str <> "%"))typecheck
问题
有什么关于如何设置的建议吗?
原代码
如果有任何帮助,这或多或少是对以下 C#
的转换
var students = _context.Students.Select(student => student);
if (!String.IsNullOrEmpty(searchString))
students = students.Where(student =>
student.LastName.Contains(searchString) ||
student.FirstMidName.Contains(searchString));
if (sortOrder == SortOrder.NameAsc) students = students.OrderBy( student => student.LastName);
else if (sortOrder == SortOrder.NameDsc) students = students.OrderByDescending(student => student.LastName);
else if (sortOrder == SortOrder.DateAsc) students = students.OrderBy( student => student.EnrollmentDate);
else if (sortOrder == SortOrder.DateDsc) students = students.OrderByDescending(student => student.EnrollmentDate);
else students = students.OrderBy( student => student.LastName);
参考资料
IHP 手册的 QueryBuilder 部分:
https://ihp.digitallyinduced.com/Guide/querybuilder.html
除非我遗漏了什么,否则似乎没有与上述类似的示例。
Raw SQL Queries 还有一个部分。
更新 1
这是一种有效的方法:
students <- case searchString' of
Nothing -> query @Student
|> (case sortOrder of
(Just "NameAsc") -> orderByAsc #lastName
(Just "NameDsc") -> orderByDesc #lastName
(Just "DateAsc") -> orderByAsc #enrollmentDate
(Just "DateDsc") -> orderByDesc #enrollmentDate
Nothing -> orderByAsc #lastName
_ -> orderByAsc #lastName)
|> fetch
(Just str) -> query @Student
|> queryOr
(filterWhereILike (#lastName, "%" <> str <> "%"))
(filterWhereILike (#firstMidName, "%" <> str <> "%"))
|> (case sortOrder of
(Just "NameAsc") -> orderByAsc #lastName
(Just "NameDsc") -> orderByDesc #lastName
(Just "DateAsc") -> orderByAsc #enrollmentDate
(Just "DateDsc") -> orderByDesc #enrollmentDate
Nothing -> orderByAsc #lastName
_ -> orderByAsc #lastName)
|> fetch
但是,如您所见,排序子句是重复的。
如果我尝试按如下方式分解排序子句:
let sortClause = (case sortOrder of
(Just "NameAsc") -> orderByAsc #lastName
(Just "NameDsc") -> orderByDesc #lastName
(Just "DateAsc") -> orderByAsc #enrollmentDate
(Just "DateDsc") -> orderByDesc #enrollmentDate
Nothing -> orderByAsc #lastName
_ -> orderByAsc #lastName)
我(可以理解地)得到以下信息:
因为我们不在查询上下文中。
更新 2
好的,我能够通过为未引用的查询提供参数来分解排序子句:
let sortClause q = (case sortOrder of
(Just "NameAsc") -> orderByAsc #lastName
(Just "NameDsc") -> orderByDesc #lastName
(Just "DateAsc") -> orderByAsc #enrollmentDate
(Just "DateDsc") -> orderByDesc #enrollmentDate
Nothing -> orderByAsc #lastName
_ -> orderByAsc #lastName)
我可以使用 sortClause
,但是,我必须添加对 queryOr
的“无操作”调用,以便使类型对齐:
students <- case searchString' of
Nothing -> query @Student
|> queryOr
(filterWhereILike (#lastName, "%"))
(filterWhereILike (#firstMidName, "%"))
|> sortClause (query @Student)
|> fetch
(Just str) -> query @Student
|> queryOr
(filterWhereILike (#lastName, "%" <> str <> "%"))
(filterWhereILike (#firstMidName, "%" <> str <> "%"))
|> sortClause (query @Student)
|> fetch
所以,我想对于这种方法的问题是,有没有办法避免在第一个分支中使用“no-op”queryOr
?
我可以重现这个问题。这是 IHP 中的一个错误,其中 queryOr
的类型过于具体。通过 https://github.com/digitallyinduced/ihp/pull/1081
修复
你能试试看吗?请参阅 https://ihp.digitallyinduced.com/Guide/updating.html#updating-to-a-specific-git-commit 以更新到特定提交。
与错误无关,这是该操作的另一个版本:
action StudentsAction = do
let searchString' = paramOrNothing @Text "query"
let sortOrder = paramOrNothing @Text "sort"
let filterWhereName = case searchString' of
(Just searchQuery) -> filterWhere (#lastName, "%" <> searchQuery <> "%")
Nothing -> \query -> query
let orderBySortParam = case sortOrder of
(Just "NameAsc") -> orderByAsc #lastName
(Just "NameDsc") -> orderByDesc #lastName
(Just "DateAsc") -> orderByAsc #enrollmentDate
(Just "DateDsc") -> orderByDesc #enrollmentDate
_ -> orderByAsc #lastName
students <- query @Student
|> filterWhereName
|> orderBySortParam
|> fetch
render IndexView { .. }
过滤
控制器动作中的以下代码:
students <- case searchString' of
Nothing -> query @Student |> fetch
(Just str) -> query @Student
|> queryOr
(filterWhereILike (#lastName, "%" <> str <> "%"))
(filterWhereILike (#firstMidName, "%" <> str <> "%"))
|> fetch
会:
- 如果
searchString'
可用,return 学生的lastName
或firstMidName
匹配searchString'
- 否则,return所有学生
效果很好!
正在排序
过滤后,我想按照另一个Maybe Text
排序。我想做这样的事情:
设置 queryBuilder
并完成过滤步骤:
let queryBuilder = case searchString' of
Nothing -> query @Student
(Just str) -> query @Student
|> queryOr
(filterWhereILike (#lastName, "%" <> str <> "%"))
(filterWhereILike (#firstMidName, "%" <> str <> "%"))
然后进行排序:
students <- case sortOrder of
(Just "NameAsc") -> queryBuilder |> orderByAsc #lastName |> fetch
(Just "NameDsc") -> queryBuilder |> orderByDesc #lastName |> fetch
(Just "DateAsc") -> queryBuilder |> orderByAsc #enrollmentDate |> fetch
(Just "DateDsc") -> queryBuilder |> orderByDesc #enrollmentDate |> fetch
Nothing -> queryBuilder |> orderByAsc #lastName |> fetch
_ -> queryBuilder |> orderByAsc #lastName |> fetch
然而,这(可以理解)导致以下结果:
• Couldn't match expected type ‘QueryBuilder "students"’
with actual type ‘NoJoinQueryBuilderWrapper "students"’
• In the expression:
query @Student
|>
queryOr
(filterWhereILike (#lastName, "%" <> str <> "%"))
(filterWhereILike (#firstMidName, "%" <> str <> "%"))
In a case alternative:
(Just str)
-> query @Student
|>
queryOr
(filterWhereILike (#lastName, "%" <> str <> "%"))
(filterWhereILike (#firstMidName, "%" <> str <> "%"))
In the expression:
case searchString' of
Nothing -> query @Student
(Just str)
-> query @Student
|>
queryOr
(filterWhereILike (#lastName, "%" <> str <> "%"))
(filterWhereILike (#firstMidName, "%" <> str <> "%"))typecheck
问题
有什么关于如何设置的建议吗?
原代码
如果有任何帮助,这或多或少是对以下 C#
的转换 var students = _context.Students.Select(student => student);
if (!String.IsNullOrEmpty(searchString))
students = students.Where(student =>
student.LastName.Contains(searchString) ||
student.FirstMidName.Contains(searchString));
if (sortOrder == SortOrder.NameAsc) students = students.OrderBy( student => student.LastName);
else if (sortOrder == SortOrder.NameDsc) students = students.OrderByDescending(student => student.LastName);
else if (sortOrder == SortOrder.DateAsc) students = students.OrderBy( student => student.EnrollmentDate);
else if (sortOrder == SortOrder.DateDsc) students = students.OrderByDescending(student => student.EnrollmentDate);
else students = students.OrderBy( student => student.LastName);
参考资料
IHP 手册的 QueryBuilder 部分:
https://ihp.digitallyinduced.com/Guide/querybuilder.html
除非我遗漏了什么,否则似乎没有与上述类似的示例。
Raw SQL Queries 还有一个部分。
更新 1
这是一种有效的方法:
students <- case searchString' of
Nothing -> query @Student
|> (case sortOrder of
(Just "NameAsc") -> orderByAsc #lastName
(Just "NameDsc") -> orderByDesc #lastName
(Just "DateAsc") -> orderByAsc #enrollmentDate
(Just "DateDsc") -> orderByDesc #enrollmentDate
Nothing -> orderByAsc #lastName
_ -> orderByAsc #lastName)
|> fetch
(Just str) -> query @Student
|> queryOr
(filterWhereILike (#lastName, "%" <> str <> "%"))
(filterWhereILike (#firstMidName, "%" <> str <> "%"))
|> (case sortOrder of
(Just "NameAsc") -> orderByAsc #lastName
(Just "NameDsc") -> orderByDesc #lastName
(Just "DateAsc") -> orderByAsc #enrollmentDate
(Just "DateDsc") -> orderByDesc #enrollmentDate
Nothing -> orderByAsc #lastName
_ -> orderByAsc #lastName)
|> fetch
但是,如您所见,排序子句是重复的。
如果我尝试按如下方式分解排序子句:
let sortClause = (case sortOrder of
(Just "NameAsc") -> orderByAsc #lastName
(Just "NameDsc") -> orderByDesc #lastName
(Just "DateAsc") -> orderByAsc #enrollmentDate
(Just "DateDsc") -> orderByDesc #enrollmentDate
Nothing -> orderByAsc #lastName
_ -> orderByAsc #lastName)
我(可以理解地)得到以下信息:
因为我们不在查询上下文中。
更新 2
好的,我能够通过为未引用的查询提供参数来分解排序子句:
let sortClause q = (case sortOrder of
(Just "NameAsc") -> orderByAsc #lastName
(Just "NameDsc") -> orderByDesc #lastName
(Just "DateAsc") -> orderByAsc #enrollmentDate
(Just "DateDsc") -> orderByDesc #enrollmentDate
Nothing -> orderByAsc #lastName
_ -> orderByAsc #lastName)
我可以使用 sortClause
,但是,我必须添加对 queryOr
的“无操作”调用,以便使类型对齐:
students <- case searchString' of
Nothing -> query @Student
|> queryOr
(filterWhereILike (#lastName, "%"))
(filterWhereILike (#firstMidName, "%"))
|> sortClause (query @Student)
|> fetch
(Just str) -> query @Student
|> queryOr
(filterWhereILike (#lastName, "%" <> str <> "%"))
(filterWhereILike (#firstMidName, "%" <> str <> "%"))
|> sortClause (query @Student)
|> fetch
所以,我想对于这种方法的问题是,有没有办法避免在第一个分支中使用“no-op”queryOr
?
我可以重现这个问题。这是 IHP 中的一个错误,其中 queryOr
的类型过于具体。通过 https://github.com/digitallyinduced/ihp/pull/1081
你能试试看吗?请参阅 https://ihp.digitallyinduced.com/Guide/updating.html#updating-to-a-specific-git-commit 以更新到特定提交。
与错误无关,这是该操作的另一个版本:
action StudentsAction = do
let searchString' = paramOrNothing @Text "query"
let sortOrder = paramOrNothing @Text "sort"
let filterWhereName = case searchString' of
(Just searchQuery) -> filterWhere (#lastName, "%" <> searchQuery <> "%")
Nothing -> \query -> query
let orderBySortParam = case sortOrder of
(Just "NameAsc") -> orderByAsc #lastName
(Just "NameDsc") -> orderByDesc #lastName
(Just "DateAsc") -> orderByAsc #enrollmentDate
(Just "DateDsc") -> orderByDesc #enrollmentDate
_ -> orderByAsc #lastName
students <- query @Student
|> filterWhereName
|> orderBySortParam
|> fetch
render IndexView { .. }