diff --git a/docs/api-reference/apidocs.swagger.json b/docs/api-reference/apidocs.swagger.json index a16540edd..bef0dddd2 100644 --- a/docs/api-reference/apidocs.swagger.json +++ b/docs/api-reference/apidocs.swagger.json @@ -3,7 +3,7 @@ "info": { "title": "Permify API", "description": "Permify is an open source authorization service for creating fine-grained and scalable authorization systems.", - "version": "v0.8.6", + "version": "v0.8.7", "contact": { "name": "API Support", "url": "https://github.com/Permify/permify/issues", diff --git a/internal/info.go b/internal/info.go index d554a557d..679701552 100644 --- a/internal/info.go +++ b/internal/info.go @@ -23,7 +23,7 @@ var Identifier = "" */ const ( // Version is the last release of the Permify (e.g. v0.1.0) - Version = "v0.8.6" + Version = "v0.8.7" ) // Function to create a single line of the ASCII art with centered content and color diff --git a/internal/storage/postgres/utils/filter.go b/internal/storage/postgres/utils/filter.go index b71d046b3..86442b412 100644 --- a/internal/storage/postgres/utils/filter.go +++ b/internal/storage/postgres/utils/filter.go @@ -14,8 +14,15 @@ func TuplesFilterQueryForSelectBuilder(sl squirrel.SelectBuilder, filter *base.T eq["entity_type"] = filter.GetEntity().GetType() } - if len(filter.GetEntity().GetIds()) > 0 { - eq["entity_id"] = filter.GetEntity().GetIds() + entityIds := filter.GetEntity().GetIds() + if len(entityIds) > 0 { + if len(entityIds) == 1 { + // If there is only one ID, use the = operator + eq["entity_id"] = entityIds[0] + } else { + // If there are multiple IDs, use the IN operator + eq["entity_id"] = entityIds + } } if filter.GetRelation() != "" { @@ -26,16 +33,23 @@ func TuplesFilterQueryForSelectBuilder(sl squirrel.SelectBuilder, filter *base.T eq["subject_type"] = filter.GetSubject().GetType() } - if len(filter.GetSubject().GetIds()) > 0 { - eq["subject_id"] = filter.GetSubject().GetIds() + subjectIds := filter.GetSubject().GetIds() + if len(subjectIds) > 0 { + if len(subjectIds) == 1 { + // If there is only one ID, use the = operator + eq["subject_id"] = subjectIds[0] + } else { + // If there are multiple IDs, use the IN operator + eq["subject_id"] = subjectIds + } } if filter.GetSubject().GetRelation() != "" { eq["subject_relation"] = filter.GetSubject().GetRelation() } - // If eq is empty, return the original squirrel.UpdateBuilder without attaching a WHERE clause. - // This ensures we don't accidentally update every row in the table. + // If eq is empty, return the original squirrel.SelectBuilder without attaching a WHERE clause. + // This ensures we don't accidentally select every row in the table. if len(eq) == 0 { return sl } @@ -51,16 +65,30 @@ func AttributesFilterQueryForSelectBuilder(sl squirrel.SelectBuilder, filter *ba eq["entity_type"] = filter.GetEntity().GetType() } - if len(filter.GetEntity().GetIds()) > 0 { - eq["entity_id"] = filter.GetEntity().GetIds() + entityIds := filter.GetEntity().GetIds() + if len(entityIds) > 0 { + if len(entityIds) == 1 { + // If there is only one ID, use the = operator + eq["entity_id"] = entityIds[0] + } else { + // If there are multiple IDs, use the IN operator + eq["entity_id"] = entityIds + } } - if len(filter.GetAttributes()) > 0 { - eq["attribute"] = filter.GetAttributes() + attributes := filter.GetAttributes() + if len(attributes) > 0 { + if len(attributes) == 1 { + // If there is only one attribute, use the = operator + eq["attribute"] = attributes[0] + } else { + // If there are multiple attributes, use the IN operator + eq["attribute"] = attributes + } } - // If eq is empty, return the original squirrel.UpdateBuilder without attaching a WHERE clause. - // This ensures we don't accidentally update every row in the table. + // If eq is empty, return the original squirrel.SelectBuilder without attaching a WHERE clause. + // This ensures we don't accidentally select every row in the table. if len(eq) == 0 { return sl } @@ -76,8 +104,15 @@ func TuplesFilterQueryForUpdateBuilder(sl squirrel.UpdateBuilder, filter *base.T eq["entity_type"] = filter.GetEntity().GetType() } - if len(filter.GetEntity().GetIds()) > 0 { - eq["entity_id"] = filter.GetEntity().GetIds() + entityIds := filter.GetEntity().GetIds() + if len(entityIds) > 0 { + if len(entityIds) == 1 { + // If there is only one ID, use the = operator + eq["entity_id"] = entityIds[0] + } else { + // If there are multiple IDs, use the IN operator + eq["entity_id"] = entityIds + } } if filter.GetRelation() != "" { @@ -88,8 +123,15 @@ func TuplesFilterQueryForUpdateBuilder(sl squirrel.UpdateBuilder, filter *base.T eq["subject_type"] = filter.GetSubject().GetType() } - if len(filter.GetSubject().GetIds()) > 0 { - eq["subject_id"] = filter.GetSubject().GetIds() + subjectIds := filter.GetSubject().GetIds() + if len(subjectIds) > 0 { + if len(subjectIds) == 1 { + // If there is only one ID, use the = operator + eq["subject_id"] = subjectIds[0] + } else { + // If there are multiple IDs, use the IN operator + eq["subject_id"] = subjectIds + } } if filter.GetSubject().GetRelation() != "" { @@ -113,12 +155,26 @@ func AttributesFilterQueryForUpdateBuilder(sl squirrel.UpdateBuilder, filter *ba eq["entity_type"] = filter.GetEntity().GetType() } - if len(filter.GetEntity().GetIds()) > 0 { - eq["entity_id"] = filter.GetEntity().GetIds() - } - - if len(filter.GetAttributes()) > 0 { - eq["attribute"] = filter.GetAttributes() + entityIds := filter.GetEntity().GetIds() + if len(entityIds) > 0 { + if len(entityIds) == 1 { + // If there is only one ID, use the = operator + eq["entity_id"] = entityIds[0] + } else { + // If there are multiple IDs, use the IN operator + eq["entity_id"] = entityIds + } + } + + attributes := filter.GetAttributes() + if len(attributes) > 0 { + if len(attributes) == 1 { + // If there is only one attribute, use the = operator + eq["attribute"] = attributes[0] + } else { + // If there are multiple attributes, use the IN operator + eq["attribute"] = attributes + } } // If eq is empty, return the original squirrel.UpdateBuilder without attaching a WHERE clause. diff --git a/pkg/database/postgres/postgres.go b/pkg/database/postgres/postgres.go index 3ce490884..a128ee510 100644 --- a/pkg/database/postgres/postgres.go +++ b/pkg/database/postgres/postgres.go @@ -6,10 +6,10 @@ import ( "strings" "time" - "github.com/exaring/otelpgx" - "github.com/cenkalti/backoff/v4" + "github.com/exaring/otelpgx" + "golang.org/x/exp/slog" "github.com/jackc/pgx/v5" diff --git a/pkg/pb/base/v1/openapi.pb.go b/pkg/pb/base/v1/openapi.pb.go index 1fbd0ccc1..ae8fff7a0 100644 --- a/pkg/pb/base/v1/openapi.pb.go +++ b/pkg/pb/base/v1/openapi.pb.go @@ -46,7 +46,7 @@ var file_base_v1_openapi_proto_rawDesc = []byte{ 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x66, 0x79, 0x2f, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x66, 0x79, 0x2f, 0x62, 0x6c, 0x6f, 0x62, 0x2f, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x2f, 0x4c, 0x49, 0x43, 0x45, 0x4e, 0x53, 0x45, - 0x32, 0x06, 0x76, 0x30, 0x2e, 0x38, 0x2e, 0x36, 0x2a, 0x01, 0x02, 0x32, 0x10, 0x61, 0x70, 0x70, + 0x32, 0x06, 0x76, 0x30, 0x2e, 0x38, 0x2e, 0x37, 0x2a, 0x01, 0x02, 0x32, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x3a, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x5a, 0x23, 0x0a, 0x21, 0x0a, 0x0a, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x41, 0x75, 0x74, 0x68, 0x12, diff --git a/proto/base/v1/openapi.proto b/proto/base/v1/openapi.proto index 8100b0f07..141865b0d 100644 --- a/proto/base/v1/openapi.proto +++ b/proto/base/v1/openapi.proto @@ -9,7 +9,7 @@ option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { info: { title: "Permify API"; description: "Permify is an open source authorization service for creating fine-grained and scalable authorization systems."; - version: "v0.8.6"; + version: "v0.8.7"; contact: { name: "API Support"; url: "https://github.com/Permify/permify/issues";