Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
C
canifa_note
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Vũ Hoàng Anh
canifa_note
Commits
c3d4f8e9
Commit
c3d4f8e9
authored
Sep 10, 2025
by
Steven
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: implement user-specific SQL converter for filtering in user service
parent
383553d3
Changes
5
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
92 additions
and
26 deletions
+92
-26
common_converter.go
plugin/filter/common_converter.go
+88
-22
user_service.go
server/router/api/v1/user_service.go
+1
-1
user.go
store/db/mysql/user.go
+1
-1
user.go
store/db/postgres/user.go
+1
-1
user.go
store/db/sqlite/user.go
+1
-1
No files found.
plugin/filter/common_converter.go
View file @
c3d4f8e9
...
...
@@ -13,21 +13,37 @@ import (
type
CommonSQLConverter
struct
{
dialect
SQLDialect
paramIndex
int
allowedFields
[]
string
entityType
string
}
// NewCommonSQLConverter creates a new converter with the specified dialect.
// NewCommonSQLConverter creates a new converter with the specified dialect
for memo filters
.
func
NewCommonSQLConverter
(
dialect
SQLDialect
)
*
CommonSQLConverter
{
return
&
CommonSQLConverter
{
dialect
:
dialect
,
paramIndex
:
1
,
allowedFields
:
[]
string
{
"creator_id"
,
"created_ts"
,
"updated_ts"
,
"visibility"
,
"content"
,
"pinned"
,
"has_task_list"
,
"has_link"
,
"has_code"
,
"has_incomplete_tasks"
},
entityType
:
"memo"
,
}
}
// NewCommonSQLConverterWithOffset creates a new converter with the specified dialect and parameter offset.
// NewCommonSQLConverterWithOffset creates a new converter with the specified dialect and parameter offset
for memo filters
.
func
NewCommonSQLConverterWithOffset
(
dialect
SQLDialect
,
offset
int
)
*
CommonSQLConverter
{
return
&
CommonSQLConverter
{
dialect
:
dialect
,
paramIndex
:
offset
+
1
,
allowedFields
:
[]
string
{
"creator_id"
,
"created_ts"
,
"updated_ts"
,
"visibility"
,
"content"
,
"pinned"
,
"has_task_list"
,
"has_link"
,
"has_code"
,
"has_incomplete_tasks"
},
entityType
:
"memo"
,
}
}
// NewUserSQLConverter creates a new converter for user filters.
func
NewUserSQLConverter
(
dialect
SQLDialect
)
*
CommonSQLConverter
{
return
&
CommonSQLConverter
{
dialect
:
dialect
,
paramIndex
:
1
,
allowedFields
:
[]
string
{
"username"
},
entityType
:
"user"
,
}
}
...
...
@@ -124,7 +140,7 @@ func (c *CommonSQLConverter) handleComparisonOperator(ctx *ConvertContext, callE
return
err
}
if
!
slices
.
Contains
(
[]
string
{
"creator_id"
,
"created_ts"
,
"updated_ts"
,
"visibility"
,
"content"
,
"pinned"
,
"has_task_list"
,
"has_link"
,
"has_code"
,
"has_incomplete_tasks"
}
,
identifier
)
{
if
!
slices
.
Contains
(
c
.
allowedFields
,
identifier
)
{
return
errors
.
Errorf
(
"invalid identifier for %s"
,
callExpr
.
Function
)
}
...
...
@@ -135,6 +151,8 @@ func (c *CommonSQLConverter) handleComparisonOperator(ctx *ConvertContext, callE
operator
:=
c
.
getComparisonOperator
(
callExpr
.
Function
)
// Handle memo fields
if
c
.
entityType
==
"memo"
{
switch
identifier
{
case
"created_ts"
,
"updated_ts"
:
return
c
.
handleTimestampComparison
(
ctx
,
identifier
,
operator
,
value
)
...
...
@@ -149,6 +167,19 @@ func (c *CommonSQLConverter) handleComparisonOperator(ctx *ConvertContext, callE
default
:
return
errors
.
Errorf
(
"unsupported identifier in comparison: %s"
,
identifier
)
}
}
// Handle user fields
if
c
.
entityType
==
"user"
{
switch
identifier
{
case
"username"
:
return
c
.
handleUserStringComparison
(
ctx
,
identifier
,
operator
,
value
)
default
:
return
errors
.
Errorf
(
"unsupported user identifier in comparison: %s"
,
identifier
)
}
}
return
errors
.
Errorf
(
"unsupported entity type: %s"
,
c
.
entityType
)
}
func
(
c
*
CommonSQLConverter
)
handleSizeComparison
(
ctx
*
ConvertContext
,
callExpr
*
exprv1
.
Expr_Call
,
sizeCall
*
exprv1
.
Expr_Call
)
error
{
...
...
@@ -400,6 +431,11 @@ func (c *CommonSQLConverter) handleContainsOperator(ctx *ConvertContext, callExp
func
(
c
*
CommonSQLConverter
)
handleIdentifier
(
ctx
*
ConvertContext
,
identExpr
*
exprv1
.
Expr_Ident
)
error
{
identifier
:=
identExpr
.
GetName
()
// Only memo entity has boolean identifiers that can be used standalone
if
c
.
entityType
!=
"memo"
{
return
errors
.
Errorf
(
"invalid identifier %s for entity type %s"
,
identifier
,
c
.
entityType
)
}
if
!
slices
.
Contains
([]
string
{
"pinned"
,
"has_task_list"
,
"has_link"
,
"has_code"
,
"has_incomplete_tasks"
},
identifier
)
{
return
errors
.
Errorf
(
"invalid identifier %s"
,
identifier
)
}
...
...
@@ -489,6 +525,36 @@ func (c *CommonSQLConverter) handleStringComparison(ctx *ConvertContext, field,
return
nil
}
func
(
c
*
CommonSQLConverter
)
handleUserStringComparison
(
ctx
*
ConvertContext
,
field
,
operator
string
,
value
interface
{})
error
{
if
operator
!=
"="
&&
operator
!=
"!="
{
return
errors
.
Errorf
(
"invalid operator for %s"
,
field
)
}
valueStr
,
ok
:=
value
.
(
string
)
if
!
ok
{
return
errors
.
New
(
"invalid string value"
)
}
tablePrefix
:=
c
.
dialect
.
GetTablePrefix
(
"user"
)
if
_
,
ok
:=
c
.
dialect
.
(
*
PostgreSQLDialect
);
ok
{
// PostgreSQL doesn't use backticks
if
_
,
err
:=
ctx
.
Buffer
.
WriteString
(
fmt
.
Sprintf
(
"%s.%s %s %s"
,
tablePrefix
,
field
,
operator
,
c
.
dialect
.
GetParameterPlaceholder
(
c
.
paramIndex
)));
err
!=
nil
{
return
err
}
}
else
{
// MySQL and SQLite use backticks
if
_
,
err
:=
ctx
.
Buffer
.
WriteString
(
fmt
.
Sprintf
(
"%s.`%s` %s %s"
,
tablePrefix
,
field
,
operator
,
c
.
dialect
.
GetParameterPlaceholder
(
c
.
paramIndex
)));
err
!=
nil
{
return
err
}
}
ctx
.
Args
=
append
(
ctx
.
Args
,
valueStr
)
c
.
paramIndex
++
return
nil
}
func
(
c
*
CommonSQLConverter
)
handleIntComparison
(
ctx
*
ConvertContext
,
field
,
operator
string
,
value
interface
{})
error
{
if
operator
!=
"="
&&
operator
!=
"!="
{
return
errors
.
Errorf
(
"invalid operator for %s"
,
field
)
...
...
server/router/api/v1/user_service.go
View file @
c3d4f8e9
...
...
@@ -1368,7 +1368,7 @@ func (s *APIV1Service) validateUserFilter(_ context.Context, filterStr string) e
dialect
=
&
filter
.
SQLiteDialect
{}
}
converter
:=
filter
.
New
Common
SQLConverter
(
dialect
)
converter
:=
filter
.
New
User
SQLConverter
(
dialect
)
err
=
converter
.
ConvertExprToSQL
(
convertCtx
,
parsedExpr
.
GetExpr
())
if
err
!=
nil
{
return
errors
.
Wrap
(
err
,
"failed to convert filter to SQL"
)
...
...
store/db/mysql/user.go
View file @
c3d4f8e9
...
...
@@ -94,7 +94,7 @@ func (d *DB) ListUsers(ctx context.Context, find *store.FindUser) ([]*store.User
}
convertCtx
:=
filter
.
NewConvertContext
()
// ConvertExprToSQL converts the parsed expression to a SQL condition string.
converter
:=
filter
.
New
Common
SQLConverter
(
&
filter
.
MySQLDialect
{})
converter
:=
filter
.
New
User
SQLConverter
(
&
filter
.
MySQLDialect
{})
if
err
:=
converter
.
ConvertExprToSQL
(
convertCtx
,
parsedExpr
.
GetExpr
());
err
!=
nil
{
return
nil
,
err
}
...
...
store/db/postgres/user.go
View file @
c3d4f8e9
...
...
@@ -95,7 +95,7 @@ func (d *DB) ListUsers(ctx context.Context, find *store.FindUser) ([]*store.User
}
convertCtx
:=
filter
.
NewConvertContext
()
// ConvertExprToSQL converts the parsed expression to a SQL condition string.
converter
:=
filter
.
New
Common
SQLConverter
(
&
filter
.
PostgreSQLDialect
{})
converter
:=
filter
.
New
User
SQLConverter
(
&
filter
.
PostgreSQLDialect
{})
if
err
:=
converter
.
ConvertExprToSQL
(
convertCtx
,
parsedExpr
.
GetExpr
());
err
!=
nil
{
return
nil
,
err
}
...
...
store/db/sqlite/user.go
View file @
c3d4f8e9
...
...
@@ -96,7 +96,7 @@ func (d *DB) ListUsers(ctx context.Context, find *store.FindUser) ([]*store.User
}
convertCtx
:=
filter
.
NewConvertContext
()
// ConvertExprToSQL converts the parsed expression to a SQL condition string.
converter
:=
filter
.
New
Common
SQLConverter
(
&
filter
.
SQLiteDialect
{})
converter
:=
filter
.
New
User
SQLConverter
(
&
filter
.
SQLiteDialect
{})
if
err
:=
converter
.
ConvertExprToSQL
(
convertCtx
,
parsedExpr
.
GetExpr
());
err
!=
nil
{
return
nil
,
err
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment