Skip to content

Commit

Permalink
Merge pull request #1711 from Permify/subject-filter
Browse files Browse the repository at this point in the history
feat: subject filter cursor pagination
  • Loading branch information
tolgaOzen authored Oct 22, 2024
2 parents e5b4f5f + fe427d0 commit 9956044
Show file tree
Hide file tree
Showing 7 changed files with 16 additions and 52 deletions.
2 changes: 1 addition & 1 deletion docs/api-reference/apidocs.swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": "v1.1.6",
"version": "v1.1.7",
"contact": {
"name": "API Support",
"url": "https://github.com/Permify/permify/issues",
Expand Down
2 changes: 1 addition & 1 deletion docs/api-reference/openapiv2/apidocs.swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": "v1.1.6",
"version": "v1.1.7",
"contact": {
"name": "API Support",
"url": "https://github.com/Permify/permify/issues",
Expand Down
40 changes: 5 additions & 35 deletions internal/engines/lookup.go
Original file line number Diff line number Diff line change
Expand Up @@ -240,44 +240,14 @@ func (engine *LookupEngine) LookupSubject(ctx context.Context, request *base.Per
}, nil
}

start := ""

// Sort the IDs
sort.Strings(ids)

// Handle continuous token if present
if request.GetContinuousToken() != "" {
var t database.ContinuousToken
t, err := utils.EncodedContinuousToken{Value: request.GetContinuousToken()}.Decode()
if err != nil {
return nil, err
}
start = t.(utils.ContinuousToken).Value
}

// Since the incoming 'ids' are already filtered based on the continuous token,
// there is no need to decode or handle the continuous token manually.
// The startIndex is initialized to 0.
startIndex := 0

if start != "" {
// Locate the position in the sorted list where the ID equals or exceeds the token value
for i, id := range ids {
if id >= start {
startIndex = i
break
}
}
}

// Convert size to int for compatibility with startIndex
// Convert page size to int for compatibility with startIndex
pageSize := int(size)

// Calculate the end index based on the page size
end := startIndex + pageSize
if end > len(ids) {
end = len(ids)
}
// Determine the end index based on the page size and total number of IDs
end := min(pageSize, len(ids))

// Generate the next continuous token if there are more results
if end < len(ids) {
Expand All @@ -288,8 +258,8 @@ func (engine *LookupEngine) LookupSubject(ctx context.Context, request *base.Per

// Return the paginated list of IDs
return &base.PermissionLookupSubjectResponse{
SubjectIds: ids[startIndex:end], // Slice the IDs based on pagination
ContinuousToken: ct, // Return the next continuous token
SubjectIds: ids[:end], // Slice the IDs based on pagination
ContinuousToken: ct, // Return the next continuous token
}, nil
}

Expand Down
18 changes: 6 additions & 12 deletions internal/engines/subjectFilter.go
Original file line number Diff line number Diff line change
Expand Up @@ -429,15 +429,15 @@ func (engine *SubjectFilter) subjectFilterDirectRelation(
// NewContextualRelationships() creates a ContextualRelationships instance from tuples in the request.
// QueryRelationships() then uses the filter to find and return matching relationships.
var cti *database.TupleIterator
cti, err = storageContext.NewContextualTuples(request.GetContext().GetTuples()...).QueryRelationships(filter, database.NewCursorPagination())
cti, err = storageContext.NewContextualTuples(request.GetContext().GetTuples()...).QueryRelationships(filter, database.NewCursorPagination(database.Cursor(request.GetContinuousToken()), database.Sort("subject_id")))
if err != nil {
return subjectFilterEmpty(), err
}

// Query the relationships for the entity in the request.
// TupleFilter helps in filtering out the relationships for a specific entity and a permission.
var rit *database.TupleIterator
rit, err = engine.dataReader.QueryRelationships(ctx, request.GetTenantId(), filter, request.GetMetadata().GetSnapToken(), database.NewCursorPagination())
rit, err = engine.dataReader.QueryRelationships(ctx, request.GetTenantId(), filter, request.GetMetadata().GetSnapToken(), database.NewCursorPagination(database.Cursor(request.GetContinuousToken()), database.Sort("subject_id")))
if err != nil {
return subjectFilterEmpty(), err
}
Expand Down Expand Up @@ -517,10 +517,10 @@ func (engine *SubjectFilter) subjectFilterDirectRelation(
// setChild generates a SubjectFilterFunction by applying a SubjectFilterCombiner
// to a set of child permission lookups, given a request and a list of Child objects.
func (engine *SubjectFilter) setChild(
ctx context.Context, // The context for carrying out the operation
ctx context.Context, // The context for carrying out the operation
request *base.PermissionLookupSubjectRequest, // The request containing parameters for lookup
children []*base.Child, // The children of a particular node in the permission schema
combiner SubjectFilterCombiner, // A function to combine the results from multiple lookup functions
children []*base.Child, // The children of a particular node in the permission schema
combiner SubjectFilterCombiner, // A function to combine the results from multiple lookup functions
) SubjectFilterFunction {
var functions []SubjectFilterFunction // Array of functions to store lookup functions for each child

Expand Down Expand Up @@ -795,13 +795,7 @@ func subjectFilterIntersection(ctx context.Context, functions []SubjectFilterFun
// If wildcard was encountered, we exclude the IDs in `excludedIds`
if encounteredWildcard {
if len(commonIds) == 0 {
// No specific common IDs were found, so all are included except exclusions
finalRes := []string{ALL}
if len(excludedIds) > 0 {
exclusions := "-" + strings.Join(excludedIds, ",")
return []string{finalRes[0] + exclusions}, nil
}
return []string{ALL}, nil
return []string{}, nil
}

// Exclude IDs from commonIds that are in excludedIds
Expand Down
2 changes: 1 addition & 1 deletion internal/info.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ var Identifier = ""
*/
const (
// Version is the last release of the Permify (e.g. v0.1.0)
Version = "v1.1.6"
Version = "v1.1.7"
)

// Function to create a single line of the ASCII art with centered content and color
Expand Down
2 changes: 1 addition & 1 deletion pkg/pb/base/v1/openapi.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion proto/base/v1/openapi.proto
Original file line number Diff line number Diff line change
Expand Up @@ -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: "v1.1.6";
version: "v1.1.7";
contact: {
name: "API Support";
url: "https://github.com/Permify/permify/issues";
Expand Down

0 comments on commit 9956044

Please sign in to comment.