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

[Feature Branch] Aggregation 7 #6011

Draft
wants to merge 41 commits into
base: 7.x
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
c340f32
Add aggregation fields inside connection
angrykoala Jan 17, 2025
484c061
Fix aggregation aliases
angrykoala Jan 20, 2025
6cc7a09
update top level aggregation tests
angrykoala Jan 20, 2025
ef2d979
Add interface aggregations on top level
angrykoala Jan 21, 2025
c3e3416
Update tck tests with aggregate
angrykoala Jan 21, 2025
4e8ab68
Deprecate top level aggregation
angrykoala Jan 21, 2025
233dc74
Fix unit tests
angrykoala Jan 21, 2025
a6e9486
Add deprecation flag
angrykoala Jan 22, 2025
f0cc167
Cleanup of aggregations inside connections code
angrykoala Jan 22, 2025
5d36415
Test multiple aliased aggregations in the same connection
angrykoala Jan 22, 2025
2cb4148
Merge pull request #5944 from neo4j/aggregation-connections
angrykoala Jan 23, 2025
922f788
Merge branch 'dev' into aggregation-6
angrykoala Jan 24, 2025
f32e374
Merge branch 'dev' into aggregation-6
angrykoala Jan 27, 2025
b5510f0
Merge remote-tracking branch 'upstream/aggregation-6' into aggregation-7
MacondoExpress Jan 28, 2025
00e3293
initial implementation
MacondoExpress Jan 30, 2025
6a5498d
wip, remove union from be generated as aggregation filters, update sc…
MacondoExpress Jan 30, 2025
953fd65
wip add first integration test
MacondoExpress Jan 30, 2025
a22b8f7
update aggregation/node tests to use aggregation filters inside conne…
MacondoExpress Jan 31, 2025
11fbf54
update aggregation/where/edge tests to use aggregation filters inside…
MacondoExpress Jan 31, 2025
13ec601
update tests to use new aggregate/generic operator syntax
MacondoExpress Jan 31, 2025
9ca08fc
refactor test count.int.test.ts and separate count-interface suite to…
MacondoExpress Feb 3, 2025
034b1fa
improve aggregation/top-level tests batch(1)
MacondoExpress Feb 5, 2025
1f2e47a
improve aggregation/top-level tests batch(2)
MacondoExpress Feb 5, 2025
af5b66e
add authorization filter test, for new aggregation
MacondoExpress Feb 5, 2025
3362063
add test coverage for authorization with aggregation rules and nested…
MacondoExpress Feb 6, 2025
dc8be5a
Merge pull request #5994 from MacondoExpress/aggregation-filters-insi…
MacondoExpress Feb 6, 2025
e382d3b
added schema changes for aggregation count filters
MacondoExpress Feb 11, 2025
271a0a3
merge aggregation-6-into-aggregation-7
MacondoExpress Feb 11, 2025
3470dea
fix relationship adapter unit test
MacondoExpress Feb 11, 2025
09fe679
Merge pull request #6000 from MacondoExpress/merge-aggregation-6-into…
MacondoExpress Feb 11, 2025
9551284
update tests to support count nodes syntax
MacondoExpress Feb 11, 2025
d3fb0a9
update aggregation/tests to use the new count syntax
MacondoExpress Feb 12, 2025
e6bb032
fix old aggregate filtering syntax, add tests for it
MacondoExpress Feb 13, 2025
16e471d
implement and test aggregation count for edges, fixed count for nodes…
MacondoExpress Feb 14, 2025
4b1fbee
add .int suffix to count-edges.test.ts
MacondoExpress Feb 14, 2025
1a56515
add count-edges tck test
MacondoExpress Feb 14, 2025
55c897f
improve coverage over edges and distinct count
MacondoExpress Feb 14, 2025
5667e6c
decouple count distinct fix
MacondoExpress Feb 18, 2025
de3ef63
update schema tests
MacondoExpress Feb 18, 2025
704ac20
Merge branch 'aggregation-7' into aggregation-filters-count
MacondoExpress Feb 18, 2025
7a40949
Merge pull request #6004 from MacondoExpress/aggregation-filters-count
MacondoExpress Feb 18, 2025
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
20 changes: 20 additions & 0 deletions .changeset/hot-windows-whisper.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
"@neo4j/graphql": minor
---

Add aggregate fieldd in connection:

```graphql
query {
moviesConnection {
aggregate {
node {
count
int {
longest
}
}
}
}
}
```
5 changes: 5 additions & 0 deletions .changeset/sixty-steaks-reflect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@neo4j/graphql": patch
---

Deprecate aggrgation fields (e.g `actedInAggregate`) in favor of the field `aggregate` inside the connection (e.g `actedInConnection -> aggregate`)
22 changes: 22 additions & 0 deletions .changeset/soft-socks-count.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
"@neo4j/graphql": patch
---

Add `addVersionPrefix` to `cypherQueryOptions` in context to add a Cypher version with `CYPHER` before each query:

```js
{
cypherQueryOptions: {
addVersionPrefix: true,
},
}
```

This prepends all Cypher queries with a `CYPHER [version]` statement:

```cypher
CYPHER 5
MATCH (this:Movie)
WHERE this.title = $param0
RETURN this { .title } AS this
```
25 changes: 25 additions & 0 deletions .changeset/thin-goats-begin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
"@neo4j/graphql": patch
---

Deprecated old aggregate operations:

```graphql
query {
moviesAggregate {
count
rating {
min
}
}
}
```

These fields can be completely removed from the schema with the new flag `deprecatedAggregateOperations`:

```js
const neoSchema = new Neo4jGraphQL({
typeDefs,
features: { excludeDeprecatedFields: { deprecatedAggregateOperations: true } },
});
```
2 changes: 1 addition & 1 deletion .github/workflows/changesets.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
persist-credentials: false

- name: Setup Node.js
uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4
uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4
with:
node-version: lts/*

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/cla-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
with:
repository: neo-technology/whitelist-check
token: ${{ secrets.NEO4J_TEAM_GRAPHQL_PERSONAL_ACCESS_TOKEN }}
- uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5
- uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5
with:
python-version: 3
- name: Install dependencies
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/lint-markdown.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:

steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4
with:
node-version: lts/*
- name: Install markdownlint
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/performance-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:

steps:
- name: Setup Node.js
uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4
uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4
with:
node-version: lts/*

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/pull-requests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:

steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4
with:
node-version: 18.13.0
cache: yarn
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/reusable-api-library-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ jobs:

steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4
with:
node-version: lts/*
cache: yarn
Expand Down Expand Up @@ -68,7 +68,7 @@ jobs:

steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4
with:
node-version: lts/*
cache: yarn
Expand All @@ -82,7 +82,7 @@ jobs:

steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4
with:
node-version: lts/*
cache: yarn
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/reusable-aura-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
with:
ref: ${{ inputs.BRANCH || github.ref }}
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4
with:
node-version: lts/*
cache: yarn
Expand Down Expand Up @@ -62,7 +62,7 @@ jobs:
steps:
- name: Check out repository code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4
with:
node-version: lts/*
cache: yarn
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/reusable-codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ jobs:

steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4
with:
node-version: lts/*
- name: Initialize CodeQL
uses: github/codeql-action/init@f6091c0113d1dcf9b98e269ee48e8a7e51b7bdd4 # v3
uses: github/codeql-action/init@dd746615b3b9d728a6a37ca2045b68ca76d4841a # v3
with:
config-file: ./.github/codeql/codeql-config.yml
languages: javascript
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@f6091c0113d1dcf9b98e269ee48e8a7e51b7bdd4 # v3
uses: github/codeql-action/analyze@dd746615b3b9d728a6a37ca2045b68ca76d4841a # v3
2 changes: 1 addition & 1 deletion .github/workflows/reusable-federation-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
steps:
- name: Check out repository code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4
with:
node-version: lts/*
cache: yarn
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ jobs:
- name: Check out repository code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- name: Setting up Node.js with version ${{ matrix.node.name }}
uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4
uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4
with:
node-version: ${{ matrix.node.name }}
cache: yarn
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/reusable-integration-tests-on-prem.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ jobs:
steps:
- name: Check out repository code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4
with:
node-version: lts/*
cache: yarn
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/reusable-package-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ jobs:

steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4
with:
node-version: 18.13.0
cache: yarn
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/reusable-unit-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:

steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4
with:
node-version: lts/*
cache: yarn
Expand Down
4 changes: 2 additions & 2 deletions packages/graphql/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
"koa-jwt": "4.0.4",
"koa-router": "13.0.1",
"mock-jwks": "1.0.10",
"nock": "13.5.6",
"nock": "14.0.0",
"randomstring": "1.3.1",
"rimraf": "6.0.1",
"supertest": "7.0.0",
Expand All @@ -79,7 +79,7 @@
"@graphql-tools/resolvers-composition": "^7.0.0",
"@graphql-tools/schema": "^10.0.0",
"@graphql-tools/utils": "10.6.1",
"@neo4j/cypher-builder": "2.2.1",
"@neo4j/cypher-builder": "2.3.0",
"camelcase": "^6.3.0",
"debug": "^4.3.4",
"dot-prop": "^6.0.1",
Expand Down
38 changes: 29 additions & 9 deletions packages/graphql/src/classes/Executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import {
} from "../constants";
import { debugCypherAndParams } from "../debug/debug-cypher-and-params";
import type { CypherQueryOptions } from "../types";
import { isInArray } from "../utils/is-in-array";
import {
Neo4jGraphQLAuthenticationError,
Neo4jGraphQLConstraintValidationError,
Expand All @@ -49,6 +50,8 @@ import {

const debug = Debug(DEBUG_EXECUTE);

const SUPPORTED_CYPHER_VERSION = "5";

interface DriverLike {
session(config);
}
Expand Down Expand Up @@ -107,7 +110,6 @@ export class Executor {
}: ExecutorConstructorParam) {
this.executionContext = executionContext;
this.cypherQueryOptions = cypherQueryOptions;
this.cypherQueryOptions = cypherQueryOptions;
this.sessionConfig = sessionConfig;
this.cypherParams = cypherParams;
this.transactionMetadata = transactionMetadata;
Expand Down Expand Up @@ -173,16 +175,34 @@ export class Executor {
return error;
}

private generateQuery(query: string): string {
if (this.cypherQueryOptions && Object.keys(this.cypherQueryOptions).length) {
const cypherQueryOptions = `CYPHER ${Object.entries(this.cypherQueryOptions)
.map(([key, value]) => `${key}=${value}`)
.join(" ")}`;
private addCypherOptionsToQuery(query: string): string {
const cypherVersion = this.getCypherVersionStatement();

const cypherQueryOptions = this.getCypherQueryOptionsStatement();

return `${cypherVersion}${cypherQueryOptions}${query}`;
}

return `${cypherQueryOptions}\n${query}`;
private getCypherVersionStatement(): string {
if (this.cypherQueryOptions?.addVersionPrefix) {
return `CYPHER ${SUPPORTED_CYPHER_VERSION}\n`;
}
return "";
}

return query;
private getCypherQueryOptionsStatement(): string {
const ignoredCypherQueryOptions: Array<keyof CypherQueryOptions> = ["addVersionPrefix"];
const cypherQueryOptions = Object.entries(this.cypherQueryOptions ?? []).filter(([key, _value]) => {
return !isInArray(ignoredCypherQueryOptions, key);
});
if (cypherQueryOptions.length) {
return `CYPHER ${cypherQueryOptions
.map(([key, value]) => {
return `${key}=${value}`;
})
.join(" ")}\n`;
}
return "";
}

private getTransactionConfig(info?: GraphQLResolveInfo): TransactionConfig {
Expand Down Expand Up @@ -276,7 +296,7 @@ export class Executor {
parameters: Record<string, any>,
transaction: Transaction | ManagedTransaction
): Result {
const queryToRun = this.generateQuery(query);
const queryToRun = this.addCypherOptionsToQuery(query);

debugCypherAndParams(debug, queryToRun, parameters);

Expand Down
2 changes: 1 addition & 1 deletion packages/graphql/src/classes/Neo4jDatabaseInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export class Neo4jDatabaseInfo {
public edition: Neo4jEdition | undefined;

constructor(version: string, edition?: Neo4jEdition) {
// Quick hack to support CalVar
// Quick hack to support CalVer
version = version.replace(/\.0([0-9]+)/, ".$1");
this.version = this.toSemVer(version);
this.rawVersion = version;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright (c) "Neo4j"
* Neo4j Sweden AB [http://neo4j.com]
*
* This file is part of Neo4j.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { GraphQLInputObjectType } from "graphql";
import { IntScalarFilters } from "../generic-operators/IntScalarFilters";

export const ConnectionAggregationCountFilterInput = new GraphQLInputObjectType({
name: "ConnectionAggregationCountFilterInput",
fields: {
nodes: { type: IntScalarFilters },
edges: { type: IntScalarFilters },
},
});
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ export type RootTypeFieldNames = {
type AggregateTypeNames = {
selection: string;
input: string;
connection: string;
node: string;
};

type MutationResponseTypeNames = {
Expand Down Expand Up @@ -148,6 +150,8 @@ export class ImplementingEntityOperations<T extends InterfaceEntityAdapter | Con
return {
selection: `${this.entityAdapter.name}AggregateSelection`,
input: `${this.entityAdapter.name}AggregateSelectionInput`,
connection: `${this.entityAdapter.name}Aggregate`,
node: `${this.entityAdapter.name}AggregateNode`,
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ describe("RelationshipAdapter", () => {

test("should parse selectable", () => {
const relationshipAdapter = userAdapter.relationships.get("accounts");
expect(relationshipAdapter?.isAggregable()).toBeTrue();
expect(relationshipAdapter?.isAggregable()).toBeFalse();
expect(relationshipAdapter?.isReadable()).toBeFalse();
});
});
Loading