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

Pagination Cursors on Connections (Relay Specification) #282

Merged
merged 22 commits into from
Jul 2, 2021

Conversation

litewarp
Copy link
Contributor

@litewarp litewarp commented Jun 27, 2021

Description

UPDATE This PR only contains the first part of the Relay implementation, the pagination cursors. For the node resolution part, see #285.

Added a bunch of features to make the library fully-compatible with Relay. That is:

  • Connections now return totalCount, edges, and pageInfo

  • Connections now accept pagination arguments using Relay's cursor-based approach while still allowing for limit/offset calculations.

  • A Node interface is added which ensures that all types implementing the interface have an id field that is unique

  • A root Query field "node" is added allowing users to query a node by its ID and resolve the correct type based on the labels of the node.

Input

type Actor implements Node {
  id: ID! @id
  name: String
  movies: [Movie!]! @relationship(type: "ACTED_IN", properties: "ActedIn", direction: OUT)
}

type Movie implements Node {
  id: ID! @id
  title: String
  actors: [Actor!]! @relationship(type: "ACTED_IN", properties: "ActedIn", direction: IN)
}

interface ActedIn {
  screenTime: Int!
}

Output

# only relevant types shown
# ...

type ActorMoviesConnection {
  edges: [ActorMoviesRelationship!]!
  pageInfo: PageInfo!
  totalCount: Int!
}

input ActorMoviesConnectionOptions {
  sort: [ActorMoviesConnectionSort!]
  first: Int
  after: Cursor
}

"""Opaque cursor used for pagination (Relay)"""
scalar Cursor

type MovieActorsConnection {
  edges: [MovieActorsRelationship!]!
  pageInfo: PageInfo!
  totalCount: Int!
}

input MovieActorsConnectionOptions {
  sort: [MovieActorsConnectionSort!]
  first: Int
  after: Cursor
}

type MovieActorsRelationship implements ActedIn {
  cursor: Cursor!
  node: Actor!
  screenTime: Int!
}

"""Pagination information (Relay)"""
type PageInfo {
    hasNextPage: Boolean!
    hasPreviousPage: Boolean!
    startCursor: Cursor
    endCursor: Cursor
}

"""Globally-identifiable node (Relay)"""
interface Node {
  id: ID!
}

type Query {
  actors(where: ActorWhere, options: ActorOptions): [Actor!]!
  movies(where: MovieWhere, options: MovieOptions): [Movie!]!
  node(id: ID!): Node!
}
# ...

Checklist

The following requirements should have been met (depending on the changes in the branch):

  • Documentation has been updated
  • TCK tests have been updated
  • Integration tests have been updated
  • Example applications have been updated
  • New files have copyright header
  • CLA (https://neo4j.com/developer/cla/) has been signed

@darrellwarde
Copy link
Contributor

First comment is, can you please complete the CLA (https://neo4j.com/developer/cla/) so that we can get the pipeline running and see where we stand? Thanks.

Copy link
Contributor

@darrellwarde darrellwarde left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like really great work, thanks for the submission. Honestly, this looks like it should work in practice, but there are a couple of things I would like to see clarified/fixed:

  • I believe all node types should implement the Node interface, but this introduces a lot of problems with enforcing the id field, and migrating existing datasets. This was always one of our blockers for doing this now.
  • How are cursors calculated? Trying to figure this out as it's not overly clear, and I want to make sure there are no downsides to this approach. We were considering actually storing cursors on relationships as properties.

packages/graphql/src/schema/make-augmented-schema.ts Outdated Show resolved Hide resolved
packages/graphql/src/schema/make-augmented-schema.ts Outdated Show resolved Hide resolved
packages/graphql/src/schema/make-augmented-schema.ts Outdated Show resolved Hide resolved
packages/graphql/src/schema/make-augmented-schema.ts Outdated Show resolved Hide resolved
packages/graphql/src/schema/connection.ts Outdated Show resolved Hide resolved
packages/graphql/src/schema/make-augmented-schema.ts Outdated Show resolved Hide resolved
packages/graphql/src/schema/connection.ts Outdated Show resolved Hide resolved
@litewarp
Copy link
Contributor Author

litewarp commented Jun 28, 2021

  • How are cursors calculated? Trying to figure this out as it's not overly clear, and I want to make sure there are no downsides to this approach. We were considering actually storing cursors on relationships as properties.

So the cursors are created based on a base64 transform exported as the helpers below by the graphql-relay-js package:

const PREFIX = 'arrayconnection:';

/**
 * Creates the cursor string from an offset.
 */
export function offsetToCursor(offset: number): ConnectionCursor {
  return base64(PREFIX + offset.toString());
}

/**
 * Extracts the offset from the cursor string.
 */
export function cursorToOffset(cursor: ConnectionCursor): number {
  return parseInt(unbase64(cursor).substring(PREFIX.length), 10);
}

However, this is only one method of generating cursors, although most of the implementations I've seen seem to use base64:

The key thing is that cursors should be translatable in some way to the offset so that the database call doesn't have to traverse the entire collection to find the subsequent starting point when the user calls for the next group of data.

@darrellwarde
Copy link
Contributor

The key thing is that cursors should be translatable in some way to the offset so that the database call doesn't have to traverse the entire collection to find the subsequent starting point when the user calls for the next group of data.

Thanks for the explanation and references. This makes sense, however one thing I can't quite work out is how this works when data changes between queries. Say you had a query for the first 5 comments of all posts, ordered by their creation timestamp descending:

query {
  posts {
    commentsConnection(options: { first: 5, sort: { node: { createdAt: DESC } } }) {
      edges {
        cursor
        node {
          ...commentFields
        }
      }
    }
  }
}

Say this returns the following 5 posts in descending order the first time around:

  1. Post 5 (cursor: "a")
  2. Post 4 (cursor: "b")
  3. Post 3 (cursor: "c")
  4. Post 2 (cursor: "d")
  5. Post 1 (cursor: "e")

Now let's say a 6th post is created, and it is at the top of the list because it is the most recently created, I imagine your list would now look like:

  1. Post 6 (cursor: "a")
  2. Post 5 (cursor: "b")
  3. Post 4 (cursor: "c")
  4. Post 3 (cursor: "d")
  5. Post 2 (cursor: "e")

I might be completely misunderstanding - I only come to this conclusion because if cursors are calculated based on offset, rather than being "saved" on particular relationships (which is what we thought would have to be done), this is how I imagine it will work. If that is the case, would this not be a problem in that the starting point can change in between queries?

@darrellwarde
Copy link
Contributor

First comment is, can you please complete the CLA (https://neo4j.com/developer/cla/) so that we can get the pipeline running and see where we stand? Thanks.

Great, thanks for doing that! Looks like there is just one test failure because of some more recent changes on the 2.0.0 branch - can you please merge those changes from the 2.0.0 into your branch?

@darrellwarde
Copy link
Contributor

Right, I have a bit of a painful request for you, which I hope you won't mind doing.

Would you mind pulling out anything to do with the Node interface and the node query into a different branch and raise a separate PR for that? I think we can all agree that is where the complexity lies here. If we can get that set up, I think we will be able to get the cursor-based pagination side of things reviewed and merged pretty quickly, and we can better focus on how to add support for the node IDs, etc. 🙂

@litewarp litewarp changed the title Full Support for the Relay Specification Pagination Cursors on Connections (Relay Specification) Jun 29, 2021
@litewarp
Copy link
Contributor Author

litewarp commented Jun 29, 2021

The key thing is that cursors should be translatable in some way to the offset so that the database call doesn't have to traverse the entire collection to find the subsequent starting point when the user calls for the next group of data.

Thanks for the explanation and references. This makes sense, however one thing I can't quite work out is how this works when data changes between queries. Say you had a query for the first 5 comments of all posts, ordered by their creation timestamp descending:

query {
  posts {
    commentsConnection(options: { first: 5, sort: { node: { createdAt: DESC } } }) {
      edges {
        cursor
        node {
          ...commentFields
        }
      }
    }
  }
}

Say this returns the following 5 posts in descending order the first time around:

  1. Post 5 (cursor: "a")
  2. Post 4 (cursor: "b")
  3. Post 3 (cursor: "c")
  4. Post 2 (cursor: "d")
  5. Post 1 (cursor: "e")

Now let's say a 6th post is created, and it is at the top of the list because it is the most recently created, I imagine your list would now look like:

  1. Post 6 (cursor: "a")
  2. Post 5 (cursor: "b")
  3. Post 4 (cursor: "c")
  4. Post 3 (cursor: "d")
  5. Post 2 (cursor: "e")

I might be completely misunderstanding - I only come to this conclusion because if cursors are calculated based on offset, rather than being "saved" on particular relationships (which is what we thought would have to be done), this is how I imagine it will work. If that is the case, would this not be a problem in that the starting point can change in between queries?

So it depends on how your querying is done. Every time there's a change in the query (i.e., sort, or new filters, or new args), cursors will be recalculated on the server and the client will update with those new cursors. In the world where there are no changes, relay knows the order of the list and the number of items so recalculating the position on the client side is doable.

So in terms of "the starting point changing", this would only be an issue on the client when they have not refetched new data (causing recalculation of the cursors). In that case, if you don't want to cause a refetch after a mutation, you can actually manually add the new item to the cache while keeping the cursors consistent by using the Relay connection handler.

If you're using Apollo, they have a field policy helper specifically for relay pagination. I believe urql has similar functionality.

I suppose I don't really understand how storing "cursors" on the relationship lets you do pagination. If a user resorts, you'd have to recreate the entire list of cursors in the order they wanted. And then when you want to start off after a certain cursor, you'd need to traverse through the entire list to find the starting point.

Copy link
Contributor

@darrellwarde darrellwarde left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like we're close on this one now that this PR just focuses on pagination. A few points for review, would especially like to see some integration testing for the pagination functionality. Thanks again for the work on this, really great to see! 🙂

packages/graphql/src/schema/make-augmented-schema.ts Outdated Show resolved Hide resolved
packages/graphql/src/schema/make-augmented-schema.ts Outdated Show resolved Hide resolved
packages/graphql/src/schema/connection.ts Outdated Show resolved Hide resolved
@darrellwarde
Copy link
Contributor

The key thing is that cursors should be translatable in some way to the offset so that the database call doesn't have to traverse the entire collection to find the subsequent starting point when the user calls for the next group of data.

Thanks for the explanation and references. This makes sense, however one thing I can't quite work out is how this works when data changes between queries. Say you had a query for the first 5 comments of all posts, ordered by their creation timestamp descending:

query {
  posts {
    commentsConnection(options: { first: 5, sort: { node: { createdAt: DESC } } }) {
      edges {
        cursor
        node {
          ...commentFields
        }
      }
    }
  }
}

Say this returns the following 5 posts in descending order the first time around:

  1. Post 5 (cursor: "a")
  2. Post 4 (cursor: "b")
  3. Post 3 (cursor: "c")
  4. Post 2 (cursor: "d")
  5. Post 1 (cursor: "e")

Now let's say a 6th post is created, and it is at the top of the list because it is the most recently created, I imagine your list would now look like:

  1. Post 6 (cursor: "a")
  2. Post 5 (cursor: "b")
  3. Post 4 (cursor: "c")
  4. Post 3 (cursor: "d")
  5. Post 2 (cursor: "e")

I might be completely misunderstanding - I only come to this conclusion because if cursors are calculated based on offset, rather than being "saved" on particular relationships (which is what we thought would have to be done), this is how I imagine it will work. If that is the case, would this not be a problem in that the starting point can change in between queries?

So it depends on how your querying is done. Every time there's a change in the query (i.e., sort, or new filters, or new args), cursors will be recalculated on the server and the client will update with those new cursors. In the world where there are no changes, relay knows the order of the list and the number of items so recalculating the position on the client side is doable.

So in terms of "the starting point changing", this would only be an issue on the client when they have not refetched new data (causing recalculation of the cursors). In that case, if you don't want to cause a refetch after a mutation, you can actually manually add the new item to the cache while keeping the cursors consistent by using the Relay connection handler.

If you're using Apollo, they have a field policy helper specifically for relay pagination. I believe urql has similar functionality.

I suppose I don't really understand how storing "cursors" on the relationship lets you do pagination. If a user resorts, you'd have to recreate the entire list of cursors in the order they wanted. And then when you want to start off after a certain cursor, you'd need to traverse through the entire list to find the starting point.

I guess I'm less thinking about examples where a user is querying the data that they're mutating themselves, but where data has been mutated by another user (another client, so cache wouldn't have updated unless subscriptions are being used, etc.). In this case, the offset could be "changed" between queries by another user inserting data, so when our user resumes pagination from a known cursor, with the same filters, the node that this cursor relates to has now been shifted to the right.

I might be misunderstanding and it's very hard to express my thoughts through text - you seem to have significantly more knowledge of Relay than I do! 🤯

The thinking of having cursors as properties on relationships was in very early stages, so it might have been completely off the mark. But it was less thinking that cursors were related to offsets, so that if more data was inserted at the start of the list, you still get the same node back with the cursor, compared to a particular position in a list with this approach. Yes, you would have to fetch the entire list matching the filter and then slice it down based on the first and after arguments, but this could all easily be done in Cypher which means the Cypher planner should have been able to deal with it quite well.

@litewarp
Copy link
Contributor Author

litewarp commented Jul 1, 2021

Just an FYI. There was a bug with the skipLimitStr function. The correct syntax (as I learned on the discord today) for pagination is [offset..sliceEnd] rather than [offset..limit]. So you need to add the offset to the limit to get the sliceEnd. But some of the input values are Integers so you need to convert them before adding them together.

Also since the offsets start at 0 but the cypher string should start with 1, (e.g., [1..11]) you need to make sure the create-connection-and-params translation increments it by one.

I ended up writing some unit tests for the pagination utilities to help me debug and ensure consistency in the output.

Copy link
Contributor

@darrellwarde darrellwarde left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is really starting to look good now, the only comment that I really have is regarding moving and renaming a test file! I've also asked @danstarns to review this, but it feels to me like we're pretty close here. 🙂

packages/graphql/tests/integration/pagination.int.test.ts Outdated Show resolved Hide resolved
Copy link
Contributor

@darrellwarde darrellwarde left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only one small comment from me now, but this is easily fixed at any point, and everything else looks good to me!

Thanks for your work on this @litewarp, saved us a lot of time and implemented a much requested feature. Will wait for a review from @danstarns before merging.

Comment on lines +65 to +86
export function createSkipLimitStr({ skip, limit }: { skip?: number | Integer; limit?: number | Integer }): string {
const hasSkip = typeof skip !== "undefined" && skip !== 0;
const hasLimit = typeof limit !== "undefined" && limit !== 0;
let skipLimitStr = "";

if (hasSkip && !hasLimit) {
skipLimitStr = `[${skip}..]`;
}

if (hasLimit && !hasSkip) {
skipLimitStr = `[..${limit}]`;
}

if (hasLimit && hasSkip) {
const sliceStart = isInt(skip as Integer) ? (skip as Integer).toNumber() : skip;
const itemsToGrab = isInt(limit as Integer) ? (limit as Integer).toNumber() : limit;
const sliceEnd = (sliceStart as number) + (itemsToGrab as number);
skipLimitStr = `[${skip}..${sliceEnd}]`;
}

return skipLimitStr;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably be in the translate directory, but we can easily shuffle things around when merged, so not a blocker.

@danstarns
Copy link
Contributor

Hey @litewarp, Am I doing something wrong?

Schema:

type Person {
    name: String
    actedIn: [Movie] @relationship(type: "ACTED_IN", direction: OUT)
}

type Movie {
    title: String
}

Query:

 {
  people {
    name
    actedInConnection {
      edges {
        cursor
        node {
          title
        }
      }
    }
  }
}

Error:

{
  "errors": [
    {
      "message": "Cannot read property 'cursor' of undefined",
      "locations": [
        {
          "line": 4,
          "column": 5
        }
      ],
      "path": [
        "people",
        4,
        "actedInConnection"
      ],
      "extensions": {
        "code": "INTERNAL_SERVER_ERROR",
        "exception": {
          "stacktrace": [
            "TypeError: Cannot read property 'cursor' of undefined",
            "    at Object.createConnectionWithEdgeProperties (C:\\code\\neo4j\\graphql\\packages\\graphql\\src\\schema\\pagination.ts:57:36)",
            "    at resolve (C:\\code\\neo4j\\graphql\\packages\\graphql\\src\\schema\\make-augmented-schema.ts:997:32)",
            "    at field.resolve (C:\\code\\neo4j\\graphql\\node_modules\\apollo-server-core\\src\\utils\\schemaInstrumentation.ts:103:18)",
            "    at resolveField (C:\\code\\neo4j\\graphql\\node_modules\\graphql\\execution\\execute.js:464:18)",
            "    at executeFields (C:\\code\\neo4j\\graphql\\node_modules\\graphql\\execution\\execute.js:292:18)",
            "    at collectAndExecuteSubfields (C:\\code\\neo4j\\graphql\\node_modules\\graphql\\execution\\execute.js:748:10)",
            "    at completeObjectValue (C:\\code\\neo4j\\graphql\\node_modules\\graphql\\execution\\execute.js:738:10)",
            "    at completeValue (C:\\code\\neo4j\\graphql\\node_modules\\graphql\\execution\\execute.js:590:12)",
            "    at completeValue (C:\\code\\neo4j\\graphql\\node_modules\\graphql\\execution\\execute.js:556:21)",
            "    at C:\\code\\neo4j\\graphql\\node_modules\\graphql\\execution\\execute.js:620:25"
          ]
        }
      }
    }
  ],
  "data": null
}

@litewarp
Copy link
Contributor Author

litewarp commented Jul 2, 2021

You need to add properties to the relationship. I was actually going to raise this in another PR but the library doesn't create a connection unless there are properties on the relationship.

@danstarns
Copy link
Contributor

You need to add properties to the relationship. I was actually going to raise this in another PR but the library doesn't create a connection unless there are properties on the relationship.

I'm not sure about this, seeming that most of our users are currently not using relationship properties this would mean they couldn't use the cursor. Is this something that can be resolved ? and if so what do you propose?

@darrellwarde
Copy link
Contributor

You need to add properties to the relationship. I was actually going to raise this in another PR but the library doesn't create a connection unless there are properties on the relationship.

I think this was done to minimise the size of the schema, because before this PR there was literally zero value in having the connection types unless relationship properties were defined, but that's obviously all changed now! So we can either do that here, or do it afterwards - my gut says afterwards so that we can get this merged.

Copy link
Contributor

@danstarns danstarns left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice contribution 🍺

@darrellwarde darrellwarde merged commit 1b2af05 into neo4j:2.0.0 Jul 2, 2021
@darrellwarde darrellwarde mentioned this pull request Jul 12, 2021
6 tasks
darrellwarde added a commit that referenced this pull request Aug 10, 2021
* Relationship properties - connection fields with filtering and sorting (#205)

* Schema generation and Cypher translation for basic relationship property queries using GraphQL cursor connections

Somewhat TCK tested, but still requires integration tests

* Connection fields now returned for both queries and mutations

An array of new TCK tests validating the new filtering code and projections of connections

* Relationship Properties Union Support (#215)

* Schema generation and Cypher translation for basic relationship property queries using GraphQL cursor connections

Somewhat TCK tested, but still requires integration tests

* Connection fields now returned for both queries and mutations

An array of new TCK tests validating the new filtering code and projections of connections

* Union support

* Few loose ends for unions with relationship properties (#218)

* Feat/relationship-properties-create (#219)

* test: add inital for creating rel properties

* feat: add inital for creating rel properties

* feat: get unions working with nested create

* test: fix ogm tests to include nested create changes

* Relationship property update operations (#222)

* Schema generation and Cypher translation for basic relationship property queries using GraphQL cursor connections

Somewhat TCK tested, but still requires integration tests

* Connection fields now returned for both queries and mutations

An array of new TCK tests validating the new filtering code and projections of connections

* Union support

* A couple of loose ends for unions - __resolveType and filtering

* Merging 2.0.0 branch is for some reason reverting some of my changes, trying to fix

* Make breaking schema changes and fix tests

* Update relationship properties, validated by TCK tests

* Integration tests for update operations

* Feat/relationship-properties-connect (#224)

* test: add cases for connecting with rel properties

* feat: add logic for connecting with rel properties

* fix: change properties set to use the new appointed name

* refactor: only add update with when needed

* test: update all breaking tests due to changes in rel properties connect

* feat: add union connect support

* test: union connect support

* Feat/composite-where-on-delete-and-disconnect (#239)

* test: add composite where without unions and auth

Co-authored-by: Darrell Warde <darrellwarde@users.noreply.github.com>

* feat: added union support for composite where

Co-authored-by: Darrell Warde <darrellwarde@users.noreply.github.com>

* config: add husky back

Co-authored-by: Darrell Warde <darrellwarde@users.noreply.github.com>

* Fix bug in code merged in from master

* Update version and mark prerelease

* Bring 2.0.0 in line with master (#250)

* Update neo-push-server to enforce nodemon uses local ts-node install
(force rerun cla check)

* Fix typos

* refactor: add more debug logs for get jwt

Co-authored-by: Evan Reed <evan@evdev.co>
Co-authored-by: Matt Murphy <63432827+mattmurph9@users.noreply.github.com>
Co-authored-by: Daniel Starns <danielstarns@hotmail.com>

* Documentation for 2.0.0 (#242)

* Beginning of documentation for relationship properties

* Basic migration guide (navigation a little broken)

* Continued work on 2.0.0 docs

* Fixed headers not working for new pages (page keys cannot begin with a number)

* Remove node from where clause of connect

* A couple of outstanding documentation tasks

* Highlight that req must be passed into context, add lambda edge case

* Clarify Point and CartesianPoint usage in docs

* Relationship propery enum support

* Missing copyright headers

* Point to prerelease documentation for 2.0.0 branch

* General housekeeping before release

* Update code comment

* General 2.0.0 housekeeping (#255)

* Missing copyright headers

* Point to prerelease documentation for 2.0.0 branch

* General housekeeping before release

* Update code comment

* Fix TCK tests broken from merge

* Bring 2.0.0 in line with master (#264)

* Missing copyright headers

* Point to prerelease documentation for 2.0.0 branch

* General housekeeping before release

* Fixed nullability of Query return type

* Update code comment

* refactor: remove neoSchema from OGM properties (#256)

* feat: add cypherParams (#254)

* Use upperFirst from graphql-compose in all cases (#262)

* Remove upper-case-first and our own util function from @neo4j/graphql - use upperFirst from graphql-compose

* Re-export graphql-compose upperFirst from @neo4j/graphql for use in @neo4j/graphql-ogm, remove upper-case-first dependency

* Fix TCK tests broken from merge

Co-authored-by: Daniel Starns <danielstarns@hotmail.com>

* Version update

* Update index.adoc

Fix broken link

* Update relationships.adoc

Fix typo, relationship properties type should be interface

* Update filtering.adoc

Add missing word, and change phrasing

* Add scalars earlier in schema augmentation for use in types and interfaces without throwing Error (fixes DateTime relationship properties)

* Changes to accomodate merge from master

* Add scalars earlier to fix DateTime relationship properties, and merge changes from master (#272)

* Potential fix for the problem serializing Int/Float values

* Fix bug in previous bugfix code related to this fix

* Missing copyright headers

* Point to prerelease documentation for 2.0.0 branch

* General housekeeping before release

* Fixed nullability of Query return type

* Update code comment

* refactor: remove neoSchema from OGM properties (#256)

* feat: add cypherParams (#254)

* Quick fix for custom type resolvers on unions. Prevents generated resolvers from being overwritten with __resolveType.

* Use upperFirst from graphql-compose in all cases (#262)

* Remove upper-case-first and our own util function from @neo4j/graphql - use upperFirst from graphql-compose

* Re-export graphql-compose upperFirst from @neo4j/graphql for use in @neo4j/graphql-ogm, remove upper-case-first dependency

* Fix TCK tests broken from merge

* update: documentation

* Update filtering.adoc

Add missing word and change phrasing

* Add scalars earlier in schema augmentation for use in types and interfaces without throwing Error (fixes DateTime relationship properties)

* Changes to accomodate merge from master

Co-authored-by: Daniel Starns <danielstarns@hotmail.com>
Co-authored-by: Dan Gerard <dan@dangerard.com>
Co-authored-by: dmoree <dmoree@gmail.com>

* Version update

* Fix exact match when checking for existing scalars

“Date” would otherwise match “scalar DateTime”.

* Add Date type and map it to Neo4j Date

* Fix for projecting connection fields from relationship fields (#284)

* Missing copyright headers

* Point to prerelease documentation for 2.0.0 branch

* General housekeeping before release

* Update code comment

* Fix TCK tests broken from merge

* Add scalars earlier in schema augmentation for use in types and interfaces without throwing Error (fixes DateTime relationship properties)

* Changes to accomodate merge from master

* Fix projecting connection field from a relationship field

* Feat/Connection Auth (#286)

* test: add coverage for connections auth

* feat: add connections auth

* test: add coverage for auth where and user where

* Pagination Cursors on Connections (Relay Specification) (#282)

* skip and limit on connections

* add pageinfo and pagecursor definitions

* add totalCount, return connections

* add skip, limit on unions, make all tests pass

* add global node resolution, green on tests

* add copyright header to connection.ts

* minor cleanup

* cleanup

* remove before/last arguments; move pagination arguments into options

* use one consistent node interface definition

* remove cursor Scalar

* use isInt on totalCount check in make-augmented-schema connection resolver

* remove redundant arraySlice check in createConnectionWithEdge properties

* remove Node global resolution from this pr

* remove erroneous yalc stuff, formatting cleanup

* hoist connection args to field level, fix tests from merge, simplify connection cursor function

* integration test for pagination, fix skipLimitStr

* add pagination helper tests, fix off-by-one error in cursor calculation

* remove erroneous console

* move pagination tests

* Add union relationship where (#291)

* Missing copyright headers

* Point to prerelease documentation for 2.0.0 branch

* General housekeeping before release

* Update code comment

* Fix TCK tests broken from merge

* Add scalars earlier in schema augmentation for use in types and interfaces without throwing Error (fixes DateTime relationship properties)

* Changes to accomodate merge from master

* Add top-level where for union relationship fields

* Add "node" level to connect where (#290)

* Missing copyright headers

* Point to prerelease documentation for 2.0.0 branch

* General housekeeping before release

* Update code comment

* Fix TCK tests broken from merge

* Add scalars earlier in schema augmentation for use in types and interfaces without throwing Error (fixes DateTime relationship properties)

* Changes to accomodate merge from master

* Remove seemingly redundant input type

* Add "node level" to connect where

* Update other tests, and documentation

* Only return union members which have fragments in the selection set (#289)

* Missing copyright headers

* Point to prerelease documentation for 2.0.0 branch

* General housekeeping before release

* Update code comment

* Fix TCK tests broken from merge

* Add scalars earlier in schema augmentation for use in types and interfaces without throwing Error (fixes DateTime relationship properties)

* Changes to accomodate merge from master

* Only return union members of which a fragment is present in the selection set

* Fix test broken from merge

* Refactor/rename skip to offset (#294)

* Missing copyright headers

* Point to prerelease documentation for 2.0.0 branch

* General housekeeping before release

* Update code comment

* Fix TCK tests broken from merge

* Add scalars earlier in schema augmentation for use in types and interfaces without throwing Error (fixes DateTime relationship properties)

* Changes to accomodate merge from master

* Rename skip to offset

* Nested update argument change (#295)

* Missing copyright headers

* Point to prerelease documentation for 2.0.0 branch

* General housekeeping before release

* Update code comment

* Fix TCK tests broken from merge

* Add scalars earlier in schema augmentation for use in types and interfaces without throwing Error (fixes DateTime relationship properties)

* Changes to accomodate merge from master

* Update structure of nested updates

* Update documentation with new update structure

* Merge most recent changes from master into 2.0.0 (#306)

* Missing copyright headers

* Point to prerelease documentation for 2.0.0 branch

* General housekeeping before release

* Update code comment

* Fix TCK tests broken from merge

* fix(jwt): req.cookies might be undefined

this fix prevents the app from crashing id req.cookies is undefined

* Add scalars earlier in schema augmentation for use in types and interfaces without throwing Error (fixes DateTime relationship properties)

* Changes to accomodate merge from master

* fix: use package json for useragent name and version (#271)

* fix: use package json for useragent name and version

* fix: add userAgent support for <=4.2 and >=4.3 drivers

* config: remove codeowners (#277)

* Version update

* fix(login): avoid confusion caused by secondary button (#265)

* fix: losing params while creating Auth Predicate (#281)

* fix: loosing params while creating Auth Predicate

* fix: typos

* fix: typo

* feat: add projection to top level cypher directive (#251)

* feat: add projection to top level queries and mutations using cypher directive

* fix: add missing cypherParams

* Fix for loss of scalar and field level resolvers (#297)

* wrapCustomResolvers removed in favour of schema level resolver auth injection

* Add test cases for this fix

* Mention double escaping for @cypher directive

* Version update

Co-authored-by: gaspard <gaspard@gmail.com>
Co-authored-by: Oskar Hane <oh@oskarhane.com>
Co-authored-by: Daniel Starns <danielstarns@hotmail.com>
Co-authored-by: Neo Technology Build Agent <continuous-integration+build-agent@neotechnology.com>
Co-authored-by: Arnaud Gissinger <37625778+mathix420@users.noreply.github.com>

* Refactor/union arguments (#304)

* Missing copyright headers

* Point to prerelease documentation for 2.0.0 branch

* General housekeeping before release

* Update code comment

* Fix TCK tests broken from merge

* fix(jwt): req.cookies might be undefined

this fix prevents the app from crashing id req.cookies is undefined

* Add scalars earlier in schema augmentation for use in types and interfaces without throwing Error (fixes DateTime relationship properties)

* Changes to accomodate merge from master

* fix: use package json for useragent name and version (#271)

* fix: use package json for useragent name and version

* fix: add userAgent support for <=4.2 and >=4.3 drivers

* config: remove codeowners (#277)

* Version update

* fix(login): avoid confusion caused by secondary button (#265)

* fix: losing params while creating Auth Predicate (#281)

* fix: loosing params while creating Auth Predicate

* fix: typos

* fix: typo

* feat: add projection to top level cypher directive (#251)

* feat: add projection to top level queries and mutations using cypher directive

* fix: add missing cypherParams

* Fix for loss of scalar and field level resolvers (#297)

* wrapCustomResolvers removed in favour of schema level resolver auth injection

* Add test cases for this fix

* Mention double escaping for @cypher directive

* Version update

* checkpoint: commit all changes to date - NOT WORKING

* Committing before merging in 2.0.0 changes

* Union connect and test needs fixing

* Add .huskyrc back

* Reformat schema TCK tests for better diff

* Reorganise schema TCK for better diff

* Create union input types in a map

* Various work, including nested connects and disconnects for unions, fixing a variety of bugs

* Documentation changes

* Fix structure of nested creates for unions, and add tests for nested union mutations

* Fix where input for nested update

* Add integration tests for multiple union create/update

Co-authored-by: gaspard <gaspard@gmail.com>
Co-authored-by: Oskar Hane <oh@oskarhane.com>
Co-authored-by: Daniel Starns <danielstarns@hotmail.com>
Co-authored-by: Neo Technology Build Agent <continuous-integration+build-agent@neotechnology.com>
Co-authored-by: Arnaud Gissinger <37625778+mathix420@users.noreply.github.com>

* Merge changes from master into 2.0.0 (#309)

* Missing copyright headers

* Point to prerelease documentation for 2.0.0 branch

* General housekeeping before release

* Update code comment

* Fix TCK tests broken from merge

* fix(jwt): req.cookies might be undefined

this fix prevents the app from crashing id req.cookies is undefined

* Add scalars earlier in schema augmentation for use in types and interfaces without throwing Error (fixes DateTime relationship properties)

* Changes to accomodate merge from master

* fix: use package json for useragent name and version (#271)

* fix: use package json for useragent name and version

* fix: add userAgent support for <=4.2 and >=4.3 drivers

* config: remove codeowners (#277)

* Version update

* fix(login): avoid confusion caused by secondary button (#265)

* fix: losing params while creating Auth Predicate (#281)

* fix: loosing params while creating Auth Predicate

* fix: typos

* fix: typo

* feat: add projection to top level cypher directive (#251)

* feat: add projection to top level queries and mutations using cypher directive

* fix: add missing cypherParams

* Fix for loss of scalar and field level resolvers (#297)

* wrapCustomResolvers removed in favour of schema level resolver auth injection

* Add test cases for this fix

* Mention double escaping for @cypher directive

* Version update

* Allows users to pass in decoded JWT (#303)

* Allows users to pass in decoded JWT - needs more testing

* More tests for decoded JWTs

* Updates to auth documentation

* Fix relationships documentation examples (#296)

* Version update

Co-authored-by: gaspard <gaspard@gmail.com>
Co-authored-by: Oskar Hane <oh@oskarhane.com>
Co-authored-by: Daniel Starns <danielstarns@hotmail.com>
Co-authored-by: Neo Technology Build Agent <continuous-integration+build-agent@neotechnology.com>
Co-authored-by: Arnaud Gissinger <37625778+mathix420@users.noreply.github.com>

* Selectively project union members

* Replace instances of "properties" with "relationship"

* Fix errors when no sorting available on related nodes

* Add tests for #288 which previously didn't work due to this bug

* Fixed tests broken after merge

* Merge 1.2.1 changes from master into 2.0.0 (#319)

* Fix for bug, caused by returning a union

* Docs media (#310)

* config: remove codeowners

* docs: add some media links

* docs: change links to list

* Update README.md

Capitalise NODES

* docs: add wills talk to list

Co-authored-by: Darrell Warde <8117355+darrellwarde@users.noreply.github.com>

* Version update

* Fixed tests broken after merge

Co-authored-by: Daniel Starns <danielstarns@hotmail.com>
Co-authored-by: Neo Technology Build Agent <continuous-integration+build-agent@neotechnology.com>

* refactor: change union where on connections (#317)

* refactor: change union where on connections

* Merge changes from 2.0.0 into union-where

* test: add coverage for using relationship on union where

* refactor: remove temp file

* test: format and add relationship and node coverage

* Jwt type (#321)

* config: remove codeowners

* refactor: type change to boolean

* Refactor/tck test formatting (#323)

* Fix for bug, caused by returning a union

* Docs media (#310)

* config: remove codeowners

* docs: add some media links

* docs: change links to list

* Update README.md

Capitalise NODES

* docs: add wills talk to list

Co-authored-by: Darrell Warde <8117355+darrellwarde@users.noreply.github.com>

* Version update

* Fixed tests broken after merge

* Refactor headings and add markdownlint config to allow nested heading re-use

* Use code block tags which allow formatting

* Replace ```schema with ```graphql

* Slight markdownlint config tweak

* Merge branch '2.0.0' into refactor/tck-test-formatting

Co-authored-by: Daniel Starns <danielstarns@hotmail.com>
Co-authored-by: Neo Technology Build Agent <continuous-integration+build-agent@neotechnology.com>

* Version update

* Add Connection where field to node where types

Co-authored-by: Daniel Starns <danielstarns@hotmail.com>

* Added more test cases

* Ensure that all combinations of connection projections work without error

* Remove commented code

* Make startCursor and endCursor nullable

* fix: relationship cypher params added for create

* update: integration test for update -> create

* fix: use correct property for proper translation

* update: integration test for update -> update

* fix: formatting

* Feat/Count queries (#329)

* test: add init coverage for count

* feat: add count queries

* test: changes to existing for count queries

* docs: add count queries

* docs: remove misleading comment on count

* refactor: change to xCount over countX

* feat: add count to ogm

* Align naming of "issue tests"

* Version update

* Manually add schemaDirectives after resolvers

* Add missing copyright header

* Remove leftover comment, add some explanation to order

* A new approach for deciding which union members to return!

* Validation of Type Definitions (#300)

* docs: add aura flag apoc

* fix: temporarily disable validateTypeDefs

Co-authored-by: Darrell Warde <darrellwarde@users.noreply.github.com>

* docs: duplicate doc text

* docs: remove auth aura flag

* docs: add license to docs and readmes

* docs: wrong licence link

* fix: validate document

* refactor: remove compose from validate document

* test: add the correct issue test cases

* refactor: remove checkNodeImplementsInterfaces

* test: add case for github issue

* Working solution for type definition validation

* Allow for skipping of validation for some edge cases such as using our internally generated types

* Add tests that demonstrate errors will be thrown if using "protected" types

* Filter out internel input type names during validation so that they can be used without error

* Add test to demonstrate that directives cannot be redefined

* Make suggested changes from PR

Co-authored-by: Daniel Starns <danielstarns@hotmail.com>
Co-authored-by: Darrell Warde <darrellwarde@users.noreply.github.com>

* Remove redundant comments

* Rename points.md to point.md

* Add missing types to where for relationship properties

* Add missing Date filters

* Test that Date and Boolean relationship property filters added to schema

* Added Cypher TCK test for filtering by relationship property temporal values

* Allow OGM selectionSet to be SelectionSetNode

* Dependency patch upgrades

* Upgrade graphql-compose to 8.1.0

* graphql-compose to 9.x and fix results of breaking changes

* Fix/issue 369 (#370)

* fix: issue #369 connections using cypher

* test: coverage for issue #369

* Alias connections (#368)

* fix: alias connections

* test: alias connections

* refactor: change to source and info

* test: add a case with many alias

* 2.0.0 documentation updates (#366)

* Docs changes

* Add unions page back to migration guide

* Document union where changes in migration guide

* Move custom resolvers page down

* Ensure contents in type definitions map to underlying pages

* Documentation changes from editorial comments, aligning frontpage with other products

* Missing summaries in contents

* Restructure following editorial comments

* Split out each Mutation operation into separate chapters

* Rewrite of getting started guide, with more examples and screenshots

* Add type definitions basics page

* Add documentation for all GraphQL types

* Fix order of type definitions pages

* Rewrite introduction page with features, interacting and deployment section

* Change documentation for interfaces, highlighting that they are used for relationship properties

* Fix references to pagination

* Continued rewriting and restructuring

* Rework auth content

* Overhaul API references for both Neo4jGraphQL and OGM

* Changes reflecting @danstarns comments

* Version update

* Remove duplicate sentence

* Fix OGM contents

* Remove ; and &

* Filter out nested input types during validation

* Change minimum database version to 4.1.5

* Fix validation of database versions using semver package

* Don't list temporal and spatial types on filtering page - could fall out of date

* Error auth relationship properties (#379)

* feat: throw error when auth directive is used on relationship props

* test: when auth directive is used on relationship props

* Add a simple util file which can be called with ts-node to clear down database before/after running integration tests

* Add comment explaining teardown file

* Error relationship on relationship properties (#381)

* feat: throw error when relationship directive is used on relationship props

* test: when relationship directive is used on relationship props

* Coerce Aura database version numbers

* Refactor/unify relationship fields (#383)

* feat: throw error when relationship directive is used on relationship props

* test: when relationship directive is used on relationship props

* refactor: unify relationship properties fields and reuse existing functions

* test: add for cypher on interface

* Rough find/replace attempt at passing last bookmark into GraphQL execution

* Treat custom scalars, enums and primitives the same for custom Cypher fields

* Also fix custom scalars for Query-level custom Cypher

* Style guidance - remove instances of "whilst"

* Remove "Step x" from Getting Started, change to second person

* Attempt to change all wording to second person

* refactor: change schema references from relationship to edge (#389)

* refactor: change schema references from relationship to edge

* docs: add note about relationship and edges

* Update relationships.adoc

Rephrase sentence to be passive

* feat: export auth errors from index (#394)

* Reserved properties (#396)

* feat: throw error when using reserved names

* test: error when using reserved names

* docs: remove useage of Node type

* refactor: changes from PR comments

* Version update

* Fix multiple connections being returned from custom Cypher

* Remove _IN and _NOT_IN filters for relationships

* Remove translation for surplus _IN and _NOT_IN

* Remove prerelease marker

* refactor: use alias for params and name for fields

* add: int test for nested connections and aliasing

* add: tck test for multiple aliasing on connections

Co-authored-by: Daniel Starns <danielstarns@hotmail.com>
Co-authored-by: Darrell Warde <darrellwarde@users.noreply.github.com>
Co-authored-by: Neil Dewhurst <neil.dewhurst@neo4j.com>
Co-authored-by: Evan Reed <evan@evdev.co>
Co-authored-by: Matt Murphy <63432827+mattmurph9@users.noreply.github.com>
Co-authored-by: Neo Technology Build Agent <continuous-integration+build-agent@neotechnology.com>
Co-authored-by: Dan Gerard <dan@dangerard.com>
Co-authored-by: dmoree <dmoree@gmail.com>
Co-authored-by: Oskar Hane <oh@oskarhane.com>
Co-authored-by: nsethi <nicholas.sethi@gmail.com>
Co-authored-by: gaspard <gaspard@gmail.com>
Co-authored-by: Arnaud Gissinger <37625778+mathix420@users.noreply.github.com>
Co-authored-by: dmoree <dmoree@users.noreply.github.com>
Co-authored-by: Neo Technology Build Agent <continuous-integration+build-agent@neo4j.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants