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

Add com.walmartlabs.lacinia.executor/selection #335

Merged
merged 18 commits into from Sep 28, 2020
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGES.md
Expand Up @@ -4,6 +4,9 @@ Optional request tracing is now designed to be compatible with Apollo GraphQL's

New support for [Apollo GraphQL Federation](https://www.apollographql.com/docs/apollo-server/federation/introduction/).

Added function `com.walmartlabs.lacinia.executor/selection` which provides access to
the details about the selection, including directives and nested selections.

## 0.37.0 -- 30 Jun 2020

Added new function `com.walmartlabs.lacinia.util/inject-streamers`, used to
Expand Down
10 changes: 10 additions & 0 deletions dev-resources/com/walmartlabs/test_utils.clj
Expand Up @@ -6,6 +6,7 @@
[clojure.edn :as edn]
[com.walmartlabs.lacinia :as lacinia]
[com.walmartlabs.lacinia.util :as util]
[com.walmartlabs.lacinia.parser.schema :refer [parse-schema]]
[com.walmartlabs.lacinia.schema :as schema])
(:import
(clojure.lang IPersistentMap)))
Expand Down Expand Up @@ -70,6 +71,15 @@
(util/attach-resolvers resolvers)
(schema/compile options))))

(defn compile-sdl-schema
"Reads a schema SDL file, injects resolvers, and compiles the schema."
[resource-path resolvers]
(-> (io/resource resource-path)
slurp
parse-schema
(util/inject-resolvers resolvers)
schema/compile))

(defn execute
([compiled-schema query]
(execute compiled-schema query nil nil))
Expand Down
10 changes: 10 additions & 0 deletions dev-resources/selection/directive-args.sdl
@@ -0,0 +1,10 @@
directive @auth (role: String!) on FIELD_DEFINITION

directive @limit(value: Int = 10) on FIELD

schema { query: Query }

type Query {
basic: [String]!
}

15 changes: 15 additions & 0 deletions dev-resources/selection/enum-types.sdl
@@ -0,0 +1,15 @@
directive @auth (role: String!) on ENUM

schema { query: Query }

enum Rank @auth(role: "enum") { INTRO, JUNIOR, SENIOR }

type User {
name: String!
rank: Rank
}

type Query {
me: User
}

24 changes: 24 additions & 0 deletions dev-resources/selection/interface-types.sdl
@@ -0,0 +1,24 @@
directive @auth (role: String!) on OBJECT | INTERFACE

schema { query: Query }

interface User @auth(role: "basic") {
name: String!
}

type LegacyUser implements User @auth(role: "hidden") {
name: String!
userId: Int!
}

type ActiveUser implements User {
name: String!
userId: String!
}

type Query {
me: User

friends: [User!]!
}

15 changes: 15 additions & 0 deletions dev-resources/selection/object-type.sdl
@@ -0,0 +1,15 @@
directive @auth (role: String!) on OBJECT | FIELD_DEFINITION

schema { query: Query }

type User @auth(role: "basic") {
name: String! @auth(role: "advanced")
department: String!
}

type Query {
me: User

friends: [User!]!
}

15 changes: 15 additions & 0 deletions dev-resources/selection/scalar-types.sdl
@@ -0,0 +1,15 @@
schema { query: Query }

directive @auth (role: String!) on SCALAR

scalar UUID @auth(role: "basic")

type User {
name: String!
id: UUID
}

type Query {
me: User
}

10 changes: 10 additions & 0 deletions dev-resources/selection/simple.sdl
@@ -0,0 +1,10 @@
directive @auth (role: String!) on FIELD_DEFINITION

directive @concise on FIELD

schema { query: Query }

type Query {
basic: String! @auth(role: "basic")
}

22 changes: 22 additions & 0 deletions dev-resources/selection/union-types.sdl
@@ -0,0 +1,22 @@
directive @auth (role: String!) on OBJECT | UNION

schema { query: Query }

union User @auth(role: "basic") = ActiveUser | LegacyUser

type LegacyUser @auth(role: "hidden") {
userName: String!
userId: Int!
}

type ActiveUser {
name: String!
idCode: String!
}

type Query {
me: User

friends: [User!]!
}

14 changes: 14 additions & 0 deletions docs/resolve/selections.rst
Expand Up @@ -89,9 +89,23 @@ These last two are leaf nodes, because they are scalar values.
The list of ``characters`` (from the ``friends`` field) then has its ``name`` field selected.
The result map then constructs from bottom to top.

Accessing the Selection
-----------------------

From inside a field resolver, the function :api:`executor/selection` may be invoked to
return a :api:`protocols/FieldSelection` instance; from this instance it is possible
to identify directives on the field, navigate to nested selections, or even navigate to the
field type and identify directives there.

Previewing Selections
---------------------

.. tip::

This API is a bit older than :api:`executor/selection`, but is a bit easier to use.
Also, ``selection`` includes the field selection itself; these APIs identify only
nested selections below the current field.

A field resolver can "preview" what fields will be selected below it in the selections tree.
This is a tool frequently used to optimize data retrieval operations.

Expand Down
11 changes: 2 additions & 9 deletions docs/tracing.rst
Expand Up @@ -27,15 +27,8 @@ of multiple fields represent overlapping time periods, which is exactly what you
Generally, resolver tracing maps are added to the list in order of completion, but the exact order is
not guaranteed.

Enabling tracing adds a lot of overhead to execution and parsing, both for the essential overhead of collecting
the tracing information, but also because certain optimizations are disabled when tracing is enabled;
for example default field resolvers (where no explicit resolver is provided) are heavily optimized normally, to
avoid unecessary function calls and object creation.

.. warning::

Tracing should never be enabled in production. This can be accomplished by removing the ``com.walmartlabs.lacinia.pedestal2/enable-tracing-interceptor``
interceptor from the pipeline (when using lacinia-pedestal).
Enabling tracing adds some overhead to query execution and will often vastly increase the size of the result (which,
in turn, can cause much larger HTTP responses), so the tracing should be used judiciously.



Expand Down
16 changes: 16 additions & 0 deletions perf/benchmarks.csv
Expand Up @@ -181,3 +181,19 @@ date,commit,kind,parse,exec
20200619,9b7459bf,basic,0.19865560343769184,0.2354193381588716
20200619,9b7459bf,basic-vars,0.2260441183689628,0.31585147254901963
20200619,9b7459bf,errors,0.10017066182698124,6.0060396
20200918,fe6562b7,introspection,0.6266158460784315,2.833012211711712
20200918,fe6562b7,basic,0.15509166615931,0.20755368893387313
20200918,fe6562b7,basic-vars,0.18651278707107843,0.21064954722792611
20200918,fe6562b7,errors,0.0806548746264602,5.073428000000001
20200923,e678d1d6,introspection,0.7504292595238095,3.2544591000000005
20200923,e678d1d6,basic,0.18639196106194691,0.2352217332613391
20200923,e678d1d6,basic-vars,0.23791920902777777,0.2318051874566875
20200923,e678d1d6,errors,0.0890985931498997,5.281042833333333
20200928,0cfdbcfb,introspection,0.6375315082815735,2.0291349705882356
20200928,0cfdbcfb,basic,0.1773841184573003,0.16587745114006516
20200928,0cfdbcfb,basic-vars,0.19652242017879953,0.17003586015981736
20200928,0cfdbcfb,errors,0.08625362936966695,1.9438954748427675
20200928,0cfdbcfb,introspection,0.6495307310126582,2.014724068627451
20200928,0cfdbcfb,basic,0.16301182026666666,0.1713143711001642
20200928,0cfdbcfb,basic-vars,0.199482251984127,0.1727440829159711
20200928,0cfdbcfb,errors,0.08740605913978494,1.9187714722222227