Skip to content

Commit

Permalink
Merge pull request #39 from the-control-group/relay-connection
Browse files Browse the repository at this point in the history
Fix #32 - use relay-style connections
  • Loading branch information
mike-marcacci committed Jun 13, 2019
2 parents 63a97d0 + e7d05dc commit 1a6e8a4
Show file tree
Hide file tree
Showing 29 changed files with 808 additions and 340 deletions.
2 changes: 2 additions & 0 deletions packages/authx/package.json
Expand Up @@ -9,6 +9,7 @@
"@types/auth-header": "^1.0.1",
"@types/form-data": "^2.2.1",
"@types/graphql-api-koa": "^2.0.0",
"@types/graphql-relay": "^0.4.9",
"@types/jsonwebtoken": "^8.3.2",
"@types/koa": "^2.0.48",
"@types/koa-router": "^7.0.40",
Expand All @@ -20,6 +21,7 @@
"graphql": "^14.3.1",
"graphql-api-koa": "^2.0.0",
"graphql-playground-middleware-koa": "^1.6.12",
"graphql-relay": "^0.6.0",
"jsonwebtoken": "^8.5.0",
"koa": "^2.7.0",
"koa-body": "^4.1.0",
Expand Down
11 changes: 11 additions & 0 deletions packages/authx/src/graphql/GraphQLAuthorityConnection.ts
@@ -0,0 +1,11 @@
import { GraphQLList, GraphQLNonNull, GraphQLObjectType } from "graphql";
import { GraphQLPageInfo } from "./GraphQLPageInfo";
import { GraphQLAuthorityEdge } from "./GraphQLAuthorityEdge";

export const GraphQLAuthorityConnection = new GraphQLObjectType({
name: "AuthorityConnection",
fields: () => ({
pageInfo: { type: new GraphQLNonNull(GraphQLPageInfo) },
edges: { type: new GraphQLList(GraphQLAuthorityEdge) }
})
});
10 changes: 10 additions & 0 deletions packages/authx/src/graphql/GraphQLAuthorityEdge.ts
@@ -0,0 +1,10 @@
import { GraphQLObjectType, GraphQLString } from "graphql";
import { GraphQLAuthority } from "./GraphQLAuthority";

export const GraphQLAuthorityEdge = new GraphQLObjectType({
name: "AuthorityEdge",
fields: () => ({
cursor: { type: GraphQLString },
node: { type: GraphQLAuthority }
})
});
11 changes: 11 additions & 0 deletions packages/authx/src/graphql/GraphQLAuthorizationConnection.ts
@@ -0,0 +1,11 @@
import { GraphQLList, GraphQLNonNull, GraphQLObjectType } from "graphql";
import { GraphQLPageInfo } from "./GraphQLPageInfo";
import { GraphQLAuthorizationEdge } from "./GraphQLAuthorizationEdge";

export const GraphQLAuthorizationConnection = new GraphQLObjectType({
name: "AuthorizationConnection",
fields: () => ({
pageInfo: { type: new GraphQLNonNull(GraphQLPageInfo) },
edges: { type: new GraphQLList(GraphQLAuthorizationEdge) }
})
});
10 changes: 10 additions & 0 deletions packages/authx/src/graphql/GraphQLAuthorizationEdge.ts
@@ -0,0 +1,10 @@
import { GraphQLObjectType, GraphQLString } from "graphql";
import { GraphQLAuthorization } from "./GraphQLAuthorization";

export const GraphQLAuthorizationEdge = new GraphQLObjectType({
name: "AuthorizationEdge",
fields: () => ({
cursor: { type: GraphQLString },
node: { type: GraphQLAuthorization }
})
});
26 changes: 20 additions & 6 deletions packages/authx/src/graphql/GraphQLClient.ts
Expand Up @@ -7,9 +7,15 @@ import {
GraphQLObjectType
} from "graphql";

import {
connectionFromArray,
connectionArgs,
ConnectionArguments
} from "graphql-relay";

import { Client } from "../model";
import { Context } from "../Context";
import { GraphQLUser } from "./GraphQLUser";
import { GraphQLUserConnection } from "./GraphQLUserConnection";
import { filter } from "../util/filter";

export const GraphQLClient = new GraphQLObjectType<Client, Context>({
Expand All @@ -36,14 +42,22 @@ export const GraphQLClient = new GraphQLObjectType<Client, Context>({
},
urls: { type: new GraphQLList(GraphQLString) },
users: {
type: new GraphQLList(GraphQLUser),
async resolve(client, args, { realm, authorization: a, tx }: Context) {
type: GraphQLUserConnection,
args: connectionArgs,
async resolve(
client,
args: ConnectionArguments,
{ realm, authorization: a, tx }: Context
) {
return a &&
(await client.isAccessibleBy(realm, a, tx, "read.assignments"))
? filter(await client.users(tx), user =>
user.isAccessibleBy(realm, a, tx)
? connectionFromArray(
await filter(await client.users(tx), user =>
user.isAccessibleBy(realm, a, tx)
),
args
)
: [];
: null;
}
}
})
Expand Down
11 changes: 11 additions & 0 deletions packages/authx/src/graphql/GraphQLClientConnection.ts
@@ -0,0 +1,11 @@
import { GraphQLList, GraphQLNonNull, GraphQLObjectType } from "graphql";
import { GraphQLPageInfo } from "./GraphQLPageInfo";
import { GraphQLClientEdge } from "./GraphQLClientEdge";

export const GraphQLClientConnection = new GraphQLObjectType({
name: "ClientConnection",
fields: () => ({
pageInfo: { type: new GraphQLNonNull(GraphQLPageInfo) },
edges: { type: new GraphQLList(GraphQLClientEdge) }
})
});
10 changes: 10 additions & 0 deletions packages/authx/src/graphql/GraphQLClientEdge.ts
@@ -0,0 +1,10 @@
import { GraphQLObjectType, GraphQLString } from "graphql";
import { GraphQLClient } from "./GraphQLClient";

export const GraphQLClientEdge = new GraphQLObjectType({
name: "ClientEdge",
fields: () => ({
cursor: { type: GraphQLString },
node: { type: GraphQLClient }
})
});
11 changes: 11 additions & 0 deletions packages/authx/src/graphql/GraphQLCredentialConnection.ts
@@ -0,0 +1,11 @@
import { GraphQLList, GraphQLNonNull, GraphQLObjectType } from "graphql";
import { GraphQLPageInfo } from "./GraphQLPageInfo";
import { GraphQLCredentialEdge } from "./GraphQLCredentialEdge";

export const GraphQLCredentialConnection = new GraphQLObjectType({
name: "CredentialConnection",
fields: () => ({
pageInfo: { type: new GraphQLNonNull(GraphQLPageInfo) },
edges: { type: new GraphQLList(GraphQLCredentialEdge) }
})
});
10 changes: 10 additions & 0 deletions packages/authx/src/graphql/GraphQLCredentialEdge.ts
@@ -0,0 +1,10 @@
import { GraphQLObjectType, GraphQLString } from "graphql";
import { GraphQLCredential } from "./GraphQLCredential";

export const GraphQLCredentialEdge = new GraphQLObjectType({
name: "CredentialEdge",
fields: () => ({
cursor: { type: GraphQLString },
node: { type: GraphQLCredential }
})
});
26 changes: 20 additions & 6 deletions packages/authx/src/graphql/GraphQLGrant.ts
Expand Up @@ -7,11 +7,17 @@ import {
GraphQLObjectType
} from "graphql";

import {
connectionFromArray,
connectionArgs,
ConnectionArguments
} from "graphql-relay";

import { Grant, Client, User } from "../model";
import { Context } from "../Context";
import { GraphQLClient } from "./GraphQLClient";
import { GraphQLUser } from "./GraphQLUser";
import { GraphQLAuthorization } from "./GraphQLAuthorization";
import { GraphQLAuthorizationConnection } from "./GraphQLAuthorizationConnection";
import { filter } from "../util/filter";

export const GraphQLGrant: GraphQLObjectType<
Expand Down Expand Up @@ -86,13 +92,21 @@ export const GraphQLGrant: GraphQLObjectType<
}
},
authorizations: {
type: new GraphQLList(GraphQLAuthorization),
async resolve(grant, args, { realm, authorization: a, tx }: Context) {
type: GraphQLAuthorizationConnection,
args: connectionArgs,
async resolve(
grant,
args: ConnectionArguments,
{ realm, authorization: a, tx }: Context
) {
return a
? filter(await grant.authorizations(tx), authorization =>
authorization.isAccessibleBy(realm, a, tx)
? connectionFromArray(
await filter(await grant.authorizations(tx), authorization =>
authorization.isAccessibleBy(realm, a, tx)
),
args
)
: [];
: null;
}
}
})
Expand Down
11 changes: 11 additions & 0 deletions packages/authx/src/graphql/GraphQLGrantConnection.ts
@@ -0,0 +1,11 @@
import { GraphQLList, GraphQLNonNull, GraphQLObjectType } from "graphql";
import { GraphQLPageInfo } from "./GraphQLPageInfo";
import { GraphQLGrantEdge } from "./GraphQLGrantEdge";

export const GraphQLGrantConnection = new GraphQLObjectType({
name: "GrantConnection",
fields: () => ({
pageInfo: { type: new GraphQLNonNull(GraphQLPageInfo) },
edges: { type: new GraphQLList(GraphQLGrantEdge) }
})
});
10 changes: 10 additions & 0 deletions packages/authx/src/graphql/GraphQLGrantEdge.ts
@@ -0,0 +1,10 @@
import { GraphQLObjectType, GraphQLString } from "graphql";
import { GraphQLGrant } from "./GraphQLGrant";

export const GraphQLGrantEdge = new GraphQLObjectType({
name: "GrantEdge",
fields: () => ({
cursor: { type: GraphQLString },
node: { type: GraphQLGrant }
})
});
13 changes: 13 additions & 0 deletions packages/authx/src/graphql/GraphQLPageInfo.ts
@@ -0,0 +1,13 @@
import { GraphQLBoolean, GraphQLObjectType, GraphQLString } from "graphql";

export const GraphQLPageInfo = new GraphQLObjectType({
name: "PageInfo",
description:
"See: https://facebook.github.io/relay/graphql/connections.htm#sec-undefined.PageInfo",
fields: () => ({
hasPreviousPage: { type: GraphQLBoolean },
hasNextPage: { type: GraphQLBoolean },
startCursor: { type: GraphQLString },
endCursor: { type: GraphQLString }
})
});
26 changes: 20 additions & 6 deletions packages/authx/src/graphql/GraphQLRole.ts
Expand Up @@ -7,9 +7,15 @@ import {
GraphQLObjectType
} from "graphql";

import {
connectionFromArray,
connectionArgs,
ConnectionArguments
} from "graphql-relay";

import { Role } from "../model";
import { Context } from "../Context";
import { GraphQLUser } from "./GraphQLUser";
import { GraphQLUserConnection } from "./GraphQLUserConnection";
import { filter } from "../util/filter";

export const GraphQLRole = new GraphQLObjectType<Role, Context>({
Expand All @@ -23,14 +29,22 @@ export const GraphQLRole = new GraphQLObjectType<Role, Context>({
name: { type: GraphQLString },
description: { type: GraphQLString },
users: {
type: new GraphQLList(GraphQLUser),
async resolve(role, args, { realm, authorization: a, tx }: Context) {
type: GraphQLUserConnection,
args: connectionArgs,
async resolve(
role,
args: ConnectionArguments,
{ realm, authorization: a, tx }: Context
) {
return a &&
(await role.isAccessibleBy(realm, a, tx, "read.assignments"))
? filter(await role.users(tx), user =>
user.isAccessibleBy(realm, a, tx)
? connectionFromArray(
await filter(await role.users(tx), user =>
user.isAccessibleBy(realm, a, tx)
),
args
)
: [];
: null;
}
},
scopes: {
Expand Down
11 changes: 11 additions & 0 deletions packages/authx/src/graphql/GraphQLRoleConnection.ts
@@ -0,0 +1,11 @@
import { GraphQLList, GraphQLNonNull, GraphQLObjectType } from "graphql";
import { GraphQLPageInfo } from "./GraphQLPageInfo";
import { GraphQLRoleEdge } from "./GraphQLRoleEdge";

export const GraphQLRoleConnection = new GraphQLObjectType({
name: "RoleConnection",
fields: () => ({
pageInfo: { type: new GraphQLNonNull(GraphQLPageInfo) },
edges: { type: new GraphQLList(GraphQLRoleEdge) }
})
});
10 changes: 10 additions & 0 deletions packages/authx/src/graphql/GraphQLRoleEdge.ts
@@ -0,0 +1,10 @@
import { GraphQLObjectType, GraphQLString } from "graphql";
import { GraphQLRole } from "./GraphQLRole";

export const GraphQLRoleEdge = new GraphQLObjectType({
name: "RoleEdge",
fields: () => ({
cursor: { type: GraphQLString },
node: { type: GraphQLRole }
})
});

0 comments on commit 1a6e8a4

Please sign in to comment.