Skip to content

Commit 4a1fe94

Browse files
authored
Merge pull request #1263 from Permify/query-optimization
refactor(query-optimization): optimize entity_id condition for single…
2 parents c7992f5 + 95c467e commit 4a1fe94

File tree

6 files changed

+84
-28
lines changed

6 files changed

+84
-28
lines changed

docs/api-reference/apidocs.swagger.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"info": {
44
"title": "Permify API",
55
"description": "Permify is an open source authorization service for creating fine-grained and scalable authorization systems.",
6-
"version": "v0.8.6",
6+
"version": "v0.8.7",
77
"contact": {
88
"name": "API Support",
99
"url": "https://github.com/Permify/permify/issues",

internal/info.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ var Identifier = ""
2323
*/
2424
const (
2525
// Version is the last release of the Permify (e.g. v0.1.0)
26-
Version = "v0.8.6"
26+
Version = "v0.8.7"
2727
)
2828

2929
// Function to create a single line of the ASCII art with centered content and color

internal/storage/postgres/utils/filter.go

Lines changed: 78 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,15 @@ func TuplesFilterQueryForSelectBuilder(sl squirrel.SelectBuilder, filter *base.T
1414
eq["entity_type"] = filter.GetEntity().GetType()
1515
}
1616

17-
if len(filter.GetEntity().GetIds()) > 0 {
18-
eq["entity_id"] = filter.GetEntity().GetIds()
17+
entityIds := filter.GetEntity().GetIds()
18+
if len(entityIds) > 0 {
19+
if len(entityIds) == 1 {
20+
// If there is only one ID, use the = operator
21+
eq["entity_id"] = entityIds[0]
22+
} else {
23+
// If there are multiple IDs, use the IN operator
24+
eq["entity_id"] = entityIds
25+
}
1926
}
2027

2128
if filter.GetRelation() != "" {
@@ -26,16 +33,23 @@ func TuplesFilterQueryForSelectBuilder(sl squirrel.SelectBuilder, filter *base.T
2633
eq["subject_type"] = filter.GetSubject().GetType()
2734
}
2835

29-
if len(filter.GetSubject().GetIds()) > 0 {
30-
eq["subject_id"] = filter.GetSubject().GetIds()
36+
subjectIds := filter.GetSubject().GetIds()
37+
if len(subjectIds) > 0 {
38+
if len(subjectIds) == 1 {
39+
// If there is only one ID, use the = operator
40+
eq["subject_id"] = subjectIds[0]
41+
} else {
42+
// If there are multiple IDs, use the IN operator
43+
eq["subject_id"] = subjectIds
44+
}
3145
}
3246

3347
if filter.GetSubject().GetRelation() != "" {
3448
eq["subject_relation"] = filter.GetSubject().GetRelation()
3549
}
3650

37-
// If eq is empty, return the original squirrel.UpdateBuilder without attaching a WHERE clause.
38-
// This ensures we don't accidentally update every row in the table.
51+
// If eq is empty, return the original squirrel.SelectBuilder without attaching a WHERE clause.
52+
// This ensures we don't accidentally select every row in the table.
3953
if len(eq) == 0 {
4054
return sl
4155
}
@@ -51,16 +65,30 @@ func AttributesFilterQueryForSelectBuilder(sl squirrel.SelectBuilder, filter *ba
5165
eq["entity_type"] = filter.GetEntity().GetType()
5266
}
5367

54-
if len(filter.GetEntity().GetIds()) > 0 {
55-
eq["entity_id"] = filter.GetEntity().GetIds()
68+
entityIds := filter.GetEntity().GetIds()
69+
if len(entityIds) > 0 {
70+
if len(entityIds) == 1 {
71+
// If there is only one ID, use the = operator
72+
eq["entity_id"] = entityIds[0]
73+
} else {
74+
// If there are multiple IDs, use the IN operator
75+
eq["entity_id"] = entityIds
76+
}
5677
}
5778

58-
if len(filter.GetAttributes()) > 0 {
59-
eq["attribute"] = filter.GetAttributes()
79+
attributes := filter.GetAttributes()
80+
if len(attributes) > 0 {
81+
if len(attributes) == 1 {
82+
// If there is only one attribute, use the = operator
83+
eq["attribute"] = attributes[0]
84+
} else {
85+
// If there are multiple attributes, use the IN operator
86+
eq["attribute"] = attributes
87+
}
6088
}
6189

62-
// If eq is empty, return the original squirrel.UpdateBuilder without attaching a WHERE clause.
63-
// This ensures we don't accidentally update every row in the table.
90+
// If eq is empty, return the original squirrel.SelectBuilder without attaching a WHERE clause.
91+
// This ensures we don't accidentally select every row in the table.
6492
if len(eq) == 0 {
6593
return sl
6694
}
@@ -76,8 +104,15 @@ func TuplesFilterQueryForUpdateBuilder(sl squirrel.UpdateBuilder, filter *base.T
76104
eq["entity_type"] = filter.GetEntity().GetType()
77105
}
78106

79-
if len(filter.GetEntity().GetIds()) > 0 {
80-
eq["entity_id"] = filter.GetEntity().GetIds()
107+
entityIds := filter.GetEntity().GetIds()
108+
if len(entityIds) > 0 {
109+
if len(entityIds) == 1 {
110+
// If there is only one ID, use the = operator
111+
eq["entity_id"] = entityIds[0]
112+
} else {
113+
// If there are multiple IDs, use the IN operator
114+
eq["entity_id"] = entityIds
115+
}
81116
}
82117

83118
if filter.GetRelation() != "" {
@@ -88,8 +123,15 @@ func TuplesFilterQueryForUpdateBuilder(sl squirrel.UpdateBuilder, filter *base.T
88123
eq["subject_type"] = filter.GetSubject().GetType()
89124
}
90125

91-
if len(filter.GetSubject().GetIds()) > 0 {
92-
eq["subject_id"] = filter.GetSubject().GetIds()
126+
subjectIds := filter.GetSubject().GetIds()
127+
if len(subjectIds) > 0 {
128+
if len(subjectIds) == 1 {
129+
// If there is only one ID, use the = operator
130+
eq["subject_id"] = subjectIds[0]
131+
} else {
132+
// If there are multiple IDs, use the IN operator
133+
eq["subject_id"] = subjectIds
134+
}
93135
}
94136

95137
if filter.GetSubject().GetRelation() != "" {
@@ -113,12 +155,26 @@ func AttributesFilterQueryForUpdateBuilder(sl squirrel.UpdateBuilder, filter *ba
113155
eq["entity_type"] = filter.GetEntity().GetType()
114156
}
115157

116-
if len(filter.GetEntity().GetIds()) > 0 {
117-
eq["entity_id"] = filter.GetEntity().GetIds()
118-
}
119-
120-
if len(filter.GetAttributes()) > 0 {
121-
eq["attribute"] = filter.GetAttributes()
158+
entityIds := filter.GetEntity().GetIds()
159+
if len(entityIds) > 0 {
160+
if len(entityIds) == 1 {
161+
// If there is only one ID, use the = operator
162+
eq["entity_id"] = entityIds[0]
163+
} else {
164+
// If there are multiple IDs, use the IN operator
165+
eq["entity_id"] = entityIds
166+
}
167+
}
168+
169+
attributes := filter.GetAttributes()
170+
if len(attributes) > 0 {
171+
if len(attributes) == 1 {
172+
// If there is only one attribute, use the = operator
173+
eq["attribute"] = attributes[0]
174+
} else {
175+
// If there are multiple attributes, use the IN operator
176+
eq["attribute"] = attributes
177+
}
122178
}
123179

124180
// If eq is empty, return the original squirrel.UpdateBuilder without attaching a WHERE clause.

pkg/database/postgres/postgres.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ import (
66
"strings"
77
"time"
88

9-
"github.com/exaring/otelpgx"
10-
119
"github.com/cenkalti/backoff/v4"
1210

11+
"github.com/exaring/otelpgx"
12+
1313
"golang.org/x/exp/slog"
1414

1515
"github.com/jackc/pgx/v5"

pkg/pb/base/v1/openapi.pb.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

proto/base/v1/openapi.proto

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
99
info: {
1010
title: "Permify API";
1111
description: "Permify is an open source authorization service for creating fine-grained and scalable authorization systems.";
12-
version: "v0.8.6";
12+
version: "v0.8.7";
1313
contact: {
1414
name: "API Support";
1515
url: "https://github.com/Permify/permify/issues";

0 commit comments

Comments
 (0)