Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add is_last_page to list response #425

Merged
merged 4 commits into from
Feb 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 55 additions & 6 deletions cmd/relationtuple/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package relationtuple

import (
"fmt"
"strconv"

acl "github.com/ory/keto/proto/ory/keto/acl/v1alpha1"

Expand All @@ -19,9 +20,11 @@ import (
)

const (
FlagSubject = "subject"
FlagRelation = "relation"
FlagObject = "object"
FlagSubject = "subject"
FlagRelation = "relation"
FlagObject = "object"
FlagPageSize = "page-size"
FlagPageToken = "page-token"
)

func registerRelationTupleFlags(flags *pflag.FlagSet) {
Expand Down Expand Up @@ -54,6 +57,11 @@ func readQueryFromFlags(cmd *cobra.Command, namespace string) (*acl.ListRelation
}

func newGetCmd() *cobra.Command {
var (
pageSize int32
pageToken string
)

cmd := &cobra.Command{
Use: "get <namespace>",
Args: cobra.ExactArgs(1),
Expand All @@ -71,21 +79,62 @@ func newGetCmd() *cobra.Command {
}

resp, err := cl.ListRelationTuples(cmd.Context(), &acl.ListRelationTuplesRequest{
Query: query,
PageSize: 100,
Query: query,
PageSize: pageSize,
PageToken: pageToken,
})
if err != nil {
_, _ = fmt.Fprintf(cmd.ErrOrStderr(), "Could not make request: %s\n", err)
return err
}

cmdx.PrintTable(cmd, relationtuple.NewProtoRelationCollection(resp.RelationTuples))
cmdx.PrintTable(cmd, &responseOutput{
RelationTuples: relationtuple.NewProtoRelationCollection(resp.RelationTuples),
IsLastPage: resp.IsLastPage,
NextPageToken: resp.NextPageToken,
})
return nil
},
}

cmd.Flags().AddFlagSet(packageFlags)
registerRelationTupleFlags(cmd.Flags())

cmd.Flags().StringVar(&pageToken, FlagPageToken, "", "page token acquired from a previous response")
cmd.Flags().Int32Var(&pageSize, FlagPageSize, 100, "maximum number of items to return")

return cmd
}

type responseOutput struct {
RelationTuples *relationtuple.RelationCollection `json:"relation_tuples"`
IsLastPage bool `json:"is_last_page"`
NextPageToken string `json:"next_page_token"`
}

func (r *responseOutput) Header() []string {
return r.RelationTuples.Header()
}

func (r *responseOutput) Table() [][]string {
return append(
r.RelationTuples.Table(),
[]string{},
[]string{"NEXT PAGE TOKEN", r.NextPageToken},
[]string{"IS LAST PAGE", strconv.FormatBool(r.IsLastPage)},
)
}

func (r *responseOutput) Interface() interface{} {
return r
}

func (r *responseOutput) Len() int {
return r.RelationTuples.Len() + 3
}

func (r *responseOutput) IDs() []string {
return r.RelationTuples.IDs()
}

var _ cmdx.Table = (*responseOutput)(nil)
4 changes: 2 additions & 2 deletions contrib/cat-videos-example/keto.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ namespaces:
dsn: memory

serve:
rest:
read:
host: 0.0.0.0
port: 4466
grpc:
write:
host: 0.0.0.0
port: 4467
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ require (
github.com/ory/graceful v0.1.1
github.com/ory/herodot v0.9.1
github.com/ory/jsonschema/v3 v3.0.1
github.com/ory/x v0.0.179
github.com/ory/x v0.0.180
github.com/pelletier/go-toml v1.8.0
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2
github.com/pkg/errors v0.9.1
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -978,8 +978,8 @@ github.com/ory/x v0.0.93/go.mod h1:lfcTaGXpTZs7IEQAW00r9EtTCOxD//SiP5uWtNiz31g=
github.com/ory/x v0.0.110/go.mod h1:DJfkE3GdakhshNhw4zlKoRaL/ozg/lcTahA9OCih2BE=
github.com/ory/x v0.0.127/go.mod h1:FwUujfFuCj5d+xgLn4fGMYPnzriR5bdAIulFXMtnK0M=
github.com/ory/x v0.0.128/go.mod h1:ykx1XOsl9taQtoW2yNvuxl/feEfTfrZTcbY1U7841tI=
github.com/ory/x v0.0.179 h1:ewzGC1n2uWEmGRDVzYYzHsbdHrxNtkCwGjbkpZeeNKI=
github.com/ory/x v0.0.179/go.mod h1:SGETCUk1DgQC30bb7y4hjhkKGQ1x0YOsldrmGmy6MNc=
github.com/ory/x v0.0.180 h1:PI7wkP8rKs/hzfQM7SHot1iunImS5rLDXVgS64Tqr54=
github.com/ory/x v0.0.180/go.mod h1:SGETCUk1DgQC30bb7y4hjhkKGQ1x0YOsldrmGmy6MNc=
github.com/parnurzeal/gorequest v0.2.15/go.mod h1:3Kh2QUMJoqw3icWAecsyzkpY7UzRfDhbRdTjtNwNiUE=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g=
Expand Down
39 changes: 37 additions & 2 deletions internal/e2e/cases_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ package e2e

import (
"fmt"
"strconv"
"testing"

"github.com/ory/keto/internal/x"

"github.com/stretchr/testify/assert"

"github.com/ory/keto/internal/expand"
Expand All @@ -23,8 +26,8 @@ func runCases(c client, nspaces []*namespace.Namespace) func(*testing.T) {

c.createTuple(t, tuple)

allTuple := c.queryTuple(t, &relationtuple.RelationQuery{Namespace: tuple.Namespace})
assert.Contains(t, allTuple, tuple)
resp := c.queryTuple(t, &relationtuple.RelationQuery{Namespace: tuple.Namespace})
assert.Contains(t, resp.RelationTuples, tuple)

// try the check API to see whether the tuple is interpreted correctly
assert.True(t, c.check(t, tuple))
Expand Down Expand Up @@ -68,5 +71,37 @@ func runCases(c client, nspaces []*namespace.Namespace) func(*testing.T) {
assert.Contains(t, actualTree.Children, child)
}
})

t.Run("case=gets result paginated", func(t *testing.T) {
const nTuples = 10

rel := fmt.Sprintf("some unique relation %T", c)
for i := 0; i < nTuples; i++ {
c.createTuple(t, &relationtuple.InternalRelationTuple{
Namespace: nspaces[0].Name,
Object: "o" + strconv.Itoa(i),
Relation: rel,
Subject: &relationtuple.SubjectID{ID: "s" + strconv.Itoa(i)},
})
}

var (
resp relationtuple.GetResponse
nPages int
)
for ; !resp.IsLastPage; nPages++ {
resp = *c.queryTuple(t,
&relationtuple.RelationQuery{
Namespace: nspaces[0].Name,
Relation: rel,
},
x.WithToken(resp.NextPageToken),
x.WithSize(1),
)
assert.Len(t, resp.RelationTuples, 1)
}

assert.Equal(t, nTuples, nPages)
})
}
}
2 changes: 1 addition & 1 deletion internal/e2e/full_suit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import (
type (
client interface {
createTuple(t require.TestingT, r *relationtuple.InternalRelationTuple)
queryTuple(t require.TestingT, q *relationtuple.RelationQuery) []*relationtuple.InternalRelationTuple
queryTuple(t require.TestingT, q *relationtuple.RelationQuery, opts ...x.PaginationOptionSetter) *relationtuple.GetResponse
check(t require.TestingT, r *relationtuple.InternalRelationTuple) bool
expand(t require.TestingT, r *relationtuple.SubjectSet, depth int) *expand.Tree
}
Expand Down
17 changes: 13 additions & 4 deletions internal/e2e/grpc_client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import (
"strconv"
"strings"

"github.com/ory/keto/internal/x"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

Expand Down Expand Up @@ -34,7 +36,7 @@ func (g *grpcClient) createTuple(t require.TestingT, r *relationtuple.InternalRe
assert.Len(t, stderr, 0, stdout)
}

func (g *grpcClient) queryTuple(t require.TestingT, q *relationtuple.RelationQuery) []*relationtuple.InternalRelationTuple {
func (g *grpcClient) queryTuple(t require.TestingT, q *relationtuple.RelationQuery, opts ...x.PaginationOptionSetter) *relationtuple.GetResponse {
var flags []string
if q.Subject != nil {
flags = append(flags, "--"+clirelationtuple.FlagSubject, q.Subject.String())
Expand All @@ -45,13 +47,20 @@ func (g *grpcClient) queryTuple(t require.TestingT, q *relationtuple.RelationQue
if q.Object != "" {
flags = append(flags, "--"+clirelationtuple.FlagObject, q.Object)
}
pagination := x.GetPaginationOptions(opts...)
if pagination.Token != "" {
flags = append(flags, "--"+clirelationtuple.FlagPageToken, pagination.Token)
}
if pagination.Size != 0 {
flags = append(flags, "--"+clirelationtuple.FlagPageSize, strconv.Itoa(pagination.Size))
}

out := g.c.ExecNoErr(t, append(flags, "relation-tuple", "get", q.Namespace)...)

var rels []*relationtuple.InternalRelationTuple
require.NoError(t, json.Unmarshal([]byte(out), &rels), "%s", out)
var resp relationtuple.GetResponse
require.NoError(t, json.Unmarshal([]byte(out), &resp), "%s", out)

return rels
return &resp
}

func (g *grpcClient) check(t require.TestingT, r *relationtuple.InternalRelationTuple) bool {
Expand Down
24 changes: 18 additions & 6 deletions internal/e2e/rest_client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ import (
"io"
"io/ioutil"
"net/http"
"strconv"

"github.com/ory/keto/internal/x"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/tidwall/gjson"

"github.com/ory/keto/internal/check"
"github.com/ory/keto/internal/expand"
Expand Down Expand Up @@ -54,14 +56,24 @@ func (rc *restClient) createTuple(t require.TestingT, r *relationtuple.InternalR
assert.Equal(t, http.StatusCreated, code, body)
}

func (rc *restClient) queryTuple(t require.TestingT, q *relationtuple.RelationQuery) []*relationtuple.InternalRelationTuple {
body, code := rc.makeRequest(t, http.MethodGet, fmt.Sprintf("%s?%s", relationtuple.RouteBase, q.ToURLQuery().Encode()), "", false)
func (rc *restClient) queryTuple(t require.TestingT, q *relationtuple.RelationQuery, opts ...x.PaginationOptionSetter) *relationtuple.GetResponse {
urlQuery := q.ToURLQuery()

pagination := x.GetPaginationOptions(opts...)
if pagination.Size != 0 {
urlQuery.Set("page_size", strconv.Itoa(pagination.Size))
}
if pagination.Token != "" {
urlQuery.Set("page_token", pagination.Token)
}

body, code := rc.makeRequest(t, http.MethodGet, fmt.Sprintf("%s?%s", relationtuple.RouteBase, urlQuery.Encode()), "", false)
require.Equal(t, http.StatusOK, code, body)

tuple := make([]*relationtuple.InternalRelationTuple, 0, gjson.Get(body, "relations.#").Int())
require.NoError(t, json.Unmarshal([]byte(gjson.Get(body, "relations").Raw), &tuple))
var dec relationtuple.GetResponse
require.NoError(t, json.Unmarshal([]byte(body), &dec))

return tuple
return &dec
}

func (rc *restClient) check(t require.TestingT, r *relationtuple.InternalRelationTuple) bool {
Expand Down
4 changes: 2 additions & 2 deletions internal/expand/engine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,11 @@ func TestEngine(t *testing.T) {
Children: []*expand.Tree{
{
Type: expand.Leaf,
Subject: tommy,
Subject: paul,
},
{
Type: expand.Leaf,
Subject: paul,
Subject: tommy,
},
},
}, tree)
Expand Down
4 changes: 3 additions & 1 deletion internal/persistence/sql/relationtuples.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ func (p *Persister) insertRelationTuple(ctx context.Context, rel *relationtuple.
// TODO sharding
shardID := "default"

p.l.WithFields(rel.ToLoggerFields()).Trace("creating in database")

return p.connection(ctx).RawQuery(fmt.Sprintf(
"INSERT INTO %s (shard_id, object, relation, subject, commit_time) VALUES (?, ?, ?, ?, ?)", tableFromNamespace(n)),
shardID, rel.Object, rel.Relation, rel.Subject.String(), commitTime,
Expand Down Expand Up @@ -111,7 +113,7 @@ func (p *Persister) GetRelationTuples(ctx context.Context, query *relationtuple.
pagination.Offset,
)
} else {
rawQuery = fmt.Sprintf("SELECT * FROM %s WHERE %s LIMIT %d OFFSET %d",
rawQuery = fmt.Sprintf("SELECT * FROM %s WHERE %s ORDER BY object, relation, subject, commit_time LIMIT %d OFFSET %d",
tableFromNamespace(n),
strings.Join(where, " AND "),
pagination.Limit+1,
Expand Down
Loading