mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-14 08:02:15 +03:00
Fix "limit" from permissions being incorrectly applied to aggregates in Data Connectors
[GDC-1064]: https://hasurahq.atlassian.net/browse/GDC-1064?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ PR-URL: https://github.com/hasura/graphql-engine-mono/pull/8345 GitOrigin-RevId: 9ef91944ba6408e1030a47de58f3271145433ee2
This commit is contained in:
parent
6e1ebd6a4b
commit
e9c697aaa9
@ -473,7 +473,125 @@ The rows returned by the query must be put into the `rows` property array in the
|
|||||||
|
|
||||||
#### Pagination
|
#### Pagination
|
||||||
|
|
||||||
If the GraphQL query contains pagination information, then the `limit` and `offset` fields may be set to integer values, indicating the number of rows to return, and the index of the first row to return, respectively.
|
There are three properties that are used to control pagination of queried data:
|
||||||
|
|
||||||
|
* `aggregates_limit`: The maximum number of rows to consider in aggregations calculated and returned in the `aggregrates` property. `aggregates_limit` does not influence the rows returned in the `rows` property. It will only be used if there are aggregates in the query.
|
||||||
|
* `limit`: The maximum number of rows to return from a query in the `rows` property. `limit` does not influence the rows considered by aggregations.
|
||||||
|
* `offset`: The index of the first row to return. This affects the rows returned, and also the rows considered by aggregations.
|
||||||
|
|
||||||
|
`limit` and `aggregates_limit` are set when the user uses a `limit` parameter in their GraphQL query. This restricts the dataset considered when returning rows as well as calculating aggregates.
|
||||||
|
HGE also has a row limit setting in a table's select permissions. This row limit will be used in the `limit` property if it is specified or if it is smaller than the limit specified in the GraphQL query itself.
|
||||||
|
|
||||||
|
To illustrate the difference between `limit` and `aggregates_limit`, consider this GraphQL query, where a row limit of `2` has been placed on the Artist table in its select permissions.
|
||||||
|
|
||||||
|
```graphql
|
||||||
|
query ArtistsQuery {
|
||||||
|
Artist_aggregate {
|
||||||
|
aggregate {
|
||||||
|
count
|
||||||
|
}
|
||||||
|
nodes {
|
||||||
|
Name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This would produce the following agent query request JSON:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"table": ["Artist"],
|
||||||
|
"table_relationships": [],
|
||||||
|
"query": {
|
||||||
|
"aggregates_limit": null,
|
||||||
|
"limit": 2,
|
||||||
|
"offset": null,
|
||||||
|
"aggregates": {
|
||||||
|
"aggregate_count": {
|
||||||
|
"type": "star_count"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fields": {
|
||||||
|
"nodes_Name": {
|
||||||
|
"type": "column",
|
||||||
|
"column": "Name",
|
||||||
|
"column_type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The expected response to that query request would be the following JSON. Note that the row count has counted all rows (since `aggregates_limit` was null), but query has only returned the maximum number of rows as specified by the `limit` property: `2`.
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"aggregates": {
|
||||||
|
"aggregate_count": 275
|
||||||
|
},
|
||||||
|
"rows":[
|
||||||
|
{ "nodes_Name": "AC/DC" },
|
||||||
|
{ "nodes_Name": "Accept" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
By comparison, if we added a limit to our GraphQL query:
|
||||||
|
|
||||||
|
```graphql
|
||||||
|
query ArtistsQuery {
|
||||||
|
Artist_aggregate(limit: 5) {
|
||||||
|
aggregate {
|
||||||
|
count
|
||||||
|
}
|
||||||
|
nodes {
|
||||||
|
Name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This would produce the following agent query request JSON:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"table": ["Artist"],
|
||||||
|
"table_relationships": [],
|
||||||
|
"query": {
|
||||||
|
"aggregates_limit": 5,
|
||||||
|
"limit": 2,
|
||||||
|
"offset": null,
|
||||||
|
"aggregates": {
|
||||||
|
"aggregate_count": {
|
||||||
|
"type": "star_count"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fields": {
|
||||||
|
"nodes_Name": {
|
||||||
|
"type": "column",
|
||||||
|
"column": "Name",
|
||||||
|
"column_type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
We would expect the following result:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"aggregates": {
|
||||||
|
"aggregate_count": 5
|
||||||
|
},
|
||||||
|
"rows":[
|
||||||
|
{ "nodes_Name": "AC/DC" },
|
||||||
|
{ "nodes_Name": "Accept" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that the row count aggregation has been limited to `5` because `aggregates_limit` was `5`, and the rows returned were limited by the value of `limit`: `2`.
|
||||||
|
|
||||||
#### Filters
|
#### Filters
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@hasura/dc-api-types",
|
"name": "@hasura/dc-api-types",
|
||||||
"version": "0.26.0",
|
"version": "0.27.0",
|
||||||
"description": "Hasura GraphQL Engine Data Connector Agent API types",
|
"description": "Hasura GraphQL Engine Data Connector Agent API types",
|
||||||
"author": "Hasura (https://github.com/hasura/graphql-engine)",
|
"author": "Hasura (https://github.com/hasura/graphql-engine)",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
|
@ -1305,6 +1305,13 @@
|
|||||||
"nullable": true,
|
"nullable": true,
|
||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
|
"aggregates_limit": {
|
||||||
|
"description": "Optionally limit the maximum number of rows considered while applying aggregations. This limit does not apply to returned rows.",
|
||||||
|
"maximum": 9223372036854776000,
|
||||||
|
"minimum": -9223372036854776000,
|
||||||
|
"nullable": true,
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
"fields": {
|
"fields": {
|
||||||
"additionalProperties": {
|
"additionalProperties": {
|
||||||
"$ref": "#/components/schemas/Field"
|
"$ref": "#/components/schemas/Field"
|
||||||
@ -1314,14 +1321,14 @@
|
|||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
"limit": {
|
"limit": {
|
||||||
"description": "Optionally limit to N results",
|
"description": "Optionally limit the maximum number of returned rows. This limit does not apply to records considered while apply aggregations.",
|
||||||
"maximum": 9223372036854776000,
|
"maximum": 9223372036854776000,
|
||||||
"minimum": -9223372036854776000,
|
"minimum": -9223372036854776000,
|
||||||
"nullable": true,
|
"nullable": true,
|
||||||
"type": "number"
|
"type": "number"
|
||||||
},
|
},
|
||||||
"offset": {
|
"offset": {
|
||||||
"description": "Optionally offset from the Nth result",
|
"description": "Optionally offset from the Nth result. This applies to both row and aggregation results.",
|
||||||
"maximum": 9223372036854776000,
|
"maximum": 9223372036854776000,
|
||||||
"minimum": -9223372036854776000,
|
"minimum": -9223372036854776000,
|
||||||
"nullable": true,
|
"nullable": true,
|
||||||
|
@ -12,16 +12,20 @@ export type Query = {
|
|||||||
* Aggregate fields of the query
|
* Aggregate fields of the query
|
||||||
*/
|
*/
|
||||||
aggregates?: Record<string, Aggregate> | null;
|
aggregates?: Record<string, Aggregate> | null;
|
||||||
|
/**
|
||||||
|
* Optionally limit the maximum number of rows considered while applying aggregations. This limit does not apply to returned rows.
|
||||||
|
*/
|
||||||
|
aggregates_limit?: number | null;
|
||||||
/**
|
/**
|
||||||
* Fields of the query
|
* Fields of the query
|
||||||
*/
|
*/
|
||||||
fields?: Record<string, Field> | null;
|
fields?: Record<string, Field> | null;
|
||||||
/**
|
/**
|
||||||
* Optionally limit to N results
|
* Optionally limit the maximum number of returned rows. This limit does not apply to records considered while apply aggregations.
|
||||||
*/
|
*/
|
||||||
limit?: number | null;
|
limit?: number | null;
|
||||||
/**
|
/**
|
||||||
* Optionally offset from the Nth result
|
* Optionally offset from the Nth result. This applies to both row and aggregation results.
|
||||||
*/
|
*/
|
||||||
offset?: number | null;
|
offset?: number | null;
|
||||||
order_by?: OrderBy;
|
order_by?: OrderBy;
|
||||||
|
10
dc-agents/package-lock.json
generated
10
dc-agents/package-lock.json
generated
@ -24,7 +24,7 @@
|
|||||||
},
|
},
|
||||||
"dc-api-types": {
|
"dc-api-types": {
|
||||||
"name": "@hasura/dc-api-types",
|
"name": "@hasura/dc-api-types",
|
||||||
"version": "0.26.0",
|
"version": "0.27.0",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tsconfig/node16": "^1.0.3",
|
"@tsconfig/node16": "^1.0.3",
|
||||||
@ -2227,7 +2227,7 @@
|
|||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fastify/cors": "^8.1.0",
|
"@fastify/cors": "^8.1.0",
|
||||||
"@hasura/dc-api-types": "0.26.0",
|
"@hasura/dc-api-types": "0.27.0",
|
||||||
"fastify": "^4.13.0",
|
"fastify": "^4.13.0",
|
||||||
"mathjs": "^11.0.0",
|
"mathjs": "^11.0.0",
|
||||||
"pino-pretty": "^8.0.0",
|
"pino-pretty": "^8.0.0",
|
||||||
@ -2547,7 +2547,7 @@
|
|||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fastify/cors": "^8.1.0",
|
"@fastify/cors": "^8.1.0",
|
||||||
"@hasura/dc-api-types": "0.26.0",
|
"@hasura/dc-api-types": "0.27.0",
|
||||||
"fastify": "^4.13.0",
|
"fastify": "^4.13.0",
|
||||||
"fastify-metrics": "^9.2.1",
|
"fastify-metrics": "^9.2.1",
|
||||||
"nanoid": "^3.3.4",
|
"nanoid": "^3.3.4",
|
||||||
@ -2868,7 +2868,7 @@
|
|||||||
"version": "file:reference",
|
"version": "file:reference",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@fastify/cors": "^8.1.0",
|
"@fastify/cors": "^8.1.0",
|
||||||
"@hasura/dc-api-types": "0.26.0",
|
"@hasura/dc-api-types": "0.27.0",
|
||||||
"@tsconfig/node16": "^1.0.3",
|
"@tsconfig/node16": "^1.0.3",
|
||||||
"@types/node": "^16.11.49",
|
"@types/node": "^16.11.49",
|
||||||
"@types/xml2js": "^0.4.11",
|
"@types/xml2js": "^0.4.11",
|
||||||
@ -3080,7 +3080,7 @@
|
|||||||
"version": "file:sqlite",
|
"version": "file:sqlite",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@fastify/cors": "^8.1.0",
|
"@fastify/cors": "^8.1.0",
|
||||||
"@hasura/dc-api-types": "0.26.0",
|
"@hasura/dc-api-types": "0.27.0",
|
||||||
"@tsconfig/node16": "^1.0.3",
|
"@tsconfig/node16": "^1.0.3",
|
||||||
"@types/node": "^16.11.49",
|
"@types/node": "^16.11.49",
|
||||||
"@types/sqlite3": "^3.1.8",
|
"@types/sqlite3": "^3.1.8",
|
||||||
|
4
dc-agents/reference/package-lock.json
generated
4
dc-agents/reference/package-lock.json
generated
@ -10,7 +10,7 @@
|
|||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fastify/cors": "^8.1.0",
|
"@fastify/cors": "^8.1.0",
|
||||||
"@hasura/dc-api-types": "0.26.0",
|
"@hasura/dc-api-types": "0.27.0",
|
||||||
"fastify": "^4.13.0",
|
"fastify": "^4.13.0",
|
||||||
"mathjs": "^11.0.0",
|
"mathjs": "^11.0.0",
|
||||||
"pino-pretty": "^8.0.0",
|
"pino-pretty": "^8.0.0",
|
||||||
@ -52,7 +52,7 @@
|
|||||||
"integrity": "sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ=="
|
"integrity": "sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ=="
|
||||||
},
|
},
|
||||||
"node_modules/@hasura/dc-api-types": {
|
"node_modules/@hasura/dc-api-types": {
|
||||||
"version": "0.26.0",
|
"version": "0.27.0",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tsconfig/node16": "^1.0.3",
|
"@tsconfig/node16": "^1.0.3",
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fastify/cors": "^8.1.0",
|
"@fastify/cors": "^8.1.0",
|
||||||
"@hasura/dc-api-types": "0.26.0",
|
"@hasura/dc-api-types": "0.27.0",
|
||||||
"fastify": "^4.13.0",
|
"fastify": "^4.13.0",
|
||||||
"mathjs": "^11.0.0",
|
"mathjs": "^11.0.0",
|
||||||
"pino-pretty": "^8.0.0",
|
"pino-pretty": "^8.0.0",
|
||||||
|
@ -578,12 +578,22 @@ export const queryData = (getTable: (tableName: TableName) => Record<string, Raw
|
|||||||
|
|
||||||
const filteredRows = filterIterable(rows, makeFilterPredicate(query.where ?? null, getComparisonColumnValue, performExistsSubquery));
|
const filteredRows = filterIterable(rows, makeFilterPredicate(query.where ?? null, getComparisonColumnValue, performExistsSubquery));
|
||||||
const sortedRows = query.order_by ? sortRows(Array.from(filteredRows), query.order_by, getOrderByElementValue) : filteredRows;
|
const sortedRows = query.order_by ? sortRows(Array.from(filteredRows), query.order_by, getOrderByElementValue) : filteredRows;
|
||||||
const paginatedRows = Array.from(paginateRows(sortedRows, query.offset ?? null, query.limit ?? null));
|
|
||||||
|
// Get the smallest set of rows required _for both_ row results and aggregation result
|
||||||
|
const aggregatesLimit = query.aggregates_limit ?? null;
|
||||||
|
const rowLimit = query.limit ?? null;
|
||||||
|
const largestLimit = aggregatesLimit !== null && rowLimit !== null ? Math.max(aggregatesLimit, rowLimit) : null;
|
||||||
|
const largestPageOfRows = Array.from(paginateRows(sortedRows, query.offset ?? null, largestLimit));
|
||||||
|
|
||||||
|
// Limit the set of input rows to appropriate size for row results and aggregation results
|
||||||
|
const paginatedRows = rowLimit != null ? largestPageOfRows.slice(0, rowLimit) : largestPageOfRows;
|
||||||
|
const paginatedRowsForAggregation = aggregatesLimit != null ? largestPageOfRows.slice(0, aggregatesLimit) : largestPageOfRows;
|
||||||
|
|
||||||
const projectedRows = query.fields
|
const projectedRows = query.fields
|
||||||
? paginatedRows.map(projectRow(query.fields, findRelationship, performNewQuery))
|
? paginatedRows.map(projectRow(query.fields, findRelationship, performNewQuery))
|
||||||
: null;
|
: null;
|
||||||
const calculatedAggregates = query.aggregates
|
const calculatedAggregates = query.aggregates
|
||||||
? calculateAggregates(paginatedRows, query.aggregates)
|
? calculateAggregates(paginatedRowsForAggregation, query.aggregates)
|
||||||
: null;
|
: null;
|
||||||
return {
|
return {
|
||||||
aggregates: calculatedAggregates,
|
aggregates: calculatedAggregates,
|
||||||
|
4
dc-agents/sqlite/package-lock.json
generated
4
dc-agents/sqlite/package-lock.json
generated
@ -10,7 +10,7 @@
|
|||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fastify/cors": "^8.1.0",
|
"@fastify/cors": "^8.1.0",
|
||||||
"@hasura/dc-api-types": "0.26.0",
|
"@hasura/dc-api-types": "0.27.0",
|
||||||
"fastify": "^4.13.0",
|
"fastify": "^4.13.0",
|
||||||
"fastify-metrics": "^9.2.1",
|
"fastify-metrics": "^9.2.1",
|
||||||
"nanoid": "^3.3.4",
|
"nanoid": "^3.3.4",
|
||||||
@ -57,7 +57,7 @@
|
|||||||
"integrity": "sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ=="
|
"integrity": "sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ=="
|
||||||
},
|
},
|
||||||
"node_modules/@hasura/dc-api-types": {
|
"node_modules/@hasura/dc-api-types": {
|
||||||
"version": "0.26.0",
|
"version": "0.27.0",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tsconfig/node16": "^1.0.3",
|
"@tsconfig/node16": "^1.0.3",
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fastify/cors": "^8.1.0",
|
"@fastify/cors": "^8.1.0",
|
||||||
"@hasura/dc-api-types": "0.26.0",
|
"@hasura/dc-api-types": "0.27.0",
|
||||||
"fastify-metrics": "^9.2.1",
|
"fastify-metrics": "^9.2.1",
|
||||||
"fastify": "^4.13.0",
|
"fastify": "^4.13.0",
|
||||||
"nanoid": "^3.3.4",
|
"nanoid": "^3.3.4",
|
||||||
|
@ -23,9 +23,6 @@ import {
|
|||||||
OrderByRelation,
|
OrderByRelation,
|
||||||
OrderByElement,
|
OrderByElement,
|
||||||
OrderByTarget,
|
OrderByTarget,
|
||||||
Query,
|
|
||||||
ColumnFieldValue,
|
|
||||||
NullColumnFieldValue,
|
|
||||||
ScalarValue,
|
ScalarValue,
|
||||||
} from "@hasura/dc-api-types";
|
} from "@hasura/dc-api-types";
|
||||||
import { customAlphabet } from "nanoid";
|
import { customAlphabet } from "nanoid";
|
||||||
@ -335,12 +332,13 @@ function table_query(
|
|||||||
fields: Fields | null,
|
fields: Fields | null,
|
||||||
aggregates: Aggregates | null,
|
aggregates: Aggregates | null,
|
||||||
wWhere: Expression | null,
|
wWhere: Expression | null,
|
||||||
|
aggregatesLimit: number | null,
|
||||||
wLimit: number | null,
|
wLimit: number | null,
|
||||||
wOffset: number | null,
|
wOffset: number | null,
|
||||||
wOrder: OrderBy | null,
|
wOrder: OrderBy | null,
|
||||||
): string {
|
): string {
|
||||||
const tableAlias = generateTableAlias(tableName);
|
const tableAlias = generateTableAlias(tableName);
|
||||||
const aggregateSelect = aggregates ? [aggregates_query(ts, tableName, joinInfo, aggregates, wWhere, wLimit, wOffset, wOrder)] : [];
|
const aggregateSelect = aggregates ? [aggregates_query(ts, tableName, joinInfo, aggregates, wWhere, aggregatesLimit, wOffset, wOrder)] : [];
|
||||||
// The use of the JSON function inside JSON_GROUP_ARRAY is necessary from SQLite 3.39.0 due to breaking changes in
|
// The use of the JSON function inside JSON_GROUP_ARRAY is necessary from SQLite 3.39.0 due to breaking changes in
|
||||||
// SQLite. See https://sqlite.org/forum/forumpost/e3b101fb3234272b for more details. This approach still works fine
|
// SQLite. See https://sqlite.org/forum/forumpost/e3b101fb3234272b for more details. This approach still works fine
|
||||||
// for older versions too.
|
// for older versions too.
|
||||||
@ -374,10 +372,10 @@ function relationship(ts: TableRelationships[], r: Relationship, field: Relation
|
|||||||
|
|
||||||
// We force a limit of 1 for object relationships in case the user has configured a manual
|
// We force a limit of 1 for object relationships in case the user has configured a manual
|
||||||
// "object" relationship that accidentally actually is an array relationship
|
// "object" relationship that accidentally actually is an array relationship
|
||||||
const limit =
|
const [limit, aggregatesLimit] =
|
||||||
r.relationship_type === "object"
|
r.relationship_type === "object"
|
||||||
? 1
|
? [1, 1]
|
||||||
: coerceUndefinedToNull(field.query.limit);
|
: [coerceUndefinedToNull(field.query.limit), coerceUndefinedToNull(field.query.aggregates_limit)];
|
||||||
|
|
||||||
return tag("relationship", table_query(
|
return tag("relationship", table_query(
|
||||||
ts,
|
ts,
|
||||||
@ -386,6 +384,7 @@ function relationship(ts: TableRelationships[], r: Relationship, field: Relation
|
|||||||
coerceUndefinedToNull(field.query.fields),
|
coerceUndefinedToNull(field.query.fields),
|
||||||
coerceUndefinedToNull(field.query.aggregates),
|
coerceUndefinedToNull(field.query.aggregates),
|
||||||
coerceUndefinedToNull(field.query.where),
|
coerceUndefinedToNull(field.query.where),
|
||||||
|
aggregatesLimit,
|
||||||
limit,
|
limit,
|
||||||
coerceUndefinedToNull(field.query.offset),
|
coerceUndefinedToNull(field.query.offset),
|
||||||
coerceUndefinedToNull(field.query.order_by),
|
coerceUndefinedToNull(field.query.order_by),
|
||||||
@ -657,6 +656,7 @@ function query(request: QueryRequest): string {
|
|||||||
coerceUndefinedToNull(request.query.fields),
|
coerceUndefinedToNull(request.query.fields),
|
||||||
coerceUndefinedToNull(request.query.aggregates),
|
coerceUndefinedToNull(request.query.aggregates),
|
||||||
coerceUndefinedToNull(request.query.where),
|
coerceUndefinedToNull(request.query.where),
|
||||||
|
coerceUndefinedToNull(request.query.aggregates_limit),
|
||||||
coerceUndefinedToNull(request.query.limit),
|
coerceUndefinedToNull(request.query.limit),
|
||||||
coerceUndefinedToNull(request.query.offset),
|
coerceUndefinedToNull(request.query.offset),
|
||||||
coerceUndefinedToNull(request.query.order_by),
|
coerceUndefinedToNull(request.query.order_by),
|
||||||
@ -740,6 +740,7 @@ function foreach_query(foreachIds: Record<string, ScalarValue>[], request: Query
|
|||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
|
null,
|
||||||
);
|
);
|
||||||
return tag('foreach_query', `WITH ${escapeTableName(foreachTableName)} AS (${foreachIdsTableValue}) SELECT ${tableSubquery} AS data`);
|
return tag('foreach_query', `WITH ${escapeTableName(foreachTableName)} AS (${foreachIdsTableValue}) SELECT ${tableSubquery} AS data`);
|
||||||
}
|
}
|
||||||
|
@ -119,6 +119,7 @@ library
|
|||||||
Test.DataConnector.MockAgent.OrderBySpec
|
Test.DataConnector.MockAgent.OrderBySpec
|
||||||
Test.DataConnector.MockAgent.QueryRelationshipsSpec
|
Test.DataConnector.MockAgent.QueryRelationshipsSpec
|
||||||
Test.DataConnector.MockAgent.RemoteRelationshipsSpec
|
Test.DataConnector.MockAgent.RemoteRelationshipsSpec
|
||||||
|
Test.DataConnector.MockAgent.TestHelpers
|
||||||
Test.DataConnector.MockAgent.TransformedConfigurationSpec
|
Test.DataConnector.MockAgent.TransformedConfigurationSpec
|
||||||
Test.DataConnector.MockAgent.UpdateMutationsSpec
|
Test.DataConnector.MockAgent.UpdateMutationsSpec
|
||||||
Test.DataConnector.QuerySpec
|
Test.DataConnector.QuerySpec
|
||||||
|
@ -4,6 +4,7 @@ module Test.DataConnector.MockAgent.AggregateQuerySpec (spec) where
|
|||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
import Control.Lens ((.~), (?~))
|
||||||
import Data.Aeson qualified as Aeson
|
import Data.Aeson qualified as Aeson
|
||||||
import Data.HashMap.Strict qualified as HashMap
|
import Data.HashMap.Strict qualified as HashMap
|
||||||
import Data.List.NonEmpty qualified as NE
|
import Data.List.NonEmpty qualified as NE
|
||||||
@ -18,6 +19,7 @@ import Harness.Yaml (shouldBeYaml)
|
|||||||
import Hasura.Backends.DataConnector.API qualified as API
|
import Hasura.Backends.DataConnector.API qualified as API
|
||||||
import Hasura.Prelude
|
import Hasura.Prelude
|
||||||
import Language.GraphQL.Draft.Syntax.QQ qualified as G
|
import Language.GraphQL.Draft.Syntax.QQ qualified as G
|
||||||
|
import Test.DataConnector.MockAgent.TestHelpers
|
||||||
import Test.Hspec (SpecWith, describe, shouldBe)
|
import Test.Hspec (SpecWith, describe, shouldBe)
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
@ -108,14 +110,14 @@ tests _opts = describe "Aggregate Query Tests" $ do
|
|||||||
}
|
}
|
||||||
|]
|
|]
|
||||||
let queryResponse =
|
let queryResponse =
|
||||||
rowsResponse
|
mkRowsQueryResponse
|
||||||
[ [ (API.FieldName "ArtistIds_Id", API.mkColumnFieldValue $ Aeson.Number 1),
|
[ [ ("ArtistIds_Id", API.mkColumnFieldValue $ Aeson.Number 1),
|
||||||
(API.FieldName "ArtistNames_Name", API.mkColumnFieldValue $ Aeson.String "AC/DC"),
|
("ArtistNames_Name", API.mkColumnFieldValue $ Aeson.String "AC/DC"),
|
||||||
( API.FieldName "nodes_Albums",
|
( "nodes_Albums",
|
||||||
API.mkRelationshipFieldValue $
|
API.mkRelationshipFieldValue $
|
||||||
rowsResponse
|
mkRowsQueryResponse
|
||||||
[ [(API.FieldName "nodes_Title", API.mkColumnFieldValue $ Aeson.String "For Those About To Rock We Salute You")],
|
[ [("nodes_Title", API.mkColumnFieldValue $ Aeson.String "For Those About To Rock We Salute You")],
|
||||||
[(API.FieldName "nodes_Title", API.mkColumnFieldValue $ Aeson.String "Let There Be Rock")]
|
[("nodes_Title", API.mkColumnFieldValue $ Aeson.String "Let There Be Rock")]
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
@ -142,57 +144,40 @@ tests _opts = describe "Aggregate Query Tests" $ do
|
|||||||
_mrrRecordedRequest
|
_mrrRecordedRequest
|
||||||
`shouldBe` Just
|
`shouldBe` Just
|
||||||
( Query $
|
( Query $
|
||||||
API.QueryRequest
|
mkQueryRequest
|
||||||
{ _qrTable = API.TableName ("Artist" :| []),
|
(mkTableName "Artist")
|
||||||
_qrTableRelationships =
|
( emptyQuery
|
||||||
[ API.TableRelationships
|
& API.qFields
|
||||||
{ _trSourceTable = API.TableName ("Artist" :| []),
|
?~ mkFieldsMap
|
||||||
_trRelationships =
|
[ ("ArtistIds_Id", API.ColumnField (API.ColumnName "ArtistId") (API.ScalarType "number")),
|
||||||
HashMap.fromList
|
("ArtistNames_Name", API.ColumnField (API.ColumnName "Name") (API.ScalarType "string")),
|
||||||
[ ( API.RelationshipName "Albums",
|
( "nodes_Albums",
|
||||||
API.Relationship
|
API.RelField
|
||||||
{ _rTargetTable = API.TableName ("Album" :| []),
|
( API.RelationshipField
|
||||||
_rRelationshipType = API.ArrayRelationship,
|
(API.RelationshipName "Albums")
|
||||||
_rColumnMapping = HashMap.fromList [(API.ColumnName "ArtistId", API.ColumnName "ArtistId")]
|
( emptyQuery
|
||||||
}
|
& API.qFields ?~ mkFieldsMap [("nodes_Title", API.ColumnField (API.ColumnName "Title") (API.ScalarType "string"))]
|
||||||
)
|
)
|
||||||
]
|
)
|
||||||
}
|
)
|
||||||
],
|
]
|
||||||
_qrQuery =
|
& API.qLimit ?~ 1
|
||||||
API.Query
|
)
|
||||||
{ _qFields =
|
& API.qrTableRelationships
|
||||||
Just $
|
.~ [ API.TableRelationships
|
||||||
HashMap.fromList
|
{ _trSourceTable = mkTableName "Artist",
|
||||||
[ (API.FieldName "ArtistIds_Id", API.ColumnField (API.ColumnName "ArtistId") (API.ScalarType "number")),
|
_trRelationships =
|
||||||
(API.FieldName "ArtistNames_Name", API.ColumnField (API.ColumnName "Name") (API.ScalarType "string")),
|
HashMap.fromList
|
||||||
( API.FieldName "nodes_Albums",
|
[ ( API.RelationshipName "Albums",
|
||||||
API.RelField
|
API.Relationship
|
||||||
( API.RelationshipField
|
{ _rTargetTable = mkTableName "Album",
|
||||||
(API.RelationshipName "Albums")
|
_rRelationshipType = API.ArrayRelationship,
|
||||||
API.Query
|
_rColumnMapping = HashMap.fromList [(API.ColumnName "ArtistId", API.ColumnName "ArtistId")]
|
||||||
{ _qFields =
|
}
|
||||||
Just $
|
)
|
||||||
HashMap.fromList
|
]
|
||||||
[ (API.FieldName "nodes_Title", API.ColumnField (API.ColumnName "Title") (API.ScalarType "string"))
|
}
|
||||||
],
|
]
|
||||||
_qAggregates = Nothing,
|
|
||||||
_qLimit = Nothing,
|
|
||||||
_qOffset = Nothing,
|
|
||||||
_qWhere = Nothing,
|
|
||||||
_qOrderBy = Nothing
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
],
|
|
||||||
_qAggregates = Nothing,
|
|
||||||
_qLimit = Just 1,
|
|
||||||
_qOffset = Nothing,
|
|
||||||
_qWhere = Nothing,
|
|
||||||
_qOrderBy = Nothing
|
|
||||||
},
|
|
||||||
_qrForeach = Nothing
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
mockAgentGraphqlTest "works with multiple aggregate fields and through array relations" $ \_testEnv performGraphqlRequest -> do
|
mockAgentGraphqlTest "works with multiple aggregate fields and through array relations" $ \_testEnv performGraphqlRequest -> do
|
||||||
@ -224,28 +209,28 @@ tests _opts = describe "Aggregate Query Tests" $ do
|
|||||||
}
|
}
|
||||||
|]
|
|]
|
||||||
let aggregates =
|
let aggregates =
|
||||||
[ (API.FieldName "counts_count", Aeson.Number 2),
|
[ ("counts_count", Aeson.Number 2),
|
||||||
(API.FieldName "counts_uniqueBillingCountries", Aeson.Number 2),
|
("counts_uniqueBillingCountries", Aeson.Number 2),
|
||||||
(API.FieldName "ids_minimum_Id", Aeson.Number 1),
|
("ids_minimum_Id", Aeson.Number 1),
|
||||||
(API.FieldName "ids_max_InvoiceId", Aeson.Number 2)
|
("ids_max_InvoiceId", Aeson.Number 2)
|
||||||
]
|
]
|
||||||
rows =
|
rows =
|
||||||
[ [ ( API.FieldName "nodes_Lines",
|
[ [ ( "nodes_Lines",
|
||||||
API.mkRelationshipFieldValue $
|
API.mkRelationshipFieldValue $
|
||||||
aggregatesResponse
|
mkAggregatesQueryResponse
|
||||||
[ (API.FieldName "aggregate_count", Aeson.Number 2)
|
[ ("aggregate_count", Aeson.Number 2)
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
[ ( API.FieldName "nodes_Lines",
|
[ ( "nodes_Lines",
|
||||||
API.mkRelationshipFieldValue $
|
API.mkRelationshipFieldValue $
|
||||||
aggregatesResponse
|
mkAggregatesQueryResponse
|
||||||
[ (API.FieldName "aggregate_count", Aeson.Number 4)
|
[ ("aggregate_count", Aeson.Number 4)
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
let mockConfig = Mock.chinookMock & mockQueryResponse (aggregatesAndRowsResponse aggregates rows)
|
let mockConfig = Mock.chinookMock & mockQueryResponse (mkQueryResponse rows aggregates)
|
||||||
|
|
||||||
MockRequestResults {..} <- performGraphqlRequest mockConfig headers graphqlRequest
|
MockRequestResults {..} <- performGraphqlRequest mockConfig headers graphqlRequest
|
||||||
|
|
||||||
@ -273,72 +258,47 @@ tests _opts = describe "Aggregate Query Tests" $ do
|
|||||||
_mrrRecordedRequest
|
_mrrRecordedRequest
|
||||||
`shouldBe` Just
|
`shouldBe` Just
|
||||||
( Query $
|
( Query $
|
||||||
API.QueryRequest
|
mkQueryRequest
|
||||||
{ _qrTable = API.TableName ("Invoice" :| []),
|
(mkTableName "Invoice")
|
||||||
_qrTableRelationships =
|
( emptyQuery
|
||||||
[ API.TableRelationships
|
& API.qFields
|
||||||
{ _trSourceTable = API.TableName ("Invoice" :| []),
|
?~ mkFieldsMap
|
||||||
_trRelationships =
|
[ ( "nodes_Lines",
|
||||||
HashMap.fromList
|
API.RelField
|
||||||
[ ( API.RelationshipName "InvoiceLines",
|
( API.RelationshipField
|
||||||
API.Relationship
|
(API.RelationshipName "InvoiceLines")
|
||||||
{ _rTargetTable = API.TableName ("InvoiceLine" :| []),
|
( emptyQuery & API.qAggregates ?~ mkFieldsMap [("aggregate_count", API.StarCount)]
|
||||||
_rRelationshipType = API.ArrayRelationship,
|
)
|
||||||
_rColumnMapping = HashMap.fromList [(API.ColumnName "InvoiceId", API.ColumnName "InvoiceId")]
|
)
|
||||||
}
|
)
|
||||||
)
|
]
|
||||||
]
|
& API.qAggregates
|
||||||
}
|
?~ mkFieldsMap
|
||||||
],
|
[ ("counts_count", API.StarCount),
|
||||||
_qrQuery =
|
("counts_uniqueBillingCountries", API.ColumnCount (API.ColumnCountAggregate (API.ColumnName "BillingCountry") True)),
|
||||||
API.Query
|
("ids_minimum_Id", API.SingleColumn (singleColumnAggregateMin (API.ColumnName "InvoiceId") (API.ScalarType "number"))),
|
||||||
{ _qFields =
|
("ids_max_InvoiceId", API.SingleColumn (singleColumnAggregateMax (API.ColumnName "InvoiceId") (API.ScalarType "number")))
|
||||||
Just $
|
]
|
||||||
HashMap.fromList
|
& API.qLimit ?~ 2
|
||||||
[ ( API.FieldName "nodes_Lines",
|
& API.qAggregatesLimit ?~ 2
|
||||||
API.RelField
|
)
|
||||||
( API.RelationshipField
|
& API.qrTableRelationships
|
||||||
(API.RelationshipName "InvoiceLines")
|
.~ [ API.TableRelationships
|
||||||
API.Query
|
{ _trSourceTable = mkTableName "Invoice",
|
||||||
{ _qFields = Nothing,
|
_trRelationships =
|
||||||
_qAggregates =
|
HashMap.fromList
|
||||||
Just $
|
[ ( API.RelationshipName "InvoiceLines",
|
||||||
HashMap.fromList
|
API.Relationship
|
||||||
[(API.FieldName "aggregate_count", API.StarCount)],
|
{ _rTargetTable = mkTableName "InvoiceLine",
|
||||||
_qLimit = Nothing,
|
_rRelationshipType = API.ArrayRelationship,
|
||||||
_qOffset = Nothing,
|
_rColumnMapping = HashMap.fromList [(API.ColumnName "InvoiceId", API.ColumnName "InvoiceId")]
|
||||||
_qWhere = Nothing,
|
}
|
||||||
_qOrderBy = Nothing
|
)
|
||||||
}
|
]
|
||||||
)
|
}
|
||||||
)
|
]
|
||||||
],
|
|
||||||
_qAggregates =
|
|
||||||
Just $
|
|
||||||
HashMap.fromList
|
|
||||||
[ (API.FieldName "counts_count", API.StarCount),
|
|
||||||
(API.FieldName "counts_uniqueBillingCountries", API.ColumnCount (API.ColumnCountAggregate (API.ColumnName "BillingCountry") True)),
|
|
||||||
(API.FieldName "ids_minimum_Id", API.SingleColumn (singleColumnAggregateMin (API.ColumnName "InvoiceId") (API.ScalarType "number"))),
|
|
||||||
(API.FieldName "ids_max_InvoiceId", API.SingleColumn (singleColumnAggregateMax (API.ColumnName "InvoiceId") (API.ScalarType "number")))
|
|
||||||
],
|
|
||||||
_qLimit = Just 2,
|
|
||||||
_qOffset = Nothing,
|
|
||||||
_qWhere = Nothing,
|
|
||||||
_qOrderBy = Nothing
|
|
||||||
},
|
|
||||||
_qrForeach = Nothing
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
rowsResponse :: [[(API.FieldName, API.FieldValue)]] -> API.QueryResponse
|
|
||||||
rowsResponse rows = API.QueryResponse (Just $ HashMap.fromList <$> rows) Nothing
|
|
||||||
|
|
||||||
aggregatesResponse :: [(API.FieldName, Aeson.Value)] -> API.QueryResponse
|
|
||||||
aggregatesResponse aggregates = API.QueryResponse Nothing (Just $ HashMap.fromList aggregates)
|
|
||||||
|
|
||||||
aggregatesAndRowsResponse :: [(API.FieldName, Aeson.Value)] -> [[(API.FieldName, API.FieldValue)]] -> API.QueryResponse
|
|
||||||
aggregatesAndRowsResponse aggregates rows = API.QueryResponse (Just $ HashMap.fromList <$> rows) (Just $ HashMap.fromList aggregates)
|
|
||||||
|
|
||||||
singleColumnAggregateMax :: API.ColumnName -> API.ScalarType -> API.SingleColumnAggregate
|
singleColumnAggregateMax :: API.ColumnName -> API.ScalarType -> API.SingleColumnAggregate
|
||||||
singleColumnAggregateMax = API.SingleColumnAggregate $ API.SingleColumnAggregateFunction [G.name|max|]
|
singleColumnAggregateMax = API.SingleColumnAggregate $ API.SingleColumnAggregateFunction [G.name|max|]
|
||||||
|
|
||||||
|
@ -6,9 +6,9 @@ module Test.DataConnector.MockAgent.BasicQuerySpec (spec) where
|
|||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
import Control.Lens ((?~))
|
||||||
import Data.Aeson qualified as Aeson
|
import Data.Aeson qualified as Aeson
|
||||||
import Data.ByteString (ByteString)
|
import Data.ByteString (ByteString)
|
||||||
import Data.HashMap.Strict qualified as HashMap
|
|
||||||
import Data.List.NonEmpty qualified as NE
|
import Data.List.NonEmpty qualified as NE
|
||||||
import Harness.Backend.DataConnector.Mock (AgentRequest (..), MockRequestResults (..), mockAgentGraphqlTest, mockQueryResponse)
|
import Harness.Backend.DataConnector.Mock (AgentRequest (..), MockRequestResults (..), mockAgentGraphqlTest, mockQueryResponse)
|
||||||
import Harness.Backend.DataConnector.Mock qualified as Mock
|
import Harness.Backend.DataConnector.Mock qualified as Mock
|
||||||
@ -20,6 +20,7 @@ import Harness.TestEnvironment (GlobalTestEnvironment, TestEnvironment)
|
|||||||
import Harness.Yaml (shouldBeYaml)
|
import Harness.Yaml (shouldBeYaml)
|
||||||
import Hasura.Backends.DataConnector.API qualified as API
|
import Hasura.Backends.DataConnector.API qualified as API
|
||||||
import Hasura.Prelude
|
import Hasura.Prelude
|
||||||
|
import Test.DataConnector.MockAgent.TestHelpers
|
||||||
import Test.Hspec (SpecWith, describe, shouldBe)
|
import Test.Hspec (SpecWith, describe, shouldBe)
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
@ -73,19 +74,19 @@ sourceMetadata =
|
|||||||
configuration:
|
configuration:
|
||||||
custom_root_fields:
|
custom_root_fields:
|
||||||
select: artists
|
select: artists
|
||||||
select_by_pk: artists_by_pk
|
|
||||||
column_config:
|
column_config:
|
||||||
ArtistId:
|
ArtistId:
|
||||||
custom_name: id
|
custom_name: id
|
||||||
Name:
|
Name:
|
||||||
custom_name: name
|
custom_name: name
|
||||||
array_relationships:
|
select_permissions:
|
||||||
- name: albums
|
- role: *testRoleName
|
||||||
using:
|
permission:
|
||||||
manual_configuration:
|
columns:
|
||||||
remote_table: [Album]
|
- ArtistId
|
||||||
column_mapping:
|
- Name
|
||||||
ArtistId: ArtistId
|
limit: 3
|
||||||
|
filter: {}
|
||||||
- table: [Employee]
|
- table: [Employee]
|
||||||
- table: [Customer]
|
- table: [Customer]
|
||||||
select_permissions:
|
select_permissions:
|
||||||
@ -118,9 +119,9 @@ tests _opts = describe "Basic Tests" $ do
|
|||||||
}
|
}
|
||||||
|]
|
|]
|
||||||
let queryResponse =
|
let queryResponse =
|
||||||
rowsResponse
|
mkRowsQueryResponse
|
||||||
[ [ (API.FieldName "id", API.mkColumnFieldValue $ Aeson.Number 1),
|
[ [ ("id", API.mkColumnFieldValue $ Aeson.Number 1),
|
||||||
(API.FieldName "title", API.mkColumnFieldValue $ Aeson.String "For Those About To Rock We Salute You")
|
("title", API.mkColumnFieldValue $ Aeson.String "For Those About To Rock We Salute You")
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
let mockConfig = Mock.chinookMock & mockQueryResponse queryResponse
|
let mockConfig = Mock.chinookMock & mockQueryResponse queryResponse
|
||||||
@ -138,25 +139,70 @@ tests _opts = describe "Basic Tests" $ do
|
|||||||
_mrrRecordedRequest
|
_mrrRecordedRequest
|
||||||
`shouldBe` Just
|
`shouldBe` Just
|
||||||
( Query $
|
( Query $
|
||||||
API.QueryRequest
|
mkQueryRequest
|
||||||
{ _qrTable = API.TableName ("Album" :| []),
|
(mkTableName "Album")
|
||||||
_qrTableRelationships = [],
|
( emptyQuery
|
||||||
_qrQuery =
|
& API.qFields
|
||||||
API.Query
|
?~ mkFieldsMap
|
||||||
{ _qFields =
|
[ ("id", API.ColumnField (API.ColumnName "AlbumId") (API.ScalarType "number")),
|
||||||
Just $
|
("title", API.ColumnField (API.ColumnName "Title") (API.ScalarType "string"))
|
||||||
HashMap.fromList
|
]
|
||||||
[ (API.FieldName "id", API.ColumnField (API.ColumnName "AlbumId") (API.ScalarType "number")),
|
& API.qLimit ?~ 1
|
||||||
(API.FieldName "title", API.ColumnField (API.ColumnName "Title") (API.ScalarType "string"))
|
)
|
||||||
],
|
)
|
||||||
_qAggregates = Nothing,
|
|
||||||
_qLimit = Just 1,
|
mockAgentGraphqlTest "permissions-based row limits are applied" $ \_testEnv performGraphqlRequest -> do
|
||||||
_qOffset = Nothing,
|
let headers = [("X-Hasura-Role", testRoleName)]
|
||||||
_qWhere = Nothing,
|
let graphqlRequest =
|
||||||
_qOrderBy = Nothing
|
[graphql|
|
||||||
},
|
query getArtists {
|
||||||
_qrForeach = Nothing
|
artists(limit: 5) {
|
||||||
|
id
|
||||||
|
name
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|]
|
||||||
|
let queryResponse =
|
||||||
|
mkRowsQueryResponse
|
||||||
|
[ [ ("id", API.mkColumnFieldValue $ Aeson.Number 1),
|
||||||
|
("name", API.mkColumnFieldValue $ Aeson.String "AC/DC")
|
||||||
|
],
|
||||||
|
[ ("id", API.mkColumnFieldValue $ Aeson.Number 2),
|
||||||
|
("name", API.mkColumnFieldValue $ Aeson.String "Accept")
|
||||||
|
],
|
||||||
|
[ ("id", API.mkColumnFieldValue $ Aeson.Number 3),
|
||||||
|
("name", API.mkColumnFieldValue $ Aeson.String "Aerosmith")
|
||||||
|
]
|
||||||
|
]
|
||||||
|
let mockConfig = Mock.chinookMock & mockQueryResponse queryResponse
|
||||||
|
|
||||||
|
MockRequestResults {..} <- performGraphqlRequest mockConfig headers graphqlRequest
|
||||||
|
|
||||||
|
_mrrResponse
|
||||||
|
`shouldBeYaml` [yaml|
|
||||||
|
data:
|
||||||
|
artists:
|
||||||
|
- id: 1
|
||||||
|
name: AC/DC
|
||||||
|
- id: 2
|
||||||
|
name: Accept
|
||||||
|
- id: 3
|
||||||
|
name: Aerosmith
|
||||||
|
|]
|
||||||
|
|
||||||
|
_mrrRecordedRequest
|
||||||
|
`shouldBe` Just
|
||||||
|
( Query $
|
||||||
|
mkQueryRequest
|
||||||
|
(mkTableName "Artist")
|
||||||
|
( emptyQuery
|
||||||
|
& API.qFields
|
||||||
|
?~ mkFieldsMap
|
||||||
|
[ ("id", API.ColumnField (API.ColumnName "ArtistId") $ API.ScalarType "number"),
|
||||||
|
("name", API.ColumnField (API.ColumnName "Name") $ API.ScalarType "string")
|
||||||
|
]
|
||||||
|
& API.qLimit ?~ 3 -- The permissions limit is smaller than the query limit, so it is used
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
mockAgentGraphqlTest "works with an exists-based permissions filter" $ \_testEnv performGraphqlRequest -> do
|
mockAgentGraphqlTest "works with an exists-based permissions filter" $ \_testEnv performGraphqlRequest -> do
|
||||||
@ -173,12 +219,12 @@ tests _opts = describe "Basic Tests" $ do
|
|||||||
}
|
}
|
||||||
|]
|
|]
|
||||||
let queryResponse =
|
let queryResponse =
|
||||||
rowsResponse
|
mkRowsQueryResponse
|
||||||
[ [ (API.FieldName "CustomerId", API.mkColumnFieldValue $ Aeson.Number 1)
|
[ [ ("CustomerId", API.mkColumnFieldValue $ Aeson.Number 1)
|
||||||
],
|
],
|
||||||
[ (API.FieldName "CustomerId", API.mkColumnFieldValue $ Aeson.Number 2)
|
[ ("CustomerId", API.mkColumnFieldValue $ Aeson.Number 2)
|
||||||
],
|
],
|
||||||
[ (API.FieldName "CustomerId", API.mkColumnFieldValue $ Aeson.Number 3)
|
[ ("CustomerId", API.mkColumnFieldValue $ Aeson.Number 3)
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
let mockConfig = Mock.chinookMock & mockQueryResponse queryResponse
|
let mockConfig = Mock.chinookMock & mockQueryResponse queryResponse
|
||||||
@ -197,31 +243,20 @@ tests _opts = describe "Basic Tests" $ do
|
|||||||
_mrrRecordedRequest
|
_mrrRecordedRequest
|
||||||
`shouldBe` Just
|
`shouldBe` Just
|
||||||
( Query $
|
( Query $
|
||||||
API.QueryRequest
|
mkQueryRequest
|
||||||
{ _qrTable = API.TableName ("Customer" :| []),
|
(mkTableName "Customer")
|
||||||
_qrTableRelationships = [],
|
( emptyQuery
|
||||||
_qrQuery =
|
& API.qFields
|
||||||
API.Query
|
?~ mkFieldsMap
|
||||||
{ _qFields =
|
[ ("CustomerId", API.ColumnField (API.ColumnName "CustomerId") $ API.ScalarType "number")
|
||||||
Just $
|
]
|
||||||
HashMap.fromList
|
& API.qWhere
|
||||||
[ (API.FieldName "CustomerId", API.ColumnField (API.ColumnName "CustomerId") $ API.ScalarType "number")
|
?~ API.Exists
|
||||||
],
|
(API.UnrelatedTable $ mkTableName "Employee")
|
||||||
_qAggregates = Nothing,
|
( API.ApplyBinaryComparisonOperator
|
||||||
_qLimit = Nothing,
|
API.Equal
|
||||||
_qOffset = Nothing,
|
(API.ComparisonColumn API.CurrentTable (API.ColumnName "EmployeeId") $ API.ScalarType "number")
|
||||||
_qWhere =
|
(API.ScalarValueComparison $ API.ScalarValue (Aeson.Number 1) (API.ScalarType "number"))
|
||||||
Just $
|
)
|
||||||
API.Exists (API.UnrelatedTable $ API.TableName ("Employee" :| [])) $
|
)
|
||||||
API.ApplyBinaryComparisonOperator
|
|
||||||
API.Equal
|
|
||||||
(API.ComparisonColumn API.CurrentTable (API.ColumnName "EmployeeId") $ API.ScalarType "number")
|
|
||||||
(API.ScalarValueComparison $ API.ScalarValue (Aeson.Number 1) (API.ScalarType "number")),
|
|
||||||
_qOrderBy = Nothing
|
|
||||||
},
|
|
||||||
_qrForeach = Nothing
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
rowsResponse :: [[(API.FieldName, API.FieldValue)]] -> API.QueryResponse
|
|
||||||
rowsResponse rows = API.QueryResponse (Just $ HashMap.fromList <$> rows) Nothing
|
|
||||||
|
@ -6,8 +6,8 @@ module Test.DataConnector.MockAgent.CustomScalarsSpec (spec) where
|
|||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
import Control.Lens ((?~))
|
||||||
import Data.Aeson qualified as Aeson
|
import Data.Aeson qualified as Aeson
|
||||||
import Data.HashMap.Strict qualified as HashMap
|
|
||||||
import Data.List.NonEmpty qualified as NE
|
import Data.List.NonEmpty qualified as NE
|
||||||
import Harness.Backend.DataConnector.Mock (AgentRequest (..), MockRequestResults (..), mockAgentGraphqlTest, mockQueryResponse)
|
import Harness.Backend.DataConnector.Mock (AgentRequest (..), MockRequestResults (..), mockAgentGraphqlTest, mockQueryResponse)
|
||||||
import Harness.Backend.DataConnector.Mock qualified as Mock
|
import Harness.Backend.DataConnector.Mock qualified as Mock
|
||||||
@ -21,6 +21,7 @@ import Hasura.Backends.DataConnector.API (ColumnName (..), ScalarType (..), Scal
|
|||||||
import Hasura.Backends.DataConnector.API qualified as API
|
import Hasura.Backends.DataConnector.API qualified as API
|
||||||
import Hasura.Backends.DataConnector.API.V0.Expression
|
import Hasura.Backends.DataConnector.API.V0.Expression
|
||||||
import Hasura.Prelude
|
import Hasura.Prelude
|
||||||
|
import Test.DataConnector.MockAgent.TestHelpers
|
||||||
import Test.Hspec (SpecWith, describe, shouldBe)
|
import Test.Hspec (SpecWith, describe, shouldBe)
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
@ -67,7 +68,7 @@ tests _opts = describe "Custom scalar parsing tests" $ do
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|]
|
|]
|
||||||
let mockConfig = Mock.chinookMock & mockQueryResponse (rowsResponse customScalarsTable)
|
let mockConfig = Mock.chinookMock & mockQueryResponse (mkRowsQueryResponse customScalarsTable)
|
||||||
|
|
||||||
MockRequestResults {..} <- performGraphqlRequest mockConfig headers graphqlRequest
|
MockRequestResults {..} <- performGraphqlRequest mockConfig headers graphqlRequest
|
||||||
|
|
||||||
@ -86,29 +87,20 @@ tests _opts = describe "Custom scalar parsing tests" $ do
|
|||||||
_mrrRecordedRequest
|
_mrrRecordedRequest
|
||||||
`shouldBe` Just
|
`shouldBe` Just
|
||||||
( Query $
|
( Query $
|
||||||
API.QueryRequest
|
mkQueryRequest
|
||||||
{ _qrTable = API.TableName ("MyCustomScalarsTable" :| []),
|
(mkTableName "MyCustomScalarsTable")
|
||||||
_qrTableRelationships = [],
|
( emptyQuery
|
||||||
_qrQuery =
|
& API.qFields
|
||||||
API.Query
|
?~ mkFieldsMap
|
||||||
{ _qFields =
|
[ ("MyIntColumn", API.ColumnField (API.ColumnName "MyIntColumn") $ API.ScalarType "MyInt"),
|
||||||
Just $
|
("MyFloatColumn", API.ColumnField (API.ColumnName "MyFloatColumn") $ API.ScalarType "MyFloat"),
|
||||||
HashMap.fromList
|
("MyStringColumn", API.ColumnField (API.ColumnName "MyStringColumn") $ API.ScalarType "MyString"),
|
||||||
[ (API.FieldName "MyIntColumn", API.ColumnField (API.ColumnName "MyIntColumn") $ API.ScalarType "MyInt"),
|
("MyBooleanColumn", API.ColumnField (API.ColumnName "MyBooleanColumn") $ API.ScalarType "MyBoolean"),
|
||||||
(API.FieldName "MyFloatColumn", API.ColumnField (API.ColumnName "MyFloatColumn") $ API.ScalarType "MyFloat"),
|
("MyIDColumn", API.ColumnField (API.ColumnName "MyIDColumn") $ API.ScalarType "MyID"),
|
||||||
(API.FieldName "MyStringColumn", API.ColumnField (API.ColumnName "MyStringColumn") $ API.ScalarType "MyString"),
|
("MyAnythingColumn", API.ColumnField (API.ColumnName "MyAnythingColumn") $ API.ScalarType "MyAnything")
|
||||||
(API.FieldName "MyBooleanColumn", API.ColumnField (API.ColumnName "MyBooleanColumn") $ API.ScalarType "MyBoolean"),
|
]
|
||||||
(API.FieldName "MyIDColumn", API.ColumnField (API.ColumnName "MyIDColumn") $ API.ScalarType "MyID"),
|
& API.qLimit ?~ 1
|
||||||
(API.FieldName "MyAnythingColumn", API.ColumnField (API.ColumnName "MyAnythingColumn") $ API.ScalarType "MyAnything")
|
)
|
||||||
],
|
|
||||||
_qAggregates = Nothing,
|
|
||||||
_qLimit = Just 1,
|
|
||||||
_qOffset = Nothing,
|
|
||||||
_qWhere = Nothing,
|
|
||||||
_qOrderBy = Nothing
|
|
||||||
},
|
|
||||||
_qrForeach = Nothing
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
mockAgentGraphqlTest "parses scalar literals in where queries" $ \_testEnv performGraphqlRequest -> do
|
mockAgentGraphqlTest "parses scalar literals in where queries" $ \_testEnv performGraphqlRequest -> do
|
||||||
@ -133,7 +125,7 @@ tests _opts = describe "Custom scalar parsing tests" $ do
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|]
|
|]
|
||||||
let mockConfig = Mock.chinookMock & mockQueryResponse (rowsResponse customScalarsTable)
|
let mockConfig = Mock.chinookMock & mockQueryResponse (mkRowsQueryResponse customScalarsTable)
|
||||||
|
|
||||||
MockRequestResults {..} <- performGraphqlRequest mockConfig headers graphqlRequest
|
MockRequestResults {..} <- performGraphqlRequest mockConfig headers graphqlRequest
|
||||||
|
|
||||||
@ -152,56 +144,47 @@ tests _opts = describe "Custom scalar parsing tests" $ do
|
|||||||
_mrrRecordedRequest
|
_mrrRecordedRequest
|
||||||
`shouldBe` Just
|
`shouldBe` Just
|
||||||
( Query $
|
( Query $
|
||||||
API.QueryRequest
|
mkQueryRequest
|
||||||
{ _qrTable = API.TableName ("MyCustomScalarsTable" :| []),
|
(mkTableName "MyCustomScalarsTable")
|
||||||
_qrTableRelationships = [],
|
( emptyQuery
|
||||||
_qrQuery =
|
& API.qFields
|
||||||
API.Query
|
?~ mkFieldsMap
|
||||||
{ _qFields =
|
[ ("MyIntColumn", API.ColumnField (API.ColumnName "MyIntColumn") $ API.ScalarType "MyInt"),
|
||||||
Just $
|
("MyFloatColumn", API.ColumnField (API.ColumnName "MyFloatColumn") $ API.ScalarType "MyFloat"),
|
||||||
HashMap.fromList
|
("MyStringColumn", API.ColumnField (API.ColumnName "MyStringColumn") $ API.ScalarType "MyString"),
|
||||||
[ (API.FieldName "MyIntColumn", API.ColumnField (API.ColumnName "MyIntColumn") $ API.ScalarType "MyInt"),
|
("MyBooleanColumn", API.ColumnField (API.ColumnName "MyBooleanColumn") $ API.ScalarType "MyBoolean"),
|
||||||
(API.FieldName "MyFloatColumn", API.ColumnField (API.ColumnName "MyFloatColumn") $ API.ScalarType "MyFloat"),
|
("MyIDColumn", API.ColumnField (API.ColumnName "MyIDColumn") $ API.ScalarType "MyID"),
|
||||||
(API.FieldName "MyStringColumn", API.ColumnField (API.ColumnName "MyStringColumn") $ API.ScalarType "MyString"),
|
("MyAnythingColumn", API.ColumnField (API.ColumnName "MyAnythingColumn") $ API.ScalarType "MyAnything")
|
||||||
(API.FieldName "MyBooleanColumn", API.ColumnField (API.ColumnName "MyBooleanColumn") $ API.ScalarType "MyBoolean"),
|
]
|
||||||
(API.FieldName "MyIDColumn", API.ColumnField (API.ColumnName "MyIDColumn") $ API.ScalarType "MyID"),
|
& API.qLimit ?~ 1
|
||||||
(API.FieldName "MyAnythingColumn", API.ColumnField (API.ColumnName "MyAnythingColumn") $ API.ScalarType "MyAnything")
|
& API.qWhere
|
||||||
],
|
?~ And
|
||||||
_qAggregates = Nothing,
|
[ ApplyBinaryComparisonOperator
|
||||||
_qLimit = Just 1,
|
Equal
|
||||||
_qOffset = Nothing,
|
(ComparisonColumn CurrentTable (ColumnName "MyBooleanColumn") (ScalarType "MyBoolean"))
|
||||||
_qWhere =
|
(ScalarValueComparison $ ScalarValue (Aeson.Bool True) (ScalarType "MyBoolean")),
|
||||||
Just $
|
ApplyBinaryComparisonOperator
|
||||||
And
|
Equal
|
||||||
[ ApplyBinaryComparisonOperator
|
(ComparisonColumn CurrentTable (ColumnName "MyFloatColumn") (ScalarType "MyFloat"))
|
||||||
Equal
|
(ScalarValueComparison $ ScalarValue (Aeson.Number 3.14) (ScalarType "MyFloat")),
|
||||||
(ComparisonColumn {_ccPath = CurrentTable, _ccName = ColumnName {unColumnName = "MyBooleanColumn"}, _ccColumnType = ScalarType "MyBoolean"})
|
ApplyBinaryComparisonOperator
|
||||||
(ScalarValueComparison $ ScalarValue (Aeson.Bool True) (ScalarType "MyBoolean")),
|
Equal
|
||||||
ApplyBinaryComparisonOperator
|
(ComparisonColumn CurrentTable (ColumnName "MyStringColumn") (ScalarType "MyString"))
|
||||||
Equal
|
(ScalarValueComparison $ ScalarValue (Aeson.String "foo") (ScalarType "MyString")),
|
||||||
(ComparisonColumn {_ccPath = CurrentTable, _ccName = ColumnName {unColumnName = "MyFloatColumn"}, _ccColumnType = ScalarType "MyFloat"})
|
ApplyBinaryComparisonOperator
|
||||||
(ScalarValueComparison $ ScalarValue (Aeson.Number 3.14) (ScalarType "MyFloat")),
|
Equal
|
||||||
ApplyBinaryComparisonOperator
|
(ComparisonColumn CurrentTable (ColumnName "MyIDColumn") (ScalarType "MyID"))
|
||||||
Equal
|
(ScalarValueComparison $ ScalarValue (Aeson.String "x") (ScalarType "MyID")),
|
||||||
(ComparisonColumn {_ccPath = CurrentTable, _ccName = ColumnName {unColumnName = "MyStringColumn"}, _ccColumnType = ScalarType "MyString"})
|
ApplyBinaryComparisonOperator
|
||||||
(ScalarValueComparison $ ScalarValue (Aeson.String "foo") (ScalarType "MyString")),
|
Equal
|
||||||
ApplyBinaryComparisonOperator
|
(ComparisonColumn CurrentTable (ColumnName "MyIntColumn") (ScalarType "MyInt"))
|
||||||
Equal
|
(ScalarValueComparison $ ScalarValue (Aeson.Number 42.0) (ScalarType "MyInt")),
|
||||||
(ComparisonColumn {_ccPath = CurrentTable, _ccName = ColumnName {unColumnName = "MyIDColumn"}, _ccColumnType = ScalarType "MyID"})
|
ApplyBinaryComparisonOperator
|
||||||
(ScalarValueComparison $ ScalarValue (Aeson.String "x") (ScalarType "MyID")),
|
Equal
|
||||||
ApplyBinaryComparisonOperator
|
(ComparisonColumn CurrentTable (ColumnName "MyAnythingColumn") (ScalarType "MyAnything"))
|
||||||
Equal
|
(ScalarValueComparison $ ScalarValue (Aeson.Object mempty) (ScalarType "MyAnything"))
|
||||||
(ComparisonColumn {_ccPath = CurrentTable, _ccName = ColumnName {unColumnName = "MyIntColumn"}, _ccColumnType = ScalarType "MyInt"})
|
]
|
||||||
(ScalarValueComparison $ ScalarValue (Aeson.Number 42.0) (ScalarType "MyInt")),
|
)
|
||||||
ApplyBinaryComparisonOperator
|
|
||||||
Equal
|
|
||||||
(ComparisonColumn {_ccPath = CurrentTable, _ccName = ColumnName {unColumnName = "MyAnythingColumn"}, _ccColumnType = ScalarType "MyAnything"})
|
|
||||||
(ScalarValueComparison $ ScalarValue (Aeson.Object mempty) (ScalarType "MyAnything"))
|
|
||||||
],
|
|
||||||
_qOrderBy = Nothing
|
|
||||||
},
|
|
||||||
_qrForeach = Nothing
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
mockAgentGraphqlTest "fails parsing float when expecting int" $ \_testEnv performGraphqlRequest -> do
|
mockAgentGraphqlTest "fails parsing float when expecting int" $ \_testEnv performGraphqlRequest -> do
|
||||||
@ -216,7 +199,7 @@ tests _opts = describe "Custom scalar parsing tests" $ do
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|]
|
|]
|
||||||
let mockConfig = Mock.chinookMock & mockQueryResponse (rowsResponse myIntTable)
|
let mockConfig = Mock.chinookMock & mockQueryResponse (mkRowsQueryResponse myIntTable)
|
||||||
|
|
||||||
MockRequestResults {..} <- performGraphqlRequest mockConfig headers graphqlRequest
|
MockRequestResults {..} <- performGraphqlRequest mockConfig headers graphqlRequest
|
||||||
|
|
||||||
@ -243,7 +226,7 @@ tests _opts = describe "Custom scalar parsing tests" $ do
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|]
|
|]
|
||||||
let mockConfig = Mock.chinookMock & mockQueryResponse (rowsResponse myIntTable)
|
let mockConfig = Mock.chinookMock & mockQueryResponse (mkRowsQueryResponse myIntTable)
|
||||||
|
|
||||||
MockRequestResults {..} <- performGraphqlRequest mockConfig headers graphqlRequest
|
MockRequestResults {..} <- performGraphqlRequest mockConfig headers graphqlRequest
|
||||||
|
|
||||||
@ -270,7 +253,7 @@ tests _opts = describe "Custom scalar parsing tests" $ do
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|]
|
|]
|
||||||
let mockConfig = Mock.chinookMock & mockQueryResponse (rowsResponse myIntTable)
|
let mockConfig = Mock.chinookMock & mockQueryResponse (mkRowsQueryResponse myIntTable)
|
||||||
|
|
||||||
MockRequestResults {..} <- performGraphqlRequest mockConfig headers graphqlRequest
|
MockRequestResults {..} <- performGraphqlRequest mockConfig headers graphqlRequest
|
||||||
|
|
||||||
@ -297,7 +280,7 @@ tests _opts = describe "Custom scalar parsing tests" $ do
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|]
|
|]
|
||||||
let mockConfig = Mock.chinookMock & mockQueryResponse (rowsResponse myIntTable)
|
let mockConfig = Mock.chinookMock & mockQueryResponse (mkRowsQueryResponse myIntTable)
|
||||||
|
|
||||||
MockRequestResults {..} <- performGraphqlRequest mockConfig headers graphqlRequest
|
MockRequestResults {..} <- performGraphqlRequest mockConfig headers graphqlRequest
|
||||||
|
|
||||||
@ -320,7 +303,7 @@ tests _opts = describe "Custom scalar parsing tests" $ do
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|]
|
|]
|
||||||
let mockConfig = Mock.chinookMock & mockQueryResponse (rowsResponse myIntTable)
|
let mockConfig = Mock.chinookMock & mockQueryResponse (mkRowsQueryResponse myIntTable)
|
||||||
|
|
||||||
MockRequestResults {..} <- performGraphqlRequest mockConfig headers graphqlRequest
|
MockRequestResults {..} <- performGraphqlRequest mockConfig headers graphqlRequest
|
||||||
|
|
||||||
@ -347,7 +330,7 @@ tests _opts = describe "Custom scalar parsing tests" $ do
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|]
|
|]
|
||||||
let mockConfig = Mock.chinookMock & mockQueryResponse (rowsResponse myIntTable)
|
let mockConfig = Mock.chinookMock & mockQueryResponse (mkRowsQueryResponse myIntTable)
|
||||||
|
|
||||||
MockRequestResults {..} <- performGraphqlRequest mockConfig headers graphqlRequest
|
MockRequestResults {..} <- performGraphqlRequest mockConfig headers graphqlRequest
|
||||||
|
|
||||||
@ -374,7 +357,7 @@ tests _opts = describe "Custom scalar parsing tests" $ do
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|]
|
|]
|
||||||
let mockConfig = Mock.chinookMock & mockQueryResponse (rowsResponse myIntTable)
|
let mockConfig = Mock.chinookMock & mockQueryResponse (mkRowsQueryResponse myIntTable)
|
||||||
|
|
||||||
MockRequestResults {..} <- performGraphqlRequest mockConfig headers graphqlRequest
|
MockRequestResults {..} <- performGraphqlRequest mockConfig headers graphqlRequest
|
||||||
|
|
||||||
@ -401,7 +384,7 @@ tests _opts = describe "Custom scalar parsing tests" $ do
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|]
|
|]
|
||||||
let mockConfig = Mock.chinookMock & mockQueryResponse (rowsResponse myIntTable)
|
let mockConfig = Mock.chinookMock & mockQueryResponse (mkRowsQueryResponse myIntTable)
|
||||||
|
|
||||||
MockRequestResults {..} <- performGraphqlRequest mockConfig headers graphqlRequest
|
MockRequestResults {..} <- performGraphqlRequest mockConfig headers graphqlRequest
|
||||||
|
|
||||||
@ -428,7 +411,7 @@ tests _opts = describe "Custom scalar parsing tests" $ do
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|]
|
|]
|
||||||
let mockConfig = Mock.chinookMock & mockQueryResponse (rowsResponse myIntTable)
|
let mockConfig = Mock.chinookMock & mockQueryResponse (mkRowsQueryResponse myIntTable)
|
||||||
|
|
||||||
MockRequestResults {..} <- performGraphqlRequest mockConfig headers graphqlRequest
|
MockRequestResults {..} <- performGraphqlRequest mockConfig headers graphqlRequest
|
||||||
|
|
||||||
@ -455,7 +438,7 @@ tests _opts = describe "Custom scalar parsing tests" $ do
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|]
|
|]
|
||||||
let mockConfig = Mock.chinookMock & mockQueryResponse (rowsResponse myIntTable)
|
let mockConfig = Mock.chinookMock & mockQueryResponse (mkRowsQueryResponse myIntTable)
|
||||||
|
|
||||||
MockRequestResults {..} <- performGraphqlRequest mockConfig headers graphqlRequest
|
MockRequestResults {..} <- performGraphqlRequest mockConfig headers graphqlRequest
|
||||||
|
|
||||||
@ -482,7 +465,7 @@ tests _opts = describe "Custom scalar parsing tests" $ do
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|]
|
|]
|
||||||
let mockConfig = Mock.chinookMock & mockQueryResponse (rowsResponse myIntTable)
|
let mockConfig = Mock.chinookMock & mockQueryResponse (mkRowsQueryResponse myIntTable)
|
||||||
|
|
||||||
MockRequestResults {..} <- performGraphqlRequest mockConfig headers graphqlRequest
|
MockRequestResults {..} <- performGraphqlRequest mockConfig headers graphqlRequest
|
||||||
|
|
||||||
@ -509,7 +492,7 @@ tests _opts = describe "Custom scalar parsing tests" $ do
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|]
|
|]
|
||||||
let mockConfig = Mock.chinookMock & mockQueryResponse (rowsResponse myIntTable)
|
let mockConfig = Mock.chinookMock & mockQueryResponse (mkRowsQueryResponse myIntTable)
|
||||||
|
|
||||||
MockRequestResults {..} <- performGraphqlRequest mockConfig headers graphqlRequest
|
MockRequestResults {..} <- performGraphqlRequest mockConfig headers graphqlRequest
|
||||||
|
|
||||||
@ -536,7 +519,7 @@ tests _opts = describe "Custom scalar parsing tests" $ do
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|]
|
|]
|
||||||
let mockConfig = Mock.chinookMock & mockQueryResponse (rowsResponse myIntTable)
|
let mockConfig = Mock.chinookMock & mockQueryResponse (mkRowsQueryResponse myIntTable)
|
||||||
|
|
||||||
MockRequestResults {..} <- performGraphqlRequest mockConfig headers graphqlRequest
|
MockRequestResults {..} <- performGraphqlRequest mockConfig headers graphqlRequest
|
||||||
|
|
||||||
@ -559,7 +542,7 @@ tests _opts = describe "Custom scalar parsing tests" $ do
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|]
|
|]
|
||||||
let mockConfig = Mock.chinookMock & mockQueryResponse (rowsResponse myIntTable)
|
let mockConfig = Mock.chinookMock & mockQueryResponse (mkRowsQueryResponse myIntTable)
|
||||||
|
|
||||||
MockRequestResults {..} <- performGraphqlRequest mockConfig headers graphqlRequest
|
MockRequestResults {..} <- performGraphqlRequest mockConfig headers graphqlRequest
|
||||||
|
|
||||||
@ -586,7 +569,7 @@ tests _opts = describe "Custom scalar parsing tests" $ do
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|]
|
|]
|
||||||
let mockConfig = Mock.chinookMock & mockQueryResponse (rowsResponse myIntTable)
|
let mockConfig = Mock.chinookMock & mockQueryResponse (mkRowsQueryResponse myIntTable)
|
||||||
|
|
||||||
MockRequestResults {..} <- performGraphqlRequest mockConfig headers graphqlRequest
|
MockRequestResults {..} <- performGraphqlRequest mockConfig headers graphqlRequest
|
||||||
|
|
||||||
@ -613,7 +596,7 @@ tests _opts = describe "Custom scalar parsing tests" $ do
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|]
|
|]
|
||||||
let mockConfig = Mock.chinookMock & mockQueryResponse (rowsResponse myIntTable)
|
let mockConfig = Mock.chinookMock & mockQueryResponse (mkRowsQueryResponse myIntTable)
|
||||||
|
|
||||||
MockRequestResults {..} <- performGraphqlRequest mockConfig headers graphqlRequest
|
MockRequestResults {..} <- performGraphqlRequest mockConfig headers graphqlRequest
|
||||||
|
|
||||||
@ -636,7 +619,7 @@ tests _opts = describe "Custom scalar parsing tests" $ do
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|]
|
|]
|
||||||
let mockConfig = Mock.chinookMock & mockQueryResponse (rowsResponse myIntTable)
|
let mockConfig = Mock.chinookMock & mockQueryResponse (mkRowsQueryResponse myIntTable)
|
||||||
|
|
||||||
MockRequestResults {..} <- performGraphqlRequest mockConfig headers graphqlRequest
|
MockRequestResults {..} <- performGraphqlRequest mockConfig headers graphqlRequest
|
||||||
|
|
||||||
@ -659,7 +642,7 @@ tests _opts = describe "Custom scalar parsing tests" $ do
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|]
|
|]
|
||||||
let mockConfig = Mock.chinookMock & mockQueryResponse (rowsResponse myIntTable)
|
let mockConfig = Mock.chinookMock & mockQueryResponse (mkRowsQueryResponse myIntTable)
|
||||||
|
|
||||||
MockRequestResults {..} <- performGraphqlRequest mockConfig headers graphqlRequest
|
MockRequestResults {..} <- performGraphqlRequest mockConfig headers graphqlRequest
|
||||||
|
|
||||||
@ -682,7 +665,7 @@ tests _opts = describe "Custom scalar parsing tests" $ do
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|]
|
|]
|
||||||
let mockConfig = Mock.chinookMock & mockQueryResponse (rowsResponse myIntTable)
|
let mockConfig = Mock.chinookMock & mockQueryResponse (mkRowsQueryResponse myIntTable)
|
||||||
|
|
||||||
MockRequestResults {..} <- performGraphqlRequest mockConfig headers graphqlRequest
|
MockRequestResults {..} <- performGraphqlRequest mockConfig headers graphqlRequest
|
||||||
|
|
||||||
@ -705,7 +688,7 @@ tests _opts = describe "Custom scalar parsing tests" $ do
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|]
|
|]
|
||||||
let mockConfig = Mock.chinookMock & mockQueryResponse (rowsResponse myIntTable)
|
let mockConfig = Mock.chinookMock & mockQueryResponse (mkRowsQueryResponse myIntTable)
|
||||||
|
|
||||||
MockRequestResults {..} <- performGraphqlRequest mockConfig headers graphqlRequest
|
MockRequestResults {..} <- performGraphqlRequest mockConfig headers graphqlRequest
|
||||||
|
|
||||||
@ -717,18 +700,15 @@ tests _opts = describe "Custom scalar parsing tests" $ do
|
|||||||
|]
|
|]
|
||||||
where
|
where
|
||||||
customScalarsTable =
|
customScalarsTable =
|
||||||
[ [ (API.FieldName "MyIntColumn", API.mkColumnFieldValue $ Aeson.Number 42),
|
[ [ ("MyIntColumn", API.mkColumnFieldValue $ Aeson.Number 42),
|
||||||
(API.FieldName "MyFloatColumn", API.mkColumnFieldValue $ Aeson.Number 3.14),
|
("MyFloatColumn", API.mkColumnFieldValue $ Aeson.Number 3.14),
|
||||||
(API.FieldName "MyStringColumn", API.mkColumnFieldValue $ Aeson.String "foo"),
|
("MyStringColumn", API.mkColumnFieldValue $ Aeson.String "foo"),
|
||||||
(API.FieldName "MyBooleanColumn", API.mkColumnFieldValue $ Aeson.Bool True),
|
("MyBooleanColumn", API.mkColumnFieldValue $ Aeson.Bool True),
|
||||||
(API.FieldName "MyIDColumn", API.mkColumnFieldValue $ Aeson.String "x"),
|
("MyIDColumn", API.mkColumnFieldValue $ Aeson.String "x"),
|
||||||
(API.FieldName "MyAnythingColumn", API.mkColumnFieldValue $ Aeson.Object mempty)
|
("MyAnythingColumn", API.mkColumnFieldValue $ Aeson.Object mempty)
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
myIntTable =
|
myIntTable =
|
||||||
[ [ (API.FieldName "MyIntColumn", API.mkColumnFieldValue $ Aeson.Number 42)
|
[ [ ("MyIntColumn", API.mkColumnFieldValue $ Aeson.Number 42)
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
rowsResponse :: [[(API.FieldName, API.FieldValue)]] -> API.QueryResponse
|
|
||||||
rowsResponse rows = API.QueryResponse (Just $ HashMap.fromList <$> rows) Nothing
|
|
||||||
|
@ -3,6 +3,7 @@ module Test.DataConnector.MockAgent.DeleteMutationsSpec
|
|||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
|
import Control.Lens ((.~), (?~))
|
||||||
import Data.Aeson qualified as Aeson
|
import Data.Aeson qualified as Aeson
|
||||||
import Data.ByteString (ByteString)
|
import Data.ByteString (ByteString)
|
||||||
import Data.HashMap.Strict qualified as HashMap
|
import Data.HashMap.Strict qualified as HashMap
|
||||||
@ -17,6 +18,7 @@ import Harness.TestEnvironment (GlobalTestEnvironment, TestEnvironment)
|
|||||||
import Harness.Yaml
|
import Harness.Yaml
|
||||||
import Hasura.Backends.DataConnector.API qualified as API
|
import Hasura.Backends.DataConnector.API qualified as API
|
||||||
import Hasura.Prelude
|
import Hasura.Prelude
|
||||||
|
import Test.DataConnector.MockAgent.TestHelpers
|
||||||
import Test.Hspec
|
import Test.Hspec
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
@ -107,38 +109,38 @@ tests _opts = do
|
|||||||
{ API._morAffectedRows = 3,
|
{ API._morAffectedRows = 3,
|
||||||
API._morReturning =
|
API._morReturning =
|
||||||
Just
|
Just
|
||||||
[ HashMap.fromList
|
[ mkFieldsMap
|
||||||
[ (API.FieldName "deletedRows_AlbumId", API.mkColumnFieldValue $ Aeson.Number 112),
|
[ ("deletedRows_AlbumId", API.mkColumnFieldValue $ Aeson.Number 112),
|
||||||
(API.FieldName "deletedRows_Title", API.mkColumnFieldValue $ Aeson.String "The Number of The Beast"),
|
("deletedRows_Title", API.mkColumnFieldValue $ Aeson.String "The Number of The Beast"),
|
||||||
( API.FieldName "deletedRows_Artist",
|
( "deletedRows_Artist",
|
||||||
API.mkRelationshipFieldValue $
|
API.mkRelationshipFieldValue $
|
||||||
rowsResponse
|
mkRowsQueryResponse
|
||||||
[ [ (API.FieldName "ArtistId", API.mkColumnFieldValue $ Aeson.Number 90),
|
[ [ ("ArtistId", API.mkColumnFieldValue $ Aeson.Number 90),
|
||||||
(API.FieldName "Name", API.mkColumnFieldValue $ Aeson.String "Iron Maiden")
|
("Name", API.mkColumnFieldValue $ Aeson.String "Iron Maiden")
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
HashMap.fromList
|
mkFieldsMap
|
||||||
[ (API.FieldName "deletedRows_AlbumId", API.mkColumnFieldValue $ Aeson.Number 113),
|
[ ("deletedRows_AlbumId", API.mkColumnFieldValue $ Aeson.Number 113),
|
||||||
(API.FieldName "deletedRows_Title", API.mkColumnFieldValue $ Aeson.String "The X Factor"),
|
("deletedRows_Title", API.mkColumnFieldValue $ Aeson.String "The X Factor"),
|
||||||
( API.FieldName "deletedRows_Artist",
|
( "deletedRows_Artist",
|
||||||
API.mkRelationshipFieldValue $
|
API.mkRelationshipFieldValue $
|
||||||
rowsResponse
|
mkRowsQueryResponse
|
||||||
[ [ (API.FieldName "ArtistId", API.mkColumnFieldValue $ Aeson.Number 90),
|
[ [ ("ArtistId", API.mkColumnFieldValue $ Aeson.Number 90),
|
||||||
(API.FieldName "Name", API.mkColumnFieldValue $ Aeson.String "Iron Maiden")
|
("Name", API.mkColumnFieldValue $ Aeson.String "Iron Maiden")
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
HashMap.fromList
|
mkFieldsMap
|
||||||
[ (API.FieldName "deletedRows_AlbumId", API.mkColumnFieldValue $ Aeson.Number 114),
|
[ ("deletedRows_AlbumId", API.mkColumnFieldValue $ Aeson.Number 114),
|
||||||
(API.FieldName "deletedRows_Title", API.mkColumnFieldValue $ Aeson.String "Virtual XI"),
|
("deletedRows_Title", API.mkColumnFieldValue $ Aeson.String "Virtual XI"),
|
||||||
( API.FieldName "deletedRows_Artist",
|
( "deletedRows_Artist",
|
||||||
API.mkRelationshipFieldValue $
|
API.mkRelationshipFieldValue $
|
||||||
rowsResponse
|
mkRowsQueryResponse
|
||||||
[ [ (API.FieldName "ArtistId", API.mkColumnFieldValue $ Aeson.Number 90),
|
[ [ ("ArtistId", API.mkColumnFieldValue $ Aeson.Number 90),
|
||||||
(API.FieldName "Name", API.mkColumnFieldValue $ Aeson.String "Iron Maiden")
|
("Name", API.mkColumnFieldValue $ Aeson.String "Iron Maiden")
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
@ -174,66 +176,58 @@ tests _opts = do
|
|||||||
|]
|
|]
|
||||||
|
|
||||||
let expectedRequest =
|
let expectedRequest =
|
||||||
API.MutationRequest
|
emptyMutationRequest
|
||||||
{ API._mrTableRelationships =
|
& API.mrTableRelationships
|
||||||
[ API.TableRelationships
|
.~ [ API.TableRelationships
|
||||||
{ API._trSourceTable = API.TableName ("Album" :| []),
|
{ API._trSourceTable = mkTableName "Album",
|
||||||
API._trRelationships =
|
API._trRelationships =
|
||||||
HashMap.fromList
|
HashMap.fromList
|
||||||
[ ( API.RelationshipName "Artist",
|
[ ( API.RelationshipName "Artist",
|
||||||
API.Relationship
|
API.Relationship
|
||||||
{ API._rTargetTable = API.TableName ("Artist" :| []),
|
{ API._rTargetTable = mkTableName "Artist",
|
||||||
API._rRelationshipType = API.ObjectRelationship,
|
API._rRelationshipType = API.ObjectRelationship,
|
||||||
API._rColumnMapping = HashMap.fromList [(API.ColumnName "ArtistId", API.ColumnName "ArtistId")]
|
API._rColumnMapping = HashMap.fromList [(API.ColumnName "ArtistId", API.ColumnName "ArtistId")]
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
API._mrInsertSchema = [],
|
& API.mrOperations
|
||||||
API._mrOperations =
|
.~ [ API.DeleteOperation $
|
||||||
[ API.DeleteOperation $
|
API.DeleteMutationOperation
|
||||||
API.DeleteMutationOperation
|
{ API._dmoTable = mkTableName "Album",
|
||||||
{ API._dmoTable = API.TableName ("Album" :| []),
|
API._dmoWhere =
|
||||||
API._dmoWhere =
|
Just $
|
||||||
Just $
|
API.And
|
||||||
API.And
|
[ API.ApplyBinaryComparisonOperator
|
||||||
[ API.ApplyBinaryComparisonOperator
|
API.Equal
|
||||||
API.Equal
|
(API.ComparisonColumn API.CurrentTable (API.ColumnName "ArtistId") $ API.ScalarType "number")
|
||||||
(API.ComparisonColumn API.CurrentTable (API.ColumnName "ArtistId") $ API.ScalarType "number")
|
(API.ScalarValueComparison $ API.ScalarValue (Aeson.Number 90) (API.ScalarType "number")),
|
||||||
(API.ScalarValueComparison $ API.ScalarValue (Aeson.Number 90) (API.ScalarType "number")),
|
API.ApplyBinaryComparisonOperator
|
||||||
API.ApplyBinaryComparisonOperator
|
API.GreaterThan
|
||||||
API.GreaterThan
|
(API.ComparisonColumn API.CurrentTable (API.ColumnName "AlbumId") $ API.ScalarType "number")
|
||||||
(API.ComparisonColumn API.CurrentTable (API.ColumnName "AlbumId") $ API.ScalarType "number")
|
(API.ScalarValueComparison $ API.ScalarValue (Aeson.Number 111) (API.ScalarType "number"))
|
||||||
(API.ScalarValueComparison $ API.ScalarValue (Aeson.Number 111) (API.ScalarType "number"))
|
],
|
||||||
],
|
API._dmoReturningFields =
|
||||||
API._dmoReturningFields =
|
mkFieldsMap
|
||||||
HashMap.fromList
|
[ ("deletedRows_AlbumId", API.ColumnField (API.ColumnName "AlbumId") (API.ScalarType "number")),
|
||||||
[ (API.FieldName "deletedRows_AlbumId", API.ColumnField (API.ColumnName "AlbumId") (API.ScalarType "number")),
|
("deletedRows_Title", API.ColumnField (API.ColumnName "Title") (API.ScalarType "string")),
|
||||||
(API.FieldName "deletedRows_Title", API.ColumnField (API.ColumnName "Title") (API.ScalarType "string")),
|
( "deletedRows_Artist",
|
||||||
( API.FieldName "deletedRows_Artist",
|
API.RelField
|
||||||
API.RelField
|
( API.RelationshipField
|
||||||
( API.RelationshipField
|
(API.RelationshipName "Artist")
|
||||||
(API.RelationshipName "Artist")
|
( emptyQuery
|
||||||
API.Query
|
& API.qFields
|
||||||
{ _qFields =
|
?~ mkFieldsMap
|
||||||
Just $
|
[ ("ArtistId", API.ColumnField (API.ColumnName "ArtistId") $ API.ScalarType "number"),
|
||||||
HashMap.fromList
|
("Name", API.ColumnField (API.ColumnName "Name") $ API.ScalarType "string")
|
||||||
[ (API.FieldName "ArtistId", API.ColumnField (API.ColumnName "ArtistId") $ API.ScalarType "number"),
|
]
|
||||||
(API.FieldName "Name", API.ColumnField (API.ColumnName "Name") $ API.ScalarType "string")
|
)
|
||||||
],
|
)
|
||||||
_qAggregates = Nothing,
|
)
|
||||||
_qLimit = Nothing,
|
]
|
||||||
_qOffset = Nothing,
|
}
|
||||||
_qWhere = Nothing,
|
]
|
||||||
_qOrderBy = Nothing
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
_mrrRecordedRequest `shouldBe` Just (Mutation expectedRequest)
|
_mrrRecordedRequest `shouldBe` Just (Mutation expectedRequest)
|
||||||
|
|
||||||
mockAgentGraphqlTest "delete row by pk with delete permissions" $ \_testEnv performGraphqlRequest -> do
|
mockAgentGraphqlTest "delete row by pk with delete permissions" $ \_testEnv performGraphqlRequest -> do
|
||||||
@ -257,14 +251,14 @@ tests _opts = do
|
|||||||
{ API._morAffectedRows = 1,
|
{ API._morAffectedRows = 1,
|
||||||
API._morReturning =
|
API._morReturning =
|
||||||
Just
|
Just
|
||||||
[ HashMap.fromList
|
[ mkFieldsMap
|
||||||
[ (API.FieldName "AlbumId", API.mkColumnFieldValue $ Aeson.Number 112),
|
[ ("AlbumId", API.mkColumnFieldValue $ Aeson.Number 112),
|
||||||
(API.FieldName "Title", API.mkColumnFieldValue $ Aeson.String "The Number of The Beast"),
|
("Title", API.mkColumnFieldValue $ Aeson.String "The Number of The Beast"),
|
||||||
( API.FieldName "Artist",
|
( "Artist",
|
||||||
API.mkRelationshipFieldValue $
|
API.mkRelationshipFieldValue $
|
||||||
rowsResponse
|
mkRowsQueryResponse
|
||||||
[ [ (API.FieldName "ArtistId", API.mkColumnFieldValue $ Aeson.Number 90),
|
[ [ ("ArtistId", API.mkColumnFieldValue $ Aeson.Number 90),
|
||||||
(API.FieldName "Name", API.mkColumnFieldValue $ Aeson.String "Iron Maiden")
|
("Name", API.mkColumnFieldValue $ Aeson.String "Iron Maiden")
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
@ -288,67 +282,56 @@ tests _opts = do
|
|||||||
|]
|
|]
|
||||||
|
|
||||||
let expectedRequest =
|
let expectedRequest =
|
||||||
API.MutationRequest
|
emptyMutationRequest
|
||||||
{ API._mrTableRelationships =
|
& API.mrTableRelationships
|
||||||
[ API.TableRelationships
|
.~ [ API.TableRelationships
|
||||||
{ API._trSourceTable = API.TableName ("Album" :| []),
|
{ API._trSourceTable = mkTableName "Album",
|
||||||
API._trRelationships =
|
API._trRelationships =
|
||||||
HashMap.fromList
|
HashMap.fromList
|
||||||
[ ( API.RelationshipName "Artist",
|
[ ( API.RelationshipName "Artist",
|
||||||
API.Relationship
|
API.Relationship
|
||||||
{ API._rTargetTable = API.TableName ("Artist" :| []),
|
{ API._rTargetTable = mkTableName "Artist",
|
||||||
API._rRelationshipType = API.ObjectRelationship,
|
API._rRelationshipType = API.ObjectRelationship,
|
||||||
API._rColumnMapping = HashMap.fromList [(API.ColumnName "ArtistId", API.ColumnName "ArtistId")]
|
API._rColumnMapping = HashMap.fromList [(API.ColumnName "ArtistId", API.ColumnName "ArtistId")]
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
API._mrInsertSchema = [],
|
& API.mrOperations
|
||||||
API._mrOperations =
|
.~ [ API.DeleteOperation $
|
||||||
[ API.DeleteOperation $
|
API.DeleteMutationOperation
|
||||||
API.DeleteMutationOperation
|
{ API._dmoTable = mkTableName "Album",
|
||||||
{ API._dmoTable = API.TableName ("Album" :| []),
|
API._dmoWhere =
|
||||||
API._dmoWhere =
|
Just $
|
||||||
Just $
|
API.And
|
||||||
API.And
|
[ API.ApplyBinaryComparisonOperator
|
||||||
[ API.ApplyBinaryComparisonOperator
|
API.Equal
|
||||||
API.Equal
|
(API.ComparisonColumn API.CurrentTable (API.ColumnName "ArtistId") $ API.ScalarType "number")
|
||||||
(API.ComparisonColumn API.CurrentTable (API.ColumnName "ArtistId") $ API.ScalarType "number")
|
(API.ScalarValueComparison $ API.ScalarValue (Aeson.Number 90) (API.ScalarType "number")),
|
||||||
(API.ScalarValueComparison $ API.ScalarValue (Aeson.Number 90) (API.ScalarType "number")),
|
API.ApplyBinaryComparisonOperator
|
||||||
API.ApplyBinaryComparisonOperator
|
API.Equal
|
||||||
API.Equal
|
(API.ComparisonColumn API.CurrentTable (API.ColumnName "AlbumId") $ API.ScalarType "number")
|
||||||
(API.ComparisonColumn API.CurrentTable (API.ColumnName "AlbumId") $ API.ScalarType "number")
|
(API.ScalarValueComparison $ API.ScalarValue (Aeson.Number 112) (API.ScalarType "number"))
|
||||||
(API.ScalarValueComparison $ API.ScalarValue (Aeson.Number 112) (API.ScalarType "number"))
|
],
|
||||||
],
|
API._dmoReturningFields =
|
||||||
API._dmoReturningFields =
|
mkFieldsMap
|
||||||
HashMap.fromList
|
[ ("AlbumId", API.ColumnField (API.ColumnName "AlbumId") (API.ScalarType "number")),
|
||||||
[ (API.FieldName "AlbumId", API.ColumnField (API.ColumnName "AlbumId") (API.ScalarType "number")),
|
("Title", API.ColumnField (API.ColumnName "Title") (API.ScalarType "string")),
|
||||||
(API.FieldName "Title", API.ColumnField (API.ColumnName "Title") (API.ScalarType "string")),
|
( "Artist",
|
||||||
( API.FieldName "Artist",
|
API.RelField
|
||||||
API.RelField
|
( API.RelationshipField
|
||||||
( API.RelationshipField
|
(API.RelationshipName "Artist")
|
||||||
(API.RelationshipName "Artist")
|
( emptyQuery
|
||||||
API.Query
|
& API.qFields
|
||||||
{ _qFields =
|
?~ mkFieldsMap
|
||||||
Just $
|
[ ("ArtistId", API.ColumnField (API.ColumnName "ArtistId") $ API.ScalarType "number"),
|
||||||
HashMap.fromList
|
("Name", API.ColumnField (API.ColumnName "Name") $ API.ScalarType "string")
|
||||||
[ (API.FieldName "ArtistId", API.ColumnField (API.ColumnName "ArtistId") $ API.ScalarType "number"),
|
]
|
||||||
(API.FieldName "Name", API.ColumnField (API.ColumnName "Name") $ API.ScalarType "string")
|
)
|
||||||
],
|
)
|
||||||
_qAggregates = Nothing,
|
)
|
||||||
_qLimit = Nothing,
|
]
|
||||||
_qOffset = Nothing,
|
}
|
||||||
_qWhere = Nothing,
|
]
|
||||||
_qOrderBy = Nothing
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
_mrrRecordedRequest `shouldBe` Just (Mutation expectedRequest)
|
_mrrRecordedRequest `shouldBe` Just (Mutation expectedRequest)
|
||||||
|
|
||||||
rowsResponse :: [[(API.FieldName, API.FieldValue)]] -> API.QueryResponse
|
|
||||||
rowsResponse rows = API.QueryResponse (Just $ HashMap.fromList <$> rows) Nothing
|
|
||||||
|
@ -6,8 +6,8 @@ module Test.DataConnector.MockAgent.ErrorSpec (spec) where
|
|||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
import Control.Lens ((?~))
|
||||||
import Data.Aeson qualified as Aeson
|
import Data.Aeson qualified as Aeson
|
||||||
import Data.HashMap.Strict qualified as HashMap
|
|
||||||
import Data.List.NonEmpty qualified as NE
|
import Data.List.NonEmpty qualified as NE
|
||||||
import Harness.Backend.DataConnector.Mock (AgentRequest (..), MockRequestResults (..), mockAgentGraphqlTest)
|
import Harness.Backend.DataConnector.Mock (AgentRequest (..), MockRequestResults (..), mockAgentGraphqlTest)
|
||||||
import Harness.Backend.DataConnector.Mock qualified as Mock
|
import Harness.Backend.DataConnector.Mock qualified as Mock
|
||||||
@ -19,6 +19,7 @@ import Harness.TestEnvironment (GlobalTestEnvironment, TestEnvironment)
|
|||||||
import Harness.Yaml (shouldBeYaml)
|
import Harness.Yaml (shouldBeYaml)
|
||||||
import Hasura.Backends.DataConnector.API qualified as API
|
import Hasura.Backends.DataConnector.API qualified as API
|
||||||
import Hasura.Prelude
|
import Hasura.Prelude
|
||||||
|
import Test.DataConnector.MockAgent.TestHelpers
|
||||||
import Test.Hspec (SpecWith, describe, shouldBe)
|
import Test.Hspec (SpecWith, describe, shouldBe)
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
@ -92,23 +93,14 @@ tests _opts = describe "Error Protocol Tests" $ do
|
|||||||
_mrrRecordedRequest
|
_mrrRecordedRequest
|
||||||
`shouldBe` Just
|
`shouldBe` Just
|
||||||
( Query $
|
( Query $
|
||||||
API.QueryRequest
|
mkQueryRequest
|
||||||
{ _qrTable = API.TableName ("Album" :| []),
|
(mkTableName "Album")
|
||||||
_qrTableRelationships = [],
|
( emptyQuery
|
||||||
_qrQuery =
|
& API.qFields
|
||||||
API.Query
|
?~ mkFieldsMap
|
||||||
{ _qFields =
|
[ ("id", API.ColumnField (API.ColumnName "AlbumId") $ API.ScalarType "number"),
|
||||||
Just $
|
("title", API.ColumnField (API.ColumnName "Title") $ API.ScalarType "string")
|
||||||
HashMap.fromList
|
]
|
||||||
[ (API.FieldName "id", API.ColumnField (API.ColumnName "AlbumId") $ API.ScalarType "number"),
|
& API.qLimit ?~ 1
|
||||||
(API.FieldName "title", API.ColumnField (API.ColumnName "Title") $ API.ScalarType "string")
|
)
|
||||||
],
|
|
||||||
_qAggregates = Nothing,
|
|
||||||
_qLimit = Just 1,
|
|
||||||
_qOffset = Nothing,
|
|
||||||
_qWhere = Nothing,
|
|
||||||
_qOrderBy = Nothing
|
|
||||||
},
|
|
||||||
_qrForeach = Nothing
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
@ -3,6 +3,7 @@ module Test.DataConnector.MockAgent.InsertMutationsSpec
|
|||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
|
import Control.Lens ((.~), (?~))
|
||||||
import Data.Aeson qualified as Aeson
|
import Data.Aeson qualified as Aeson
|
||||||
import Data.ByteString (ByteString)
|
import Data.ByteString (ByteString)
|
||||||
import Data.HashMap.Strict qualified as HashMap
|
import Data.HashMap.Strict qualified as HashMap
|
||||||
@ -17,6 +18,7 @@ import Harness.TestEnvironment (GlobalTestEnvironment, TestEnvironment)
|
|||||||
import Harness.Yaml
|
import Harness.Yaml
|
||||||
import Hasura.Backends.DataConnector.API qualified as API
|
import Hasura.Backends.DataConnector.API qualified as API
|
||||||
import Hasura.Prelude
|
import Hasura.Prelude
|
||||||
|
import Test.DataConnector.MockAgent.TestHelpers
|
||||||
import Test.Hspec
|
import Test.Hspec
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
@ -116,26 +118,26 @@ tests _opts = do
|
|||||||
{ API._morAffectedRows = 2,
|
{ API._morAffectedRows = 2,
|
||||||
API._morReturning =
|
API._morReturning =
|
||||||
Just
|
Just
|
||||||
[ HashMap.fromList
|
[ mkFieldsMap
|
||||||
[ (API.FieldName "insertedRows_AlbumId", API.mkColumnFieldValue $ Aeson.Number 9001),
|
[ ("insertedRows_AlbumId", API.mkColumnFieldValue $ Aeson.Number 9001),
|
||||||
(API.FieldName "insertedRows_Title", API.mkColumnFieldValue $ Aeson.String "Super Mega Rock"),
|
("insertedRows_Title", API.mkColumnFieldValue $ Aeson.String "Super Mega Rock"),
|
||||||
( API.FieldName "insertedRows_Artist",
|
( "insertedRows_Artist",
|
||||||
API.mkRelationshipFieldValue $
|
API.mkRelationshipFieldValue $
|
||||||
rowsResponse
|
mkRowsQueryResponse
|
||||||
[ [ (API.FieldName "ArtistId", API.mkColumnFieldValue $ Aeson.Number 2),
|
[ [ ("ArtistId", API.mkColumnFieldValue $ Aeson.Number 2),
|
||||||
(API.FieldName "Name", API.mkColumnFieldValue $ Aeson.String "Accept")
|
("Name", API.mkColumnFieldValue $ Aeson.String "Accept")
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
HashMap.fromList
|
mkFieldsMap
|
||||||
[ (API.FieldName "insertedRows_AlbumId", API.mkColumnFieldValue $ Aeson.Number 9002),
|
[ ("insertedRows_AlbumId", API.mkColumnFieldValue $ Aeson.Number 9002),
|
||||||
(API.FieldName "insertedRows_Title", API.mkColumnFieldValue $ Aeson.String "Accept This"),
|
("insertedRows_Title", API.mkColumnFieldValue $ Aeson.String "Accept This"),
|
||||||
( API.FieldName "insertedRows_Artist",
|
( "insertedRows_Artist",
|
||||||
API.mkRelationshipFieldValue $
|
API.mkRelationshipFieldValue $
|
||||||
rowsResponse
|
mkRowsQueryResponse
|
||||||
[ [ (API.FieldName "ArtistId", API.mkColumnFieldValue $ Aeson.Number 2),
|
[ [ ("ArtistId", API.mkColumnFieldValue $ Aeson.Number 2),
|
||||||
(API.FieldName "Name", API.mkColumnFieldValue $ Aeson.String "Accept")
|
("Name", API.mkColumnFieldValue $ Aeson.String "Accept")
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
@ -166,85 +168,75 @@ tests _opts = do
|
|||||||
|]
|
|]
|
||||||
|
|
||||||
let expectedRequest =
|
let expectedRequest =
|
||||||
API.MutationRequest
|
emptyMutationRequest
|
||||||
{ API._mrTableRelationships =
|
& API.mrTableRelationships
|
||||||
[ API.TableRelationships
|
.~ [ API.TableRelationships
|
||||||
{ API._trSourceTable = API.TableName ("Album" :| []),
|
{ API._trSourceTable = mkTableName "Album",
|
||||||
API._trRelationships =
|
API._trRelationships =
|
||||||
HashMap.fromList
|
HashMap.fromList
|
||||||
[ ( API.RelationshipName "Artist",
|
[ ( API.RelationshipName "Artist",
|
||||||
API.Relationship
|
API.Relationship
|
||||||
{ API._rTargetTable = API.TableName ("Artist" :| []),
|
{ API._rTargetTable = mkTableName "Artist",
|
||||||
API._rRelationshipType = API.ObjectRelationship,
|
API._rRelationshipType = API.ObjectRelationship,
|
||||||
API._rColumnMapping = HashMap.fromList [(API.ColumnName "ArtistId", API.ColumnName "ArtistId")]
|
API._rColumnMapping = HashMap.fromList [(API.ColumnName "ArtistId", API.ColumnName "ArtistId")]
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
API._mrInsertSchema =
|
& API.mrInsertSchema
|
||||||
[ API.TableInsertSchema
|
.~ [ API.TableInsertSchema
|
||||||
{ API._tisTable = API.TableName ("Album" :| []),
|
{ API._tisTable = mkTableName "Album",
|
||||||
API._tisFields =
|
API._tisFields =
|
||||||
HashMap.fromList
|
mkFieldsMap
|
||||||
[ (API.FieldName "AlbumId", API.ColumnInsert $ API.ColumnInsertSchema (API.ColumnName "AlbumId") (API.ScalarType "number")),
|
[ ("AlbumId", API.ColumnInsert $ API.ColumnInsertSchema (API.ColumnName "AlbumId") (API.ScalarType "number")),
|
||||||
(API.FieldName "ArtistId", API.ColumnInsert $ API.ColumnInsertSchema (API.ColumnName "ArtistId") (API.ScalarType "number")),
|
("ArtistId", API.ColumnInsert $ API.ColumnInsertSchema (API.ColumnName "ArtistId") (API.ScalarType "number")),
|
||||||
(API.FieldName "Title", API.ColumnInsert $ API.ColumnInsertSchema (API.ColumnName "Title") (API.ScalarType "string"))
|
("Title", API.ColumnInsert $ API.ColumnInsertSchema (API.ColumnName "Title") (API.ScalarType "string"))
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
API._mrOperations =
|
& API.mrOperations
|
||||||
[ API.InsertOperation $
|
.~ [ API.InsertOperation $
|
||||||
API.InsertMutationOperation
|
API.InsertMutationOperation
|
||||||
{ API._imoTable = API.TableName ("Album" :| []),
|
{ API._imoTable = mkTableName "Album",
|
||||||
API._imoRows =
|
API._imoRows =
|
||||||
[ API.RowObject $
|
[ API.RowObject $
|
||||||
HashMap.fromList
|
mkFieldsMap
|
||||||
[ (API.FieldName "AlbumId", API.mkColumnInsertFieldValue $ Aeson.Number 9001),
|
[ ("AlbumId", API.mkColumnInsertFieldValue $ Aeson.Number 9001),
|
||||||
(API.FieldName "ArtistId", API.mkColumnInsertFieldValue $ Aeson.Number 2),
|
("ArtistId", API.mkColumnInsertFieldValue $ Aeson.Number 2),
|
||||||
(API.FieldName "Title", API.mkColumnInsertFieldValue $ Aeson.String "Super Mega Rock")
|
("Title", API.mkColumnInsertFieldValue $ Aeson.String "Super Mega Rock")
|
||||||
],
|
],
|
||||||
API.RowObject $
|
API.RowObject $
|
||||||
HashMap.fromList
|
mkFieldsMap
|
||||||
[ (API.FieldName "AlbumId", API.mkColumnInsertFieldValue $ Aeson.Number 9002),
|
[ ("AlbumId", API.mkColumnInsertFieldValue $ Aeson.Number 9002),
|
||||||
(API.FieldName "ArtistId", API.mkColumnInsertFieldValue $ Aeson.Number 2),
|
("ArtistId", API.mkColumnInsertFieldValue $ Aeson.Number 2),
|
||||||
(API.FieldName "Title", API.mkColumnInsertFieldValue $ Aeson.String "Accept This")
|
("Title", API.mkColumnInsertFieldValue $ Aeson.String "Accept This")
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
API._imoPostInsertCheck =
|
API._imoPostInsertCheck =
|
||||||
Just $
|
Just $
|
||||||
API.ApplyBinaryComparisonOperator
|
API.ApplyBinaryComparisonOperator
|
||||||
API.Equal
|
API.Equal
|
||||||
(API.ComparisonColumn API.CurrentTable (API.ColumnName "ArtistId") $ API.ScalarType "number")
|
(API.ComparisonColumn API.CurrentTable (API.ColumnName "ArtistId") $ API.ScalarType "number")
|
||||||
(API.ScalarValueComparison $ API.ScalarValue (Aeson.Number 2) (API.ScalarType "number")),
|
(API.ScalarValueComparison $ API.ScalarValue (Aeson.Number 2) (API.ScalarType "number")),
|
||||||
API._imoReturningFields =
|
API._imoReturningFields =
|
||||||
HashMap.fromList
|
mkFieldsMap
|
||||||
[ (API.FieldName "insertedRows_AlbumId", API.ColumnField (API.ColumnName "AlbumId") (API.ScalarType "number")),
|
[ ("insertedRows_AlbumId", API.ColumnField (API.ColumnName "AlbumId") (API.ScalarType "number")),
|
||||||
(API.FieldName "insertedRows_Title", API.ColumnField (API.ColumnName "Title") (API.ScalarType "string")),
|
("insertedRows_Title", API.ColumnField (API.ColumnName "Title") (API.ScalarType "string")),
|
||||||
( API.FieldName "insertedRows_Artist",
|
( "insertedRows_Artist",
|
||||||
API.RelField
|
API.RelField
|
||||||
( API.RelationshipField
|
( API.RelationshipField
|
||||||
(API.RelationshipName "Artist")
|
(API.RelationshipName "Artist")
|
||||||
API.Query
|
( emptyQuery
|
||||||
{ _qFields =
|
& API.qFields
|
||||||
Just $
|
?~ mkFieldsMap
|
||||||
HashMap.fromList
|
[ ("ArtistId", API.ColumnField (API.ColumnName "ArtistId") $ API.ScalarType "number"),
|
||||||
[ (API.FieldName "ArtistId", API.ColumnField (API.ColumnName "ArtistId") $ API.ScalarType "number"),
|
("Name", API.ColumnField (API.ColumnName "Name") $ API.ScalarType "string")
|
||||||
(API.FieldName "Name", API.ColumnField (API.ColumnName "Name") $ API.ScalarType "string")
|
]
|
||||||
],
|
)
|
||||||
_qAggregates = Nothing,
|
)
|
||||||
_qLimit = Nothing,
|
)
|
||||||
_qOffset = Nothing,
|
]
|
||||||
_qWhere = Nothing,
|
}
|
||||||
_qOrderBy = Nothing
|
]
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
_mrrRecordedRequest `shouldBe` Just (Mutation expectedRequest)
|
_mrrRecordedRequest `shouldBe` Just (Mutation expectedRequest)
|
||||||
|
|
||||||
rowsResponse :: [[(API.FieldName, API.FieldValue)]] -> API.QueryResponse
|
|
||||||
rowsResponse rows = API.QueryResponse (Just $ HashMap.fromList <$> rows) Nothing
|
|
||||||
|
@ -5,6 +5,7 @@ module Test.DataConnector.MockAgent.OrderBySpec (spec) where
|
|||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
import Control.Lens ((.~), (?~))
|
||||||
import Data.Aeson qualified as Aeson
|
import Data.Aeson qualified as Aeson
|
||||||
import Data.HashMap.Strict qualified as HashMap
|
import Data.HashMap.Strict qualified as HashMap
|
||||||
import Data.List.NonEmpty qualified as NE
|
import Data.List.NonEmpty qualified as NE
|
||||||
@ -19,6 +20,7 @@ import Harness.Yaml (shouldBeYaml)
|
|||||||
import Hasura.Backends.DataConnector.API qualified as API
|
import Hasura.Backends.DataConnector.API qualified as API
|
||||||
import Hasura.Prelude
|
import Hasura.Prelude
|
||||||
import Language.GraphQL.Draft.Syntax.QQ qualified as G
|
import Language.GraphQL.Draft.Syntax.QQ qualified as G
|
||||||
|
import Test.DataConnector.MockAgent.TestHelpers
|
||||||
import Test.Hspec (SpecWith, describe, shouldBe)
|
import Test.Hspec (SpecWith, describe, shouldBe)
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
@ -111,25 +113,17 @@ tests _opts = describe "Order By Tests" $ do
|
|||||||
_mrrRecordedRequest
|
_mrrRecordedRequest
|
||||||
`shouldBe` Just
|
`shouldBe` Just
|
||||||
( Query $
|
( Query $
|
||||||
API.QueryRequest
|
mkQueryRequest
|
||||||
{ _qrTable = API.TableName ("Album" :| []),
|
(mkTableName "Album")
|
||||||
_qrTableRelationships = [],
|
( emptyQuery
|
||||||
_qrQuery =
|
& API.qFields
|
||||||
API.Query
|
?~ mkFieldsMap
|
||||||
{ _qFields =
|
[ ("AlbumId", API.ColumnField (API.ColumnName "AlbumId") $ API.ScalarType "number"),
|
||||||
Just $
|
("Title", API.ColumnField (API.ColumnName "Title") $ API.ScalarType "string")
|
||||||
HashMap.fromList
|
]
|
||||||
[ (API.FieldName "AlbumId", API.ColumnField (API.ColumnName "AlbumId") $ API.ScalarType "number"),
|
& API.qLimit ?~ 3
|
||||||
(API.FieldName "Title", API.ColumnField (API.ColumnName "Title") $ API.ScalarType "string")
|
& API.qOrderBy ?~ API.OrderBy mempty (API.OrderByElement [] (API.OrderByColumn (API.ColumnName "AlbumId")) API.Ascending :| [])
|
||||||
],
|
)
|
||||||
_qAggregates = Nothing,
|
|
||||||
_qLimit = Just 3,
|
|
||||||
_qOffset = Nothing,
|
|
||||||
_qWhere = Nothing,
|
|
||||||
_qOrderBy = Just (API.OrderBy mempty (API.OrderByElement [] (API.OrderByColumn (API.ColumnName "AlbumId")) API.Ascending :| []))
|
|
||||||
},
|
|
||||||
_qrForeach = Nothing
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
mockAgentGraphqlTest "can order by aggregates" $ \_testEnv performGraphqlRequest -> do
|
mockAgentGraphqlTest "can order by aggregates" $ \_testEnv performGraphqlRequest -> do
|
||||||
@ -162,59 +156,48 @@ tests _opts = describe "Order By Tests" $ do
|
|||||||
_mrrRecordedRequest
|
_mrrRecordedRequest
|
||||||
`shouldBe` Just
|
`shouldBe` Just
|
||||||
( Query $
|
( Query $
|
||||||
API.QueryRequest
|
mkQueryRequest
|
||||||
{ _qrTable = API.TableName ("Artist" :| []),
|
(mkTableName "Artist")
|
||||||
_qrTableRelationships =
|
( emptyQuery
|
||||||
[ API.TableRelationships
|
& API.qFields ?~ mkFieldsMap [("Name", API.ColumnField (API.ColumnName "Name") (API.ScalarType "string"))]
|
||||||
{ _trSourceTable = API.TableName ("Artist" :| []),
|
& API.qLimit ?~ 2
|
||||||
_trRelationships =
|
& API.qOrderBy
|
||||||
HashMap.fromList
|
?~ API.OrderBy
|
||||||
[ ( API.RelationshipName "Albums",
|
( HashMap.fromList
|
||||||
API.Relationship
|
[ ( API.RelationshipName "Albums",
|
||||||
{ _rTargetTable = API.TableName ("Album" :| []),
|
API.OrderByRelation Nothing mempty
|
||||||
_rRelationshipType = API.ArrayRelationship,
|
)
|
||||||
_rColumnMapping = HashMap.fromList [(API.ColumnName "ArtistId", API.ColumnName "ArtistId")]
|
]
|
||||||
}
|
)
|
||||||
|
( NE.fromList
|
||||||
|
[ API.OrderByElement [API.RelationshipName "Albums"] API.OrderByStarCountAggregate API.Ascending,
|
||||||
|
API.OrderByElement
|
||||||
|
[API.RelationshipName "Albums"]
|
||||||
|
( API.OrderBySingleColumnAggregate $
|
||||||
|
API.SingleColumnAggregate
|
||||||
|
(API.SingleColumnAggregateFunction [G.name|max|])
|
||||||
|
(API.ColumnName "AlbumId")
|
||||||
|
(API.ScalarType "number")
|
||||||
)
|
)
|
||||||
]
|
API.Ascending
|
||||||
}
|
]
|
||||||
],
|
)
|
||||||
_qrQuery =
|
)
|
||||||
API.Query
|
& API.qrTableRelationships
|
||||||
{ _qFields =
|
.~ [ API.TableRelationships
|
||||||
Just $
|
{ _trSourceTable = mkTableName "Artist",
|
||||||
HashMap.fromList
|
_trRelationships =
|
||||||
[ (API.FieldName "Name", API.ColumnField (API.ColumnName "Name") (API.ScalarType "string"))
|
HashMap.fromList
|
||||||
],
|
[ ( API.RelationshipName "Albums",
|
||||||
_qAggregates = Nothing,
|
API.Relationship
|
||||||
_qLimit = Just 2,
|
{ _rTargetTable = mkTableName "Album",
|
||||||
_qOffset = Nothing,
|
_rRelationshipType = API.ArrayRelationship,
|
||||||
_qWhere = Nothing,
|
_rColumnMapping = HashMap.fromList [(API.ColumnName "ArtistId", API.ColumnName "ArtistId")]
|
||||||
_qOrderBy =
|
}
|
||||||
Just $
|
)
|
||||||
API.OrderBy
|
]
|
||||||
( HashMap.fromList
|
}
|
||||||
[ ( API.RelationshipName "Albums",
|
]
|
||||||
API.OrderByRelation Nothing mempty
|
|
||||||
)
|
|
||||||
]
|
|
||||||
)
|
|
||||||
( NE.fromList
|
|
||||||
[ API.OrderByElement [API.RelationshipName "Albums"] API.OrderByStarCountAggregate API.Ascending,
|
|
||||||
API.OrderByElement
|
|
||||||
[API.RelationshipName "Albums"]
|
|
||||||
( API.OrderBySingleColumnAggregate $
|
|
||||||
API.SingleColumnAggregate
|
|
||||||
(API.SingleColumnAggregateFunction [G.name|max|])
|
|
||||||
(API.ColumnName "AlbumId")
|
|
||||||
(API.ScalarType "number")
|
|
||||||
)
|
|
||||||
API.Ascending
|
|
||||||
]
|
|
||||||
)
|
|
||||||
},
|
|
||||||
_qrForeach = Nothing
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
rowsResponse :: [[(API.FieldName, API.FieldValue)]] -> API.QueryResponse
|
rowsResponse :: [[(API.FieldName, API.FieldValue)]] -> API.QueryResponse
|
||||||
|
@ -5,6 +5,7 @@ module Test.DataConnector.MockAgent.QueryRelationshipsSpec (spec) where
|
|||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
import Control.Lens ((.~), (?~))
|
||||||
import Data.Aeson qualified as Aeson
|
import Data.Aeson qualified as Aeson
|
||||||
import Data.ByteString (ByteString)
|
import Data.ByteString (ByteString)
|
||||||
import Data.HashMap.Strict qualified as HashMap
|
import Data.HashMap.Strict qualified as HashMap
|
||||||
@ -19,6 +20,7 @@ import Harness.TestEnvironment (GlobalTestEnvironment, TestEnvironment)
|
|||||||
import Harness.Yaml (shouldBeYaml)
|
import Harness.Yaml (shouldBeYaml)
|
||||||
import Hasura.Backends.DataConnector.API qualified as API
|
import Hasura.Backends.DataConnector.API qualified as API
|
||||||
import Hasura.Prelude
|
import Hasura.Prelude
|
||||||
|
import Test.DataConnector.MockAgent.TestHelpers
|
||||||
import Test.Hspec (SpecWith, describe, shouldBe)
|
import Test.Hspec (SpecWith, describe, shouldBe)
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
@ -145,18 +147,18 @@ tests _opts = describe "Object Relationships Tests" $ do
|
|||||||
}
|
}
|
||||||
|]
|
|]
|
||||||
let queryResponse =
|
let queryResponse =
|
||||||
rowsResponse
|
mkRowsQueryResponse
|
||||||
[ [ (API.FieldName "Name", API.mkColumnFieldValue $ Aeson.String "For Those About To Rock (We Salute You)"),
|
[ [ ("Name", API.mkColumnFieldValue $ Aeson.String "For Those About To Rock (We Salute You)"),
|
||||||
( API.FieldName "Genre",
|
( "Genre",
|
||||||
API.mkRelationshipFieldValue $
|
API.mkRelationshipFieldValue $
|
||||||
rowsResponse
|
mkRowsQueryResponse
|
||||||
[ [(API.FieldName "Name", API.mkColumnFieldValue $ Aeson.String "Rock")]
|
[ [("Name", API.mkColumnFieldValue $ Aeson.String "Rock")]
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
( API.FieldName "MediaType",
|
( "MediaType",
|
||||||
API.mkRelationshipFieldValue $
|
API.mkRelationshipFieldValue $
|
||||||
rowsResponse
|
mkRowsQueryResponse
|
||||||
[ [(API.FieldName "Name", API.mkColumnFieldValue $ Aeson.String "MPEG audio file")]
|
[ [("Name", API.mkColumnFieldValue $ Aeson.String "MPEG audio file")]
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
@ -179,83 +181,53 @@ tests _opts = describe "Object Relationships Tests" $ do
|
|||||||
_mrrRecordedRequest
|
_mrrRecordedRequest
|
||||||
`shouldBe` Just
|
`shouldBe` Just
|
||||||
( Query $
|
( Query $
|
||||||
API.QueryRequest
|
mkQueryRequest
|
||||||
{ _qrTable = API.TableName ("Track" :| []),
|
(mkTableName "Track")
|
||||||
_qrTableRelationships =
|
( emptyQuery
|
||||||
[ API.TableRelationships
|
& API.qFields
|
||||||
{ _trSourceTable = API.TableName ("Track" :| []),
|
?~ mkFieldsMap
|
||||||
_trRelationships =
|
[ ("Name", API.ColumnField (API.ColumnName "Name") $ API.ScalarType "string"),
|
||||||
HashMap.fromList
|
( "Genre",
|
||||||
[ ( API.RelationshipName "Genre",
|
API.RelField
|
||||||
API.Relationship
|
( API.RelationshipField
|
||||||
{ _rTargetTable = API.TableName ("Genre" :| []),
|
(API.RelationshipName "Genre")
|
||||||
_rRelationshipType = API.ObjectRelationship,
|
(emptyQuery & API.qFields ?~ mkFieldsMap [("Name", API.ColumnField (API.ColumnName "Name") $ API.ScalarType "string")])
|
||||||
_rColumnMapping = HashMap.fromList [(API.ColumnName "GenreId", API.ColumnName "GenreId")]
|
)
|
||||||
}
|
),
|
||||||
),
|
( "MediaType",
|
||||||
( API.RelationshipName "MediaType",
|
API.RelField
|
||||||
API.Relationship
|
( API.RelationshipField
|
||||||
{ _rTargetTable = API.TableName ("MediaType" :| []),
|
(API.RelationshipName "MediaType")
|
||||||
_rRelationshipType = API.ObjectRelationship,
|
(emptyQuery & API.qFields ?~ mkFieldsMap [("Name", API.ColumnField (API.ColumnName "Name") $ API.ScalarType "string")])
|
||||||
_rColumnMapping =
|
)
|
||||||
HashMap.fromList
|
)
|
||||||
[(API.ColumnName "MediaTypeId", API.ColumnName "MediaTypeId")]
|
]
|
||||||
}
|
& API.qLimit ?~ 1
|
||||||
)
|
)
|
||||||
]
|
& API.qrTableRelationships
|
||||||
}
|
.~ [ API.TableRelationships
|
||||||
],
|
{ _trSourceTable = mkTableName "Track",
|
||||||
_qrQuery =
|
_trRelationships =
|
||||||
API.Query
|
HashMap.fromList
|
||||||
{ _qFields =
|
[ ( API.RelationshipName "Genre",
|
||||||
Just $
|
API.Relationship
|
||||||
HashMap.fromList
|
{ _rTargetTable = mkTableName "Genre",
|
||||||
[ (API.FieldName "Name", API.ColumnField (API.ColumnName "Name") $ API.ScalarType "string"),
|
_rRelationshipType = API.ObjectRelationship,
|
||||||
( API.FieldName "Genre",
|
_rColumnMapping = HashMap.fromList [(API.ColumnName "GenreId", API.ColumnName "GenreId")]
|
||||||
API.RelField
|
}
|
||||||
( API.RelationshipField
|
),
|
||||||
(API.RelationshipName "Genre")
|
( API.RelationshipName "MediaType",
|
||||||
API.Query
|
API.Relationship
|
||||||
{ _qFields =
|
{ _rTargetTable = mkTableName "MediaType",
|
||||||
Just $
|
_rRelationshipType = API.ObjectRelationship,
|
||||||
HashMap.fromList
|
_rColumnMapping =
|
||||||
[ (API.FieldName "Name", API.ColumnField (API.ColumnName "Name") $ API.ScalarType "string")
|
HashMap.fromList
|
||||||
],
|
[(API.ColumnName "MediaTypeId", API.ColumnName "MediaTypeId")]
|
||||||
_qAggregates = Nothing,
|
}
|
||||||
_qLimit = Nothing,
|
)
|
||||||
_qOffset = Nothing,
|
]
|
||||||
_qWhere = Nothing,
|
}
|
||||||
_qOrderBy = Nothing
|
]
|
||||||
}
|
|
||||||
)
|
|
||||||
),
|
|
||||||
( API.FieldName "MediaType",
|
|
||||||
API.RelField
|
|
||||||
( API.RelationshipField
|
|
||||||
(API.RelationshipName "MediaType")
|
|
||||||
API.Query
|
|
||||||
{ _qFields =
|
|
||||||
Just $
|
|
||||||
HashMap.fromList
|
|
||||||
[ (API.FieldName "Name", API.ColumnField (API.ColumnName "Name") $ API.ScalarType "string")
|
|
||||||
],
|
|
||||||
_qAggregates = Nothing,
|
|
||||||
_qLimit = Nothing,
|
|
||||||
_qOffset = Nothing,
|
|
||||||
_qWhere = Nothing,
|
|
||||||
_qOrderBy = Nothing
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
],
|
|
||||||
_qAggregates = Nothing,
|
|
||||||
_qLimit = Just 1,
|
|
||||||
_qOffset = Nothing,
|
|
||||||
_qWhere = Nothing,
|
|
||||||
_qOrderBy = Nothing
|
|
||||||
},
|
|
||||||
_qrForeach = Nothing
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
mockAgentGraphqlTest "works with an order by that navigates relationships" $ \_testEnv performGraphqlRequest -> do
|
mockAgentGraphqlTest "works with an order by that navigates relationships" $ \_testEnv performGraphqlRequest -> do
|
||||||
@ -274,19 +246,19 @@ tests _opts = describe "Object Relationships Tests" $ do
|
|||||||
}
|
}
|
||||||
|]
|
|]
|
||||||
let queryResponse =
|
let queryResponse =
|
||||||
rowsResponse
|
mkRowsQueryResponse
|
||||||
[ [ ( API.FieldName "Album",
|
[ [ ( "Album",
|
||||||
API.mkRelationshipFieldValue $
|
API.mkRelationshipFieldValue $
|
||||||
rowsResponse
|
mkRowsQueryResponse
|
||||||
[ [ ( API.FieldName "Artist",
|
[ [ ( "Artist",
|
||||||
API.mkRelationshipFieldValue $
|
API.mkRelationshipFieldValue $
|
||||||
rowsResponse
|
mkRowsQueryResponse
|
||||||
[[(API.FieldName "Name", API.mkColumnFieldValue $ Aeson.String "Zeca Pagodinho")]]
|
[[("Name", API.mkColumnFieldValue $ Aeson.String "Zeca Pagodinho")]]
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
(API.FieldName "Name", API.mkColumnFieldValue $ Aeson.String "Camarão que Dorme e Onda Leva")
|
("Name", API.mkColumnFieldValue $ Aeson.String "Camarão que Dorme e Onda Leva")
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
let mockConfig = Mock.chinookMock & mockQueryResponse queryResponse
|
let mockConfig = Mock.chinookMock & mockQueryResponse queryResponse
|
||||||
@ -306,108 +278,83 @@ tests _opts = describe "Object Relationships Tests" $ do
|
|||||||
_mrrRecordedRequest
|
_mrrRecordedRequest
|
||||||
`shouldBe` Just
|
`shouldBe` Just
|
||||||
( Query $
|
( Query $
|
||||||
API.QueryRequest
|
mkQueryRequest
|
||||||
{ _qrTable = API.TableName ("Track" :| []),
|
(mkTableName "Track")
|
||||||
_qrTableRelationships =
|
( emptyQuery
|
||||||
[ API.TableRelationships
|
& API.qFields
|
||||||
{ _trSourceTable = API.TableName ("Track" :| []),
|
?~ mkFieldsMap
|
||||||
_trRelationships =
|
[ ("Name", API.ColumnField (API.ColumnName "Name") $ API.ScalarType "string"),
|
||||||
HashMap.fromList
|
( "Album",
|
||||||
[ ( API.RelationshipName "Album",
|
API.RelField
|
||||||
API.Relationship
|
( API.RelationshipField
|
||||||
{ _rTargetTable = API.TableName ("Album" :| []),
|
(API.RelationshipName "Album")
|
||||||
_rRelationshipType = API.ObjectRelationship,
|
( emptyQuery
|
||||||
_rColumnMapping = HashMap.fromList [(API.ColumnName "AlbumId", API.ColumnName "AlbumId")]
|
& API.qFields
|
||||||
}
|
?~ mkFieldsMap
|
||||||
)
|
[ ( "Artist",
|
||||||
]
|
API.RelField
|
||||||
},
|
( API.RelationshipField
|
||||||
API.TableRelationships
|
(API.RelationshipName "Artist")
|
||||||
{ _trSourceTable = API.TableName ("Album" :| []),
|
(emptyQuery & API.qFields ?~ mkFieldsMap [("Name", API.ColumnField (API.ColumnName "Name") (API.ScalarType "string"))])
|
||||||
_trRelationships =
|
)
|
||||||
HashMap.fromList
|
)
|
||||||
[ ( API.RelationshipName "Artist",
|
]
|
||||||
API.Relationship
|
)
|
||||||
{ _rTargetTable = API.TableName ("Artist" :| []),
|
)
|
||||||
_rRelationshipType = API.ObjectRelationship,
|
)
|
||||||
_rColumnMapping = HashMap.fromList [(API.ColumnName "ArtistId", API.ColumnName "ArtistId")]
|
]
|
||||||
}
|
& API.qLimit ?~ 1
|
||||||
)
|
& API.qOrderBy
|
||||||
]
|
?~ API.OrderBy
|
||||||
}
|
( HashMap.fromList
|
||||||
],
|
[ ( API.RelationshipName "Album",
|
||||||
_qrQuery =
|
API.OrderByRelation
|
||||||
API.Query
|
Nothing
|
||||||
{ _qFields =
|
( HashMap.fromList
|
||||||
Just $
|
[ ( API.RelationshipName "Artist",
|
||||||
HashMap.fromList
|
API.OrderByRelation
|
||||||
[ (API.FieldName "Name", API.ColumnField (API.ColumnName "Name") $ API.ScalarType "string"),
|
Nothing
|
||||||
( API.FieldName "Album",
|
mempty
|
||||||
API.RelField
|
|
||||||
( API.RelationshipField
|
|
||||||
(API.RelationshipName "Album")
|
|
||||||
API.Query
|
|
||||||
{ _qFields =
|
|
||||||
Just $
|
|
||||||
HashMap.fromList
|
|
||||||
[ ( API.FieldName "Artist",
|
|
||||||
API.RelField
|
|
||||||
( API.RelationshipField
|
|
||||||
(API.RelationshipName "Artist")
|
|
||||||
API.Query
|
|
||||||
{ _qFields =
|
|
||||||
Just $
|
|
||||||
HashMap.fromList
|
|
||||||
[ (API.FieldName "Name", API.ColumnField (API.ColumnName "Name") $ API.ScalarType "string")
|
|
||||||
],
|
|
||||||
_qAggregates = Nothing,
|
|
||||||
_qLimit = Nothing,
|
|
||||||
_qOffset = Nothing,
|
|
||||||
_qWhere = Nothing,
|
|
||||||
_qOrderBy = Nothing
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
],
|
|
||||||
_qAggregates = Nothing,
|
|
||||||
_qLimit = Nothing,
|
|
||||||
_qOffset = Nothing,
|
|
||||||
_qWhere = Nothing,
|
|
||||||
_qOrderBy = Nothing
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
],
|
|
||||||
_qAggregates = Nothing,
|
|
||||||
_qLimit = Just 1,
|
|
||||||
_qOffset = Nothing,
|
|
||||||
_qWhere = Nothing,
|
|
||||||
_qOrderBy =
|
|
||||||
Just $
|
|
||||||
API.OrderBy
|
|
||||||
( HashMap.fromList
|
|
||||||
[ ( API.RelationshipName "Album",
|
|
||||||
API.OrderByRelation
|
|
||||||
Nothing
|
|
||||||
( HashMap.fromList
|
|
||||||
[ ( API.RelationshipName "Artist",
|
|
||||||
API.OrderByRelation
|
|
||||||
Nothing
|
|
||||||
mempty
|
|
||||||
)
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
)
|
]
|
||||||
]
|
)
|
||||||
)
|
)
|
||||||
( NE.fromList
|
]
|
||||||
[ API.OrderByElement [API.RelationshipName "Album", API.RelationshipName "Artist"] (API.OrderByColumn (API.ColumnName "Name")) API.Descending,
|
)
|
||||||
API.OrderByElement [] (API.OrderByColumn (API.ColumnName "Name")) API.Ascending
|
( NE.fromList
|
||||||
]
|
[ API.OrderByElement [API.RelationshipName "Album", API.RelationshipName "Artist"] (API.OrderByColumn (API.ColumnName "Name")) API.Descending,
|
||||||
)
|
API.OrderByElement [] (API.OrderByColumn (API.ColumnName "Name")) API.Ascending
|
||||||
},
|
]
|
||||||
_qrForeach = Nothing
|
)
|
||||||
}
|
)
|
||||||
|
& API.qrTableRelationships
|
||||||
|
.~ [ API.TableRelationships
|
||||||
|
{ _trSourceTable = mkTableName "Track",
|
||||||
|
_trRelationships =
|
||||||
|
HashMap.fromList
|
||||||
|
[ ( API.RelationshipName "Album",
|
||||||
|
API.Relationship
|
||||||
|
{ _rTargetTable = mkTableName "Album",
|
||||||
|
_rRelationshipType = API.ObjectRelationship,
|
||||||
|
_rColumnMapping = HashMap.fromList [(API.ColumnName "AlbumId", API.ColumnName "AlbumId")]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
]
|
||||||
|
},
|
||||||
|
API.TableRelationships
|
||||||
|
{ _trSourceTable = mkTableName "Album",
|
||||||
|
_trRelationships =
|
||||||
|
HashMap.fromList
|
||||||
|
[ ( API.RelationshipName "Artist",
|
||||||
|
API.Relationship
|
||||||
|
{ _rTargetTable = mkTableName "Artist",
|
||||||
|
_rRelationshipType = API.ObjectRelationship,
|
||||||
|
_rColumnMapping = HashMap.fromList [(API.ColumnName "ArtistId", API.ColumnName "ArtistId")]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
mockAgentGraphqlTest "works with an order by that navigates a relationship with table permissions" $ \_testEnv performGraphqlRequest -> do
|
mockAgentGraphqlTest "works with an order by that navigates a relationship with table permissions" $ \_testEnv performGraphqlRequest -> do
|
||||||
@ -421,8 +368,8 @@ tests _opts = describe "Object Relationships Tests" $ do
|
|||||||
}
|
}
|
||||||
|]
|
|]
|
||||||
let queryResponse =
|
let queryResponse =
|
||||||
rowsResponse
|
mkRowsQueryResponse
|
||||||
[ [ (API.FieldName "EmployeeId", API.mkColumnFieldValue $ Aeson.Number 3)
|
[ [ ("EmployeeId", API.mkColumnFieldValue $ Aeson.Number 3)
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
let mockConfig = Mock.chinookMock & mockQueryResponse queryResponse
|
let mockConfig = Mock.chinookMock & mockQueryResponse queryResponse
|
||||||
@ -439,75 +386,63 @@ tests _opts = describe "Object Relationships Tests" $ do
|
|||||||
_mrrRecordedRequest
|
_mrrRecordedRequest
|
||||||
`shouldBe` Just
|
`shouldBe` Just
|
||||||
( Query $
|
( Query $
|
||||||
API.QueryRequest
|
mkQueryRequest
|
||||||
{ _qrTable = API.TableName ("Employee" :| []),
|
(mkTableName "Employee")
|
||||||
_qrTableRelationships =
|
( emptyQuery
|
||||||
[ API.TableRelationships
|
& API.qFields ?~ mkFieldsMap [("EmployeeId", API.ColumnField (API.ColumnName "EmployeeId") $ API.ScalarType "number")]
|
||||||
{ _trSourceTable = API.TableName ("Customer" :| []),
|
& API.qLimit ?~ 1
|
||||||
_trRelationships =
|
& API.qWhere
|
||||||
HashMap.fromList
|
?~ API.Exists
|
||||||
[ ( API.RelationshipName "SupportRep",
|
(API.RelatedTable $ API.RelationshipName "SupportRepForCustomers")
|
||||||
API.Relationship
|
( API.ApplyBinaryComparisonOperator
|
||||||
{ _rTargetTable = API.TableName ("Employee" :| []),
|
API.Equal
|
||||||
_rRelationshipType = API.ObjectRelationship,
|
(API.ComparisonColumn API.CurrentTable (API.ColumnName "Country") $ API.ScalarType "string")
|
||||||
_rColumnMapping = HashMap.fromList [(API.ColumnName "SupportRepId", API.ColumnName "EmployeeId")]
|
(API.AnotherColumnComparison (API.ComparisonColumn API.QueryTable (API.ColumnName "Country") $ API.ScalarType "string"))
|
||||||
}
|
)
|
||||||
)
|
& API.qOrderBy
|
||||||
]
|
?~ API.OrderBy
|
||||||
},
|
( HashMap.fromList
|
||||||
API.TableRelationships
|
[ ( API.RelationshipName "SupportRepForCustomers",
|
||||||
{ _trSourceTable = API.TableName ("Employee" :| []),
|
API.OrderByRelation
|
||||||
_trRelationships =
|
( Just $
|
||||||
HashMap.fromList
|
API.Exists (API.RelatedTable $ API.RelationshipName "SupportRep") $
|
||||||
[ ( API.RelationshipName "SupportRepForCustomers",
|
API.ApplyBinaryComparisonOperator
|
||||||
API.Relationship
|
API.Equal
|
||||||
{ _rTargetTable = API.TableName ("Customer" :| []),
|
(API.ComparisonColumn API.CurrentTable (API.ColumnName "Country") $ API.ScalarType "string")
|
||||||
_rRelationshipType = API.ArrayRelationship,
|
(API.AnotherColumnComparison (API.ComparisonColumn API.QueryTable (API.ColumnName "Country") $ API.ScalarType "string"))
|
||||||
_rColumnMapping = HashMap.fromList [(API.ColumnName "EmployeeId", API.ColumnName "SupportRepId")]
|
)
|
||||||
}
|
mempty
|
||||||
)
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
_qrQuery =
|
|
||||||
API.Query
|
|
||||||
{ _qFields =
|
|
||||||
Just $
|
|
||||||
HashMap.fromList
|
|
||||||
[ (API.FieldName "EmployeeId", API.ColumnField (API.ColumnName "EmployeeId") $ API.ScalarType "number")
|
|
||||||
],
|
|
||||||
_qAggregates = Nothing,
|
|
||||||
_qLimit = Just 1,
|
|
||||||
_qOffset = Nothing,
|
|
||||||
_qWhere =
|
|
||||||
Just $
|
|
||||||
API.Exists (API.RelatedTable $ API.RelationshipName "SupportRepForCustomers") $
|
|
||||||
API.ApplyBinaryComparisonOperator
|
|
||||||
API.Equal
|
|
||||||
(API.ComparisonColumn API.CurrentTable (API.ColumnName "Country") $ API.ScalarType "string")
|
|
||||||
(API.AnotherColumnComparison (API.ComparisonColumn API.QueryTable (API.ColumnName "Country") $ API.ScalarType "string")),
|
|
||||||
_qOrderBy =
|
|
||||||
Just $
|
|
||||||
API.OrderBy
|
|
||||||
( HashMap.fromList
|
|
||||||
[ ( API.RelationshipName "SupportRepForCustomers",
|
|
||||||
API.OrderByRelation
|
|
||||||
( Just $
|
|
||||||
API.Exists (API.RelatedTable $ API.RelationshipName "SupportRep") $
|
|
||||||
API.ApplyBinaryComparisonOperator
|
|
||||||
API.Equal
|
|
||||||
(API.ComparisonColumn API.CurrentTable (API.ColumnName "Country") $ API.ScalarType "string")
|
|
||||||
(API.AnotherColumnComparison (API.ComparisonColumn API.QueryTable (API.ColumnName "Country") $ API.ScalarType "string"))
|
|
||||||
)
|
|
||||||
mempty
|
|
||||||
)
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
(API.OrderByElement [API.RelationshipName "SupportRepForCustomers"] API.OrderByStarCountAggregate API.Descending :| [])
|
]
|
||||||
},
|
)
|
||||||
_qrForeach = Nothing
|
(API.OrderByElement [API.RelationshipName "SupportRepForCustomers"] API.OrderByStarCountAggregate API.Descending :| [])
|
||||||
}
|
)
|
||||||
|
& API.qrTableRelationships
|
||||||
|
.~ [ API.TableRelationships
|
||||||
|
{ _trSourceTable = mkTableName "Customer",
|
||||||
|
_trRelationships =
|
||||||
|
HashMap.fromList
|
||||||
|
[ ( API.RelationshipName "SupportRep",
|
||||||
|
API.Relationship
|
||||||
|
{ _rTargetTable = mkTableName "Employee",
|
||||||
|
_rRelationshipType = API.ObjectRelationship,
|
||||||
|
_rColumnMapping = HashMap.fromList [(API.ColumnName "SupportRepId", API.ColumnName "EmployeeId")]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
]
|
||||||
|
},
|
||||||
|
API.TableRelationships
|
||||||
|
{ _trSourceTable = mkTableName "Employee",
|
||||||
|
_trRelationships =
|
||||||
|
HashMap.fromList
|
||||||
|
[ ( API.RelationshipName "SupportRepForCustomers",
|
||||||
|
API.Relationship
|
||||||
|
{ _rTargetTable = mkTableName "Customer",
|
||||||
|
_rRelationshipType = API.ArrayRelationship,
|
||||||
|
_rColumnMapping = HashMap.fromList [(API.ColumnName "EmployeeId", API.ColumnName "SupportRepId")]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
rowsResponse :: [[(API.FieldName, API.FieldValue)]] -> API.QueryResponse
|
|
||||||
rowsResponse rows = API.QueryResponse (Just $ HashMap.fromList <$> rows) Nothing
|
|
||||||
|
@ -5,7 +5,7 @@ module Test.DataConnector.MockAgent.RemoteRelationshipsSpec (spec) where
|
|||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
import Control.Lens ((.~), _Just)
|
import Control.Lens ((.~), (?~), _Just)
|
||||||
import Data.Aeson qualified as Aeson
|
import Data.Aeson qualified as Aeson
|
||||||
import Data.HashMap.Strict qualified as HashMap
|
import Data.HashMap.Strict qualified as HashMap
|
||||||
import Data.List.NonEmpty qualified as NE
|
import Data.List.NonEmpty qualified as NE
|
||||||
@ -24,6 +24,7 @@ import Harness.TestEnvironment (GlobalTestEnvironment, TestEnvironment)
|
|||||||
import Harness.Yaml (shouldBeYaml, shouldReturnYaml)
|
import Harness.Yaml (shouldBeYaml, shouldReturnYaml)
|
||||||
import Hasura.Backends.DataConnector.API qualified as API
|
import Hasura.Backends.DataConnector.API qualified as API
|
||||||
import Hasura.Prelude
|
import Hasura.Prelude
|
||||||
|
import Test.DataConnector.MockAgent.TestHelpers
|
||||||
import Test.Hspec (HasCallStack, SpecWith, describe, it, shouldBe)
|
import Test.Hspec (HasCallStack, SpecWith, describe, it, shouldBe)
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
@ -211,27 +212,27 @@ tests _opts = do
|
|||||||
}
|
}
|
||||||
|]
|
|]
|
||||||
let queryResponse =
|
let queryResponse =
|
||||||
mkRowsResponse
|
mkRowsQueryResponse
|
||||||
[ [ ( API.FieldName "query",
|
[ [ ( "query",
|
||||||
API.mkRelationshipFieldValue $
|
API.mkRelationshipFieldValue $
|
||||||
mkRowsResponse
|
mkRowsQueryResponse
|
||||||
[ [ (API.FieldName "AlbumId", API.mkColumnFieldValue $ Aeson.Number 1),
|
[ [ ("AlbumId", API.mkColumnFieldValue $ Aeson.Number 1),
|
||||||
(API.FieldName "Title", API.mkColumnFieldValue $ Aeson.String "For Those About To Rock We Salute You")
|
("Title", API.mkColumnFieldValue $ Aeson.String "For Those About To Rock We Salute You")
|
||||||
],
|
],
|
||||||
[ (API.FieldName "AlbumId", API.mkColumnFieldValue $ Aeson.Number 4),
|
[ ("AlbumId", API.mkColumnFieldValue $ Aeson.Number 4),
|
||||||
(API.FieldName "Title", API.mkColumnFieldValue $ Aeson.String "Let There Be Rock")
|
("Title", API.mkColumnFieldValue $ Aeson.String "Let There Be Rock")
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
[ ( API.FieldName "query",
|
[ ( "query",
|
||||||
API.mkRelationshipFieldValue $
|
API.mkRelationshipFieldValue $
|
||||||
mkRowsResponse
|
mkRowsQueryResponse
|
||||||
[ [ (API.FieldName "AlbumId", API.mkColumnFieldValue $ Aeson.Number 2),
|
[ [ ("AlbumId", API.mkColumnFieldValue $ Aeson.Number 2),
|
||||||
(API.FieldName "Title", API.mkColumnFieldValue $ Aeson.String "Balls to the Wall")
|
("Title", API.mkColumnFieldValue $ Aeson.String "Balls to the Wall")
|
||||||
],
|
],
|
||||||
[ (API.FieldName "AlbumId", API.mkColumnFieldValue $ Aeson.Number 3),
|
[ ("AlbumId", API.mkColumnFieldValue $ Aeson.Number 3),
|
||||||
(API.FieldName "Title", API.mkColumnFieldValue $ Aeson.String "Restless and Wild")
|
("Title", API.mkColumnFieldValue $ Aeson.String "Restless and Wild")
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
@ -264,30 +265,20 @@ tests _opts = do
|
|||||||
_mrrRecordedRequest
|
_mrrRecordedRequest
|
||||||
`shouldBe` Just
|
`shouldBe` Just
|
||||||
( Query $
|
( Query $
|
||||||
API.QueryRequest
|
mkQueryRequest
|
||||||
{ _qrTable = API.TableName ("Album" :| []),
|
(mkTableName "Album")
|
||||||
_qrTableRelationships = [],
|
( emptyQuery
|
||||||
_qrQuery =
|
& API.qFields
|
||||||
API.Query
|
?~ mkFieldsMap
|
||||||
{ _qFields =
|
[ ("AlbumId", API.ColumnField (API.ColumnName "AlbumId") $ API.ScalarType "number"),
|
||||||
Just $
|
("Title", API.ColumnField (API.ColumnName "Title") $ API.ScalarType "string")
|
||||||
HashMap.fromList
|
|
||||||
[ (API.FieldName "AlbumId", API.ColumnField (API.ColumnName "AlbumId") $ API.ScalarType "number"),
|
|
||||||
(API.FieldName "Title", API.ColumnField (API.ColumnName "Title") $ API.ScalarType "string")
|
|
||||||
],
|
|
||||||
_qAggregates = Nothing,
|
|
||||||
_qLimit = Nothing,
|
|
||||||
_qOffset = Nothing,
|
|
||||||
_qWhere = Nothing,
|
|
||||||
_qOrderBy = Nothing
|
|
||||||
},
|
|
||||||
_qrForeach =
|
|
||||||
Just $
|
|
||||||
NonEmpty.fromList
|
|
||||||
[ HashMap.fromList [(API.ColumnName "ArtistId", API.ScalarValue (Aeson.Number 1) (API.ScalarType "number"))],
|
|
||||||
HashMap.fromList [(API.ColumnName "ArtistId", API.ScalarValue (Aeson.Number 2) (API.ScalarType "number"))]
|
|
||||||
]
|
]
|
||||||
}
|
)
|
||||||
|
& API.qrForeach
|
||||||
|
?~ NonEmpty.fromList
|
||||||
|
[ HashMap.fromList [(API.ColumnName "ArtistId", API.ScalarValue (Aeson.Number 1) (API.ScalarType "number"))],
|
||||||
|
HashMap.fromList [(API.ColumnName "ArtistId", API.ScalarValue (Aeson.Number 2) (API.ScalarType "number"))]
|
||||||
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
mockAgentGraphqlTest "can act as the target of a remote object relationship" $ \testEnv performGraphqlRequest -> do
|
mockAgentGraphqlTest "can act as the target of a remote object relationship" $ \testEnv performGraphqlRequest -> do
|
||||||
@ -307,30 +298,30 @@ tests _opts = do
|
|||||||
}
|
}
|
||||||
|]
|
|]
|
||||||
let queryResponse =
|
let queryResponse =
|
||||||
mkRowsResponse
|
mkRowsQueryResponse
|
||||||
[ [ ( API.FieldName "query",
|
[ [ ( "query",
|
||||||
API.mkRelationshipFieldValue $
|
API.mkRelationshipFieldValue $
|
||||||
mkRowsResponse
|
mkRowsQueryResponse
|
||||||
[ [ (API.FieldName "AlbumId", API.mkColumnFieldValue $ Aeson.Number 3),
|
[ [ ("AlbumId", API.mkColumnFieldValue $ Aeson.Number 3),
|
||||||
(API.FieldName "Title", API.mkColumnFieldValue $ Aeson.String "Restless and Wild")
|
("Title", API.mkColumnFieldValue $ Aeson.String "Restless and Wild")
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
[ ( API.FieldName "query",
|
[ ( "query",
|
||||||
API.mkRelationshipFieldValue $
|
API.mkRelationshipFieldValue $
|
||||||
mkRowsResponse
|
mkRowsQueryResponse
|
||||||
[ [ (API.FieldName "AlbumId", API.mkColumnFieldValue $ Aeson.Number 1),
|
[ [ ("AlbumId", API.mkColumnFieldValue $ Aeson.Number 1),
|
||||||
(API.FieldName "Title", API.mkColumnFieldValue $ Aeson.String "For Those About To Rock We Salute You")
|
("Title", API.mkColumnFieldValue $ Aeson.String "For Those About To Rock We Salute You")
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
[ ( API.FieldName "query",
|
[ ( "query",
|
||||||
API.mkRelationshipFieldValue $
|
API.mkRelationshipFieldValue $
|
||||||
mkRowsResponse
|
mkRowsQueryResponse
|
||||||
[ [ (API.FieldName "AlbumId", API.mkColumnFieldValue $ Aeson.Number 4),
|
[ [ ("AlbumId", API.mkColumnFieldValue $ Aeson.Number 4),
|
||||||
(API.FieldName "Title", API.mkColumnFieldValue $ Aeson.String "Let There Be Rock")
|
("Title", API.mkColumnFieldValue $ Aeson.String "Let There Be Rock")
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
@ -364,31 +355,21 @@ tests _opts = do
|
|||||||
_mrrRecordedRequest
|
_mrrRecordedRequest
|
||||||
`shouldBe` Just
|
`shouldBe` Just
|
||||||
( Query $
|
( Query $
|
||||||
API.QueryRequest
|
mkQueryRequest
|
||||||
{ _qrTable = API.TableName ("Album" :| []),
|
(mkTableName "Album")
|
||||||
_qrTableRelationships = [],
|
( emptyQuery
|
||||||
_qrQuery =
|
& API.qFields
|
||||||
API.Query
|
?~ mkFieldsMap
|
||||||
{ _qFields =
|
[ ("AlbumId", API.ColumnField (API.ColumnName "AlbumId") $ API.ScalarType "number"),
|
||||||
Just $
|
("Title", API.ColumnField (API.ColumnName "Title") $ API.ScalarType "string")
|
||||||
HashMap.fromList
|
|
||||||
[ (API.FieldName "AlbumId", API.ColumnField (API.ColumnName "AlbumId") $ API.ScalarType "number"),
|
|
||||||
(API.FieldName "Title", API.ColumnField (API.ColumnName "Title") $ API.ScalarType "string")
|
|
||||||
],
|
|
||||||
_qAggregates = Nothing,
|
|
||||||
_qLimit = Nothing,
|
|
||||||
_qOffset = Nothing,
|
|
||||||
_qWhere = Nothing,
|
|
||||||
_qOrderBy = Nothing
|
|
||||||
},
|
|
||||||
_qrForeach =
|
|
||||||
Just $
|
|
||||||
NonEmpty.fromList
|
|
||||||
[ HashMap.fromList [(API.ColumnName "AlbumId", API.ScalarValue (Aeson.Number 3) (API.ScalarType "number"))],
|
|
||||||
HashMap.fromList [(API.ColumnName "AlbumId", API.ScalarValue (Aeson.Number 1) (API.ScalarType "number"))],
|
|
||||||
HashMap.fromList [(API.ColumnName "AlbumId", API.ScalarValue (Aeson.Number 4) (API.ScalarType "number"))]
|
|
||||||
]
|
]
|
||||||
}
|
)
|
||||||
|
& API.qrForeach
|
||||||
|
?~ NonEmpty.fromList
|
||||||
|
[ HashMap.fromList [(API.ColumnName "AlbumId", API.ScalarValue (Aeson.Number 3) (API.ScalarType "number"))],
|
||||||
|
HashMap.fromList [(API.ColumnName "AlbumId", API.ScalarValue (Aeson.Number 1) (API.ScalarType "number"))],
|
||||||
|
HashMap.fromList [(API.ColumnName "AlbumId", API.ScalarValue (Aeson.Number 4) (API.ScalarType "number"))]
|
||||||
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
mockAgentGraphqlTest "can act as the target of an aggregation over a remote array relationship" $ \testEnv performGraphqlRequest -> do
|
mockAgentGraphqlTest "can act as the target of an aggregation over a remote array relationship" $ \testEnv performGraphqlRequest -> do
|
||||||
@ -413,32 +394,32 @@ tests _opts = do
|
|||||||
}
|
}
|
||||||
|]
|
|]
|
||||||
let queryResponse =
|
let queryResponse =
|
||||||
mkRowsResponse
|
mkRowsQueryResponse
|
||||||
[ [ ( API.FieldName "query",
|
[ [ ( "query",
|
||||||
API.mkRelationshipFieldValue $
|
API.mkRelationshipFieldValue $
|
||||||
mkQueryResponse
|
mkQueryResponse
|
||||||
[ [ (API.FieldName "nodes_AlbumId", API.mkColumnFieldValue $ Aeson.Number 1),
|
[ [ ("nodes_AlbumId", API.mkColumnFieldValue $ Aeson.Number 1),
|
||||||
(API.FieldName "nodes_Title", API.mkColumnFieldValue $ Aeson.String "For Those About To Rock We Salute You")
|
("nodes_Title", API.mkColumnFieldValue $ Aeson.String "For Those About To Rock We Salute You")
|
||||||
],
|
],
|
||||||
[ (API.FieldName "nodes_AlbumId", API.mkColumnFieldValue $ Aeson.Number 4),
|
[ ("nodes_AlbumId", API.mkColumnFieldValue $ Aeson.Number 4),
|
||||||
(API.FieldName "nodes_Title", API.mkColumnFieldValue $ Aeson.String "Let There Be Rock")
|
("nodes_Title", API.mkColumnFieldValue $ Aeson.String "Let There Be Rock")
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
[ (API.FieldName "aggregate_count", Aeson.Number 2)
|
[ ("aggregate_count", Aeson.Number 2)
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
[ ( API.FieldName "query",
|
[ ( "query",
|
||||||
API.mkRelationshipFieldValue $
|
API.mkRelationshipFieldValue $
|
||||||
mkQueryResponse
|
mkQueryResponse
|
||||||
[ [ (API.FieldName "nodes_AlbumId", API.mkColumnFieldValue $ Aeson.Number 2),
|
[ [ ("nodes_AlbumId", API.mkColumnFieldValue $ Aeson.Number 2),
|
||||||
(API.FieldName "nodes_Title", API.mkColumnFieldValue $ Aeson.String "Balls to the Wall")
|
("nodes_Title", API.mkColumnFieldValue $ Aeson.String "Balls to the Wall")
|
||||||
],
|
],
|
||||||
[ (API.FieldName "nodes_AlbumId", API.mkColumnFieldValue $ Aeson.Number 3),
|
[ ("nodes_AlbumId", API.mkColumnFieldValue $ Aeson.Number 3),
|
||||||
(API.FieldName "nodes_Title", API.mkColumnFieldValue $ Aeson.String "Restless and Wild")
|
("nodes_Title", API.mkColumnFieldValue $ Aeson.String "Restless and Wild")
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
[ (API.FieldName "aggregate_count", Aeson.Number 2)
|
[ ("aggregate_count", Aeson.Number 2)
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
@ -476,41 +457,23 @@ tests _opts = do
|
|||||||
_mrrRecordedRequest
|
_mrrRecordedRequest
|
||||||
`shouldBe` Just
|
`shouldBe` Just
|
||||||
( Query $
|
( Query $
|
||||||
API.QueryRequest
|
mkQueryRequest
|
||||||
{ _qrTable = API.TableName ("Album" :| []),
|
(mkTableName "Album")
|
||||||
_qrTableRelationships = [],
|
( emptyQuery
|
||||||
_qrQuery =
|
& API.qFields
|
||||||
API.Query
|
?~ mkFieldsMap
|
||||||
{ _qFields =
|
[ ("nodes_AlbumId", API.ColumnField (API.ColumnName "AlbumId") $ API.ScalarType "number"),
|
||||||
Just $
|
("nodes_Title", API.ColumnField (API.ColumnName "Title") $ API.ScalarType "string")
|
||||||
HashMap.fromList
|
|
||||||
[ (API.FieldName "nodes_AlbumId", API.ColumnField (API.ColumnName "AlbumId") $ API.ScalarType "number"),
|
|
||||||
(API.FieldName "nodes_Title", API.ColumnField (API.ColumnName "Title") $ API.ScalarType "string")
|
|
||||||
],
|
|
||||||
_qAggregates =
|
|
||||||
Just $
|
|
||||||
HashMap.fromList
|
|
||||||
[(API.FieldName "aggregate_count", API.StarCount)],
|
|
||||||
_qLimit = Nothing,
|
|
||||||
_qOffset = Nothing,
|
|
||||||
_qWhere = Nothing,
|
|
||||||
_qOrderBy = Nothing
|
|
||||||
},
|
|
||||||
_qrForeach =
|
|
||||||
Just $
|
|
||||||
NonEmpty.fromList
|
|
||||||
[ HashMap.fromList [(API.ColumnName "ArtistId", API.ScalarValue (Aeson.Number 1) (API.ScalarType "number"))],
|
|
||||||
HashMap.fromList [(API.ColumnName "ArtistId", API.ScalarValue (Aeson.Number 2) (API.ScalarType "number"))]
|
|
||||||
]
|
]
|
||||||
}
|
& API.qAggregates ?~ mkFieldsMap [("aggregate_count", API.StarCount)]
|
||||||
|
)
|
||||||
|
& API.qrForeach
|
||||||
|
?~ NonEmpty.fromList
|
||||||
|
[ HashMap.fromList [(API.ColumnName "ArtistId", API.ScalarValue (Aeson.Number 1) (API.ScalarType "number"))],
|
||||||
|
HashMap.fromList [(API.ColumnName "ArtistId", API.ScalarValue (Aeson.Number 2) (API.ScalarType "number"))]
|
||||||
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
mkRowsResponse :: [[(API.FieldName, API.FieldValue)]] -> API.QueryResponse
|
|
||||||
mkRowsResponse rows = API.QueryResponse (Just $ HashMap.fromList <$> rows) Nothing
|
|
||||||
|
|
||||||
mkQueryResponse :: [[(API.FieldName, API.FieldValue)]] -> [(API.FieldName, Aeson.Value)] -> API.QueryResponse
|
|
||||||
mkQueryResponse rows aggregates = API.QueryResponse (Just $ HashMap.fromList <$> rows) (Just $ HashMap.fromList aggregates)
|
|
||||||
|
|
||||||
errorTests :: Fixture.Options -> SpecWith (TestEnvironment, Mock.MockAgentEnvironment)
|
errorTests :: Fixture.Options -> SpecWith (TestEnvironment, Mock.MockAgentEnvironment)
|
||||||
errorTests opts = do
|
errorTests opts = do
|
||||||
it "creating a remote relationship returns an error when it is unsupported by the target" $ \(testEnv, _) -> do
|
it "creating a remote relationship returns an error when it is unsupported by the target" $ \(testEnv, _) -> do
|
||||||
|
@ -0,0 +1,40 @@
|
|||||||
|
module Test.DataConnector.MockAgent.TestHelpers
|
||||||
|
( mkTableName,
|
||||||
|
mkQueryRequest,
|
||||||
|
emptyQuery,
|
||||||
|
emptyMutationRequest,
|
||||||
|
mkRowsQueryResponse,
|
||||||
|
mkAggregatesQueryResponse,
|
||||||
|
mkQueryResponse,
|
||||||
|
mkFieldsMap,
|
||||||
|
)
|
||||||
|
where
|
||||||
|
|
||||||
|
import Data.Aeson qualified as Aeson
|
||||||
|
import Data.HashMap.Strict qualified as HashMap
|
||||||
|
import Hasura.Backends.DataConnector.API qualified as API
|
||||||
|
import Hasura.Prelude
|
||||||
|
|
||||||
|
mkTableName :: Text -> API.TableName
|
||||||
|
mkTableName name = API.TableName (name :| [])
|
||||||
|
|
||||||
|
mkQueryRequest :: API.TableName -> API.Query -> API.QueryRequest
|
||||||
|
mkQueryRequest tableName query = API.QueryRequest tableName [] query Nothing
|
||||||
|
|
||||||
|
emptyQuery :: API.Query
|
||||||
|
emptyQuery = API.Query Nothing Nothing Nothing Nothing Nothing Nothing Nothing
|
||||||
|
|
||||||
|
emptyMutationRequest :: API.MutationRequest
|
||||||
|
emptyMutationRequest = API.MutationRequest [] [] []
|
||||||
|
|
||||||
|
mkRowsQueryResponse :: [[(Text, API.FieldValue)]] -> API.QueryResponse
|
||||||
|
mkRowsQueryResponse rows = API.QueryResponse (Just $ mkFieldsMap <$> rows) Nothing
|
||||||
|
|
||||||
|
mkAggregatesQueryResponse :: [(Text, Aeson.Value)] -> API.QueryResponse
|
||||||
|
mkAggregatesQueryResponse aggregates = API.QueryResponse Nothing (Just $ mkFieldsMap aggregates)
|
||||||
|
|
||||||
|
mkQueryResponse :: [[(Text, API.FieldValue)]] -> [(Text, Aeson.Value)] -> API.QueryResponse
|
||||||
|
mkQueryResponse rows aggregates = API.QueryResponse (Just $ mkFieldsMap <$> rows) (Just $ mkFieldsMap aggregates)
|
||||||
|
|
||||||
|
mkFieldsMap :: [(Text, v)] -> HashMap API.FieldName v
|
||||||
|
mkFieldsMap = HashMap.fromList . fmap (first API.FieldName)
|
@ -5,8 +5,8 @@ module Test.DataConnector.MockAgent.TransformedConfigurationSpec (spec) where
|
|||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
import Control.Lens ((?~))
|
||||||
import Data.Aeson qualified as Aeson
|
import Data.Aeson qualified as Aeson
|
||||||
import Data.HashMap.Strict qualified as HashMap
|
|
||||||
import Data.List.NonEmpty qualified as NE
|
import Data.List.NonEmpty qualified as NE
|
||||||
import Harness.Backend.DataConnector.Mock (AgentRequest (..), MockRequestResults (..), mockAgentGraphqlTest, mockQueryResponse)
|
import Harness.Backend.DataConnector.Mock (AgentRequest (..), MockRequestResults (..), mockAgentGraphqlTest, mockQueryResponse)
|
||||||
import Harness.Backend.DataConnector.Mock qualified as Mock
|
import Harness.Backend.DataConnector.Mock qualified as Mock
|
||||||
@ -18,6 +18,7 @@ import Harness.TestEnvironment (GlobalTestEnvironment, TestEnvironment)
|
|||||||
import Harness.Yaml (shouldBeYaml)
|
import Harness.Yaml (shouldBeYaml)
|
||||||
import Hasura.Backends.DataConnector.API qualified as API
|
import Hasura.Backends.DataConnector.API qualified as API
|
||||||
import Hasura.Prelude
|
import Hasura.Prelude
|
||||||
|
import Test.DataConnector.MockAgent.TestHelpers
|
||||||
import Test.Hspec (SpecWith, describe, shouldBe)
|
import Test.Hspec (SpecWith, describe, shouldBe)
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
@ -113,9 +114,9 @@ tests _opts = describe "Transformed Configuration Tests" $ do
|
|||||||
}
|
}
|
||||||
|]
|
|]
|
||||||
let queryResponse =
|
let queryResponse =
|
||||||
rowsResponse
|
mkRowsQueryResponse
|
||||||
[ [ (API.FieldName "id", API.mkColumnFieldValue $ Aeson.Number 1),
|
[ [ ("id", API.mkColumnFieldValue $ Aeson.Number 1),
|
||||||
(API.FieldName "title", API.mkColumnFieldValue $ Aeson.String "For Those About To Rock We Salute You")
|
("title", API.mkColumnFieldValue $ Aeson.String "For Those About To Rock We Salute You")
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
let mockConfig = Mock.chinookMock & mockQueryResponse queryResponse
|
let mockConfig = Mock.chinookMock & mockQueryResponse queryResponse
|
||||||
@ -133,25 +134,16 @@ tests _opts = describe "Transformed Configuration Tests" $ do
|
|||||||
_mrrRecordedRequest
|
_mrrRecordedRequest
|
||||||
`shouldBe` Just
|
`shouldBe` Just
|
||||||
( Query $
|
( Query $
|
||||||
API.QueryRequest
|
mkQueryRequest
|
||||||
{ _qrTable = API.TableName ("Album" :| []),
|
(mkTableName "Album")
|
||||||
_qrTableRelationships = [],
|
( emptyQuery
|
||||||
_qrQuery =
|
& API.qFields
|
||||||
API.Query
|
?~ mkFieldsMap
|
||||||
{ _qFields =
|
[ ("id", API.ColumnField (API.ColumnName "AlbumId") $ API.ScalarType "number"),
|
||||||
Just $
|
("title", API.ColumnField (API.ColumnName "Title") $ API.ScalarType "string")
|
||||||
HashMap.fromList
|
]
|
||||||
[ (API.FieldName "id", API.ColumnField (API.ColumnName "AlbumId") $ API.ScalarType "number"),
|
& API.qLimit ?~ 1
|
||||||
(API.FieldName "title", API.ColumnField (API.ColumnName "Title") $ API.ScalarType "string")
|
)
|
||||||
],
|
|
||||||
_qAggregates = Nothing,
|
|
||||||
_qLimit = Just 1,
|
|
||||||
_qOffset = Nothing,
|
|
||||||
_qWhere = Nothing,
|
|
||||||
_qOrderBy = Nothing
|
|
||||||
},
|
|
||||||
_qrForeach = Nothing
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
Aeson.toJSON _mrrRecordedRequestConfig
|
Aeson.toJSON _mrrRecordedRequestConfig
|
||||||
@ -161,6 +153,3 @@ tests _opts = describe "Transformed Configuration Tests" $ do
|
|||||||
env: "bar env default"
|
env: "bar env default"
|
||||||
session: "foo session default"
|
session: "foo session default"
|
||||||
|]
|
|]
|
||||||
|
|
||||||
rowsResponse :: [[(API.FieldName, API.FieldValue)]] -> API.QueryResponse
|
|
||||||
rowsResponse rows = API.QueryResponse (Just $ HashMap.fromList <$> rows) Nothing
|
|
||||||
|
@ -3,6 +3,7 @@ module Test.DataConnector.MockAgent.UpdateMutationsSpec
|
|||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
|
import Control.Lens ((.~), (?~))
|
||||||
import Data.Aeson qualified as Aeson
|
import Data.Aeson qualified as Aeson
|
||||||
import Data.ByteString (ByteString)
|
import Data.ByteString (ByteString)
|
||||||
import Data.HashMap.Strict qualified as HashMap
|
import Data.HashMap.Strict qualified as HashMap
|
||||||
@ -18,6 +19,7 @@ import Harness.Yaml
|
|||||||
import Hasura.Backends.DataConnector.API qualified as API
|
import Hasura.Backends.DataConnector.API qualified as API
|
||||||
import Hasura.Prelude
|
import Hasura.Prelude
|
||||||
import Language.GraphQL.Draft.Syntax.QQ qualified as G
|
import Language.GraphQL.Draft.Syntax.QQ qualified as G
|
||||||
|
import Test.DataConnector.MockAgent.TestHelpers
|
||||||
import Test.Hspec
|
import Test.Hspec
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
@ -127,35 +129,35 @@ tests _opts = do
|
|||||||
{ API._morAffectedRows = 3,
|
{ API._morAffectedRows = 3,
|
||||||
API._morReturning =
|
API._morReturning =
|
||||||
Just
|
Just
|
||||||
[ HashMap.fromList
|
[ mkFieldsMap
|
||||||
[ (API.FieldName "updatedRows_TrackId", API.mkColumnFieldValue $ Aeson.Number 3),
|
[ ("updatedRows_TrackId", API.mkColumnFieldValue $ Aeson.Number 3),
|
||||||
(API.FieldName "updatedRows_Name", API.mkColumnFieldValue $ Aeson.String "Another Name"),
|
("updatedRows_Name", API.mkColumnFieldValue $ Aeson.String "Another Name"),
|
||||||
( API.FieldName "updatedRows_Genre",
|
( "updatedRows_Genre",
|
||||||
API.mkRelationshipFieldValue $
|
API.mkRelationshipFieldValue $
|
||||||
rowsResponse
|
mkRowsQueryResponse
|
||||||
[ [ (API.FieldName "Name", API.mkColumnFieldValue $ Aeson.String "Rock")
|
[ [ ("Name", API.mkColumnFieldValue $ Aeson.String "Rock")
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
HashMap.fromList
|
mkFieldsMap
|
||||||
[ (API.FieldName "updatedRows_TrackId", API.mkColumnFieldValue $ Aeson.Number 4),
|
[ ("updatedRows_TrackId", API.mkColumnFieldValue $ Aeson.Number 4),
|
||||||
(API.FieldName "updatedRows_Name", API.mkColumnFieldValue $ Aeson.String "Another Name"),
|
("updatedRows_Name", API.mkColumnFieldValue $ Aeson.String "Another Name"),
|
||||||
( API.FieldName "updatedRows_Genre",
|
( "updatedRows_Genre",
|
||||||
API.mkRelationshipFieldValue $
|
API.mkRelationshipFieldValue $
|
||||||
rowsResponse
|
mkRowsQueryResponse
|
||||||
[ [ (API.FieldName "Name", API.mkColumnFieldValue $ Aeson.String "Rock")
|
[ [ ("Name", API.mkColumnFieldValue $ Aeson.String "Rock")
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
HashMap.fromList
|
mkFieldsMap
|
||||||
[ (API.FieldName "updatedRows_TrackId", API.mkColumnFieldValue $ Aeson.Number 5),
|
[ ("updatedRows_TrackId", API.mkColumnFieldValue $ Aeson.Number 5),
|
||||||
(API.FieldName "updatedRows_Name", API.mkColumnFieldValue $ Aeson.String "Another Name"),
|
("updatedRows_Name", API.mkColumnFieldValue $ Aeson.String "Another Name"),
|
||||||
( API.FieldName "updatedRows_Genre",
|
( "updatedRows_Genre",
|
||||||
API.mkRelationshipFieldValue $
|
API.mkRelationshipFieldValue $
|
||||||
rowsResponse
|
mkRowsQueryResponse
|
||||||
[ [ (API.FieldName "Name", API.mkColumnFieldValue $ Aeson.String "Rock")
|
[ [ ("Name", API.mkColumnFieldValue $ Aeson.String "Rock")
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
@ -188,91 +190,78 @@ tests _opts = do
|
|||||||
|]
|
|]
|
||||||
|
|
||||||
let expectedRequest =
|
let expectedRequest =
|
||||||
API.MutationRequest
|
emptyMutationRequest
|
||||||
{ API._mrTableRelationships =
|
& API.mrTableRelationships
|
||||||
[ API.TableRelationships
|
.~ [ API.TableRelationships
|
||||||
{ API._trSourceTable = API.TableName ("Track" :| []),
|
{ API._trSourceTable = mkTableName "Track",
|
||||||
API._trRelationships =
|
API._trRelationships =
|
||||||
HashMap.fromList
|
HashMap.fromList
|
||||||
[ ( API.RelationshipName "Genre",
|
[ ( API.RelationshipName "Genre",
|
||||||
API.Relationship
|
API.Relationship
|
||||||
{ API._rTargetTable = API.TableName ("Genre" :| []),
|
{ API._rTargetTable = mkTableName "Genre",
|
||||||
API._rRelationshipType = API.ObjectRelationship,
|
API._rRelationshipType = API.ObjectRelationship,
|
||||||
API._rColumnMapping = HashMap.fromList [(API.ColumnName "GenreId", API.ColumnName "GenreId")]
|
API._rColumnMapping = HashMap.fromList [(API.ColumnName "GenreId", API.ColumnName "GenreId")]
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
API._mrInsertSchema = [],
|
& API.mrOperations
|
||||||
API._mrOperations =
|
.~ [ API.UpdateOperation $
|
||||||
[ API.UpdateOperation $
|
API.UpdateMutationOperation
|
||||||
API.UpdateMutationOperation
|
{ API._umoTable = mkTableName "Track",
|
||||||
{ API._umoTable = API.TableName ("Track" :| []),
|
API._umoUpdates =
|
||||||
API._umoUpdates =
|
[ API.SetColumn $
|
||||||
[ API.SetColumn $
|
API.RowColumnOperatorValue
|
||||||
API.RowColumnOperatorValue
|
{ API._rcovColumn = API.ColumnName "Name",
|
||||||
{ API._rcovColumn = API.ColumnName "Name",
|
API._rcovValue = Aeson.String "Another Name",
|
||||||
API._rcovValue = Aeson.String "Another Name",
|
API._rcovValueType = API.ScalarType "string"
|
||||||
API._rcovValueType = API.ScalarType "string"
|
},
|
||||||
},
|
API.CustomUpdateColumnOperator (API.UpdateColumnOperatorName [G.name|inc|]) $
|
||||||
API.CustomUpdateColumnOperator (API.UpdateColumnOperatorName [G.name|inc|]) $
|
API.RowColumnOperatorValue
|
||||||
API.RowColumnOperatorValue
|
{ API._rcovColumn = API.ColumnName "Milliseconds",
|
||||||
{ API._rcovColumn = API.ColumnName "Milliseconds",
|
API._rcovValue = Aeson.Number 1000,
|
||||||
API._rcovValue = Aeson.Number 1000,
|
API._rcovValueType = API.ScalarType "number"
|
||||||
API._rcovValueType = API.ScalarType "number"
|
},
|
||||||
},
|
API.SetColumn $
|
||||||
API.SetColumn $
|
API.RowColumnOperatorValue
|
||||||
API.RowColumnOperatorValue
|
{ API._rcovColumn = API.ColumnName "AlbumId",
|
||||||
{ API._rcovColumn = API.ColumnName "AlbumId",
|
API._rcovValue = Aeson.Number 3,
|
||||||
API._rcovValue = Aeson.Number 3,
|
API._rcovValueType = API.ScalarType "number"
|
||||||
API._rcovValueType = API.ScalarType "number"
|
}
|
||||||
}
|
],
|
||||||
],
|
API._umoWhere =
|
||||||
API._umoWhere =
|
Just $
|
||||||
Just $
|
API.And
|
||||||
API.And
|
[ API.ApplyBinaryComparisonOperator
|
||||||
[ API.ApplyBinaryComparisonOperator
|
API.Equal
|
||||||
API.Equal
|
(API.ComparisonColumn API.CurrentTable (API.ColumnName "AlbumId") $ API.ScalarType "number")
|
||||||
(API.ComparisonColumn API.CurrentTable (API.ColumnName "AlbumId") $ API.ScalarType "number")
|
(API.ScalarValueComparison $ API.ScalarValue (Aeson.Number 3) (API.ScalarType "number")),
|
||||||
(API.ScalarValueComparison $ API.ScalarValue (Aeson.Number 3) (API.ScalarType "number")),
|
API.ApplyBinaryComparisonOperator
|
||||||
API.ApplyBinaryComparisonOperator
|
API.Equal
|
||||||
API.Equal
|
(API.ComparisonColumn API.CurrentTable (API.ColumnName "GenreId") $ API.ScalarType "number")
|
||||||
(API.ComparisonColumn API.CurrentTable (API.ColumnName "GenreId") $ API.ScalarType "number")
|
(API.ScalarValueComparison $ API.ScalarValue (Aeson.Number 1) (API.ScalarType "number"))
|
||||||
(API.ScalarValueComparison $ API.ScalarValue (Aeson.Number 1) (API.ScalarType "number"))
|
],
|
||||||
],
|
API._umoPostUpdateCheck =
|
||||||
API._umoPostUpdateCheck =
|
Just $
|
||||||
Just $
|
API.ApplyBinaryComparisonOperator
|
||||||
API.ApplyBinaryComparisonOperator
|
API.GreaterThan
|
||||||
API.GreaterThan
|
(API.ComparisonColumn API.CurrentTable (API.ColumnName "UnitPrice") $ API.ScalarType "number")
|
||||||
(API.ComparisonColumn API.CurrentTable (API.ColumnName "UnitPrice") $ API.ScalarType "number")
|
(API.ScalarValueComparison $ API.ScalarValue (Aeson.Number 0) (API.ScalarType "number")),
|
||||||
(API.ScalarValueComparison $ API.ScalarValue (Aeson.Number 0) (API.ScalarType "number")),
|
API._umoReturningFields =
|
||||||
API._umoReturningFields =
|
mkFieldsMap
|
||||||
HashMap.fromList
|
[ ("updatedRows_TrackId", API.ColumnField (API.ColumnName "TrackId") (API.ScalarType "number")),
|
||||||
[ (API.FieldName "updatedRows_TrackId", API.ColumnField (API.ColumnName "TrackId") (API.ScalarType "number")),
|
("updatedRows_Name", API.ColumnField (API.ColumnName "Name") (API.ScalarType "string")),
|
||||||
(API.FieldName "updatedRows_Name", API.ColumnField (API.ColumnName "Name") (API.ScalarType "string")),
|
( "updatedRows_Genre",
|
||||||
( API.FieldName "updatedRows_Genre",
|
API.RelField
|
||||||
API.RelField
|
( API.RelationshipField
|
||||||
( API.RelationshipField
|
(API.RelationshipName "Genre")
|
||||||
(API.RelationshipName "Genre")
|
(emptyQuery & API.qFields ?~ mkFieldsMap [("Name", API.ColumnField (API.ColumnName "Name") $ API.ScalarType "string")])
|
||||||
API.Query
|
)
|
||||||
{ _qFields =
|
)
|
||||||
Just $
|
]
|
||||||
HashMap.fromList
|
}
|
||||||
[ (API.FieldName "Name", API.ColumnField (API.ColumnName "Name") $ API.ScalarType "string")
|
]
|
||||||
],
|
|
||||||
_qAggregates = Nothing,
|
|
||||||
_qLimit = Nothing,
|
|
||||||
_qOffset = Nothing,
|
|
||||||
_qWhere = Nothing,
|
|
||||||
_qOrderBy = Nothing
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
_mrrRecordedRequest `shouldBe` Just (Mutation expectedRequest)
|
_mrrRecordedRequest `shouldBe` Just (Mutation expectedRequest)
|
||||||
|
|
||||||
mockAgentGraphqlTest "update_many rows with update permissions" $ \_testEnv performGraphqlRequest -> do
|
mockAgentGraphqlTest "update_many rows with update permissions" $ \_testEnv performGraphqlRequest -> do
|
||||||
@ -301,13 +290,13 @@ tests _opts = do
|
|||||||
{ API._morAffectedRows = 1,
|
{ API._morAffectedRows = 1,
|
||||||
API._morReturning =
|
API._morReturning =
|
||||||
Just
|
Just
|
||||||
[ HashMap.fromList
|
[ mkFieldsMap
|
||||||
[ (API.FieldName "updatedRows_TrackId", API.mkColumnFieldValue $ Aeson.Number 3),
|
[ ("updatedRows_TrackId", API.mkColumnFieldValue $ Aeson.Number 3),
|
||||||
(API.FieldName "updatedRows_Name", API.mkColumnFieldValue $ Aeson.String "Another Name"),
|
("updatedRows_Name", API.mkColumnFieldValue $ Aeson.String "Another Name"),
|
||||||
( API.FieldName "updatedRows_Genre",
|
( "updatedRows_Genre",
|
||||||
API.mkRelationshipFieldValue $
|
API.mkRelationshipFieldValue $
|
||||||
rowsResponse
|
mkRowsQueryResponse
|
||||||
[ [ (API.FieldName "Name", API.mkColumnFieldValue $ Aeson.String "Rock")
|
[ [ ("Name", API.mkColumnFieldValue $ Aeson.String "Rock")
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
@ -318,24 +307,24 @@ tests _opts = do
|
|||||||
{ API._morAffectedRows = 2,
|
{ API._morAffectedRows = 2,
|
||||||
API._morReturning =
|
API._morReturning =
|
||||||
Just
|
Just
|
||||||
[ HashMap.fromList
|
[ mkFieldsMap
|
||||||
[ (API.FieldName "updatedRows_TrackId", API.mkColumnFieldValue $ Aeson.Number 4),
|
[ ("updatedRows_TrackId", API.mkColumnFieldValue $ Aeson.Number 4),
|
||||||
(API.FieldName "updatedRows_Name", API.mkColumnFieldValue $ Aeson.String "Better Name"),
|
("updatedRows_Name", API.mkColumnFieldValue $ Aeson.String "Better Name"),
|
||||||
( API.FieldName "updatedRows_Genre",
|
( "updatedRows_Genre",
|
||||||
API.mkRelationshipFieldValue $
|
API.mkRelationshipFieldValue $
|
||||||
rowsResponse
|
mkRowsQueryResponse
|
||||||
[ [ (API.FieldName "Name", API.mkColumnFieldValue $ Aeson.String "Rock")
|
[ [ ("Name", API.mkColumnFieldValue $ Aeson.String "Rock")
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
HashMap.fromList
|
mkFieldsMap
|
||||||
[ (API.FieldName "updatedRows_TrackId", API.mkColumnFieldValue $ Aeson.Number 5),
|
[ ("updatedRows_TrackId", API.mkColumnFieldValue $ Aeson.Number 5),
|
||||||
(API.FieldName "updatedRows_Name", API.mkColumnFieldValue $ Aeson.String "Better Name"),
|
("updatedRows_Name", API.mkColumnFieldValue $ Aeson.String "Better Name"),
|
||||||
( API.FieldName "updatedRows_Genre",
|
( "updatedRows_Genre",
|
||||||
API.mkRelationshipFieldValue $
|
API.mkRelationshipFieldValue $
|
||||||
rowsResponse
|
mkRowsQueryResponse
|
||||||
[ [ (API.FieldName "Name", API.mkColumnFieldValue $ Aeson.String "Rock")
|
[ [ ("Name", API.mkColumnFieldValue $ Aeson.String "Rock")
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
@ -376,126 +365,110 @@ tests _opts = do
|
|||||||
(API.ComparisonColumn API.CurrentTable (API.ColumnName "UnitPrice") $ API.ScalarType "number")
|
(API.ComparisonColumn API.CurrentTable (API.ColumnName "UnitPrice") $ API.ScalarType "number")
|
||||||
(API.ScalarValueComparison $ API.ScalarValue (Aeson.Number 0) (API.ScalarType "number"))
|
(API.ScalarValueComparison $ API.ScalarValue (Aeson.Number 0) (API.ScalarType "number"))
|
||||||
let sharedReturning =
|
let sharedReturning =
|
||||||
HashMap.fromList
|
mkFieldsMap
|
||||||
[ (API.FieldName "updatedRows_TrackId", API.ColumnField (API.ColumnName "TrackId") (API.ScalarType "number")),
|
[ ("updatedRows_TrackId", API.ColumnField (API.ColumnName "TrackId") (API.ScalarType "number")),
|
||||||
(API.FieldName "updatedRows_Name", API.ColumnField (API.ColumnName "Name") (API.ScalarType "string")),
|
("updatedRows_Name", API.ColumnField (API.ColumnName "Name") (API.ScalarType "string")),
|
||||||
( API.FieldName "updatedRows_Genre",
|
( "updatedRows_Genre",
|
||||||
API.RelField
|
API.RelField
|
||||||
( API.RelationshipField
|
( API.RelationshipField
|
||||||
(API.RelationshipName "Genre")
|
(API.RelationshipName "Genre")
|
||||||
API.Query
|
(emptyQuery & API.qFields ?~ mkFieldsMap [("Name", API.ColumnField (API.ColumnName "Name") $ API.ScalarType "string")])
|
||||||
{ _qFields =
|
|
||||||
Just $
|
|
||||||
HashMap.fromList
|
|
||||||
[ (API.FieldName "Name", API.ColumnField (API.ColumnName "Name") $ API.ScalarType "string")
|
|
||||||
],
|
|
||||||
_qAggregates = Nothing,
|
|
||||||
_qLimit = Nothing,
|
|
||||||
_qOffset = Nothing,
|
|
||||||
_qWhere = Nothing,
|
|
||||||
_qOrderBy = Nothing
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
let expectedRequest =
|
let expectedRequest =
|
||||||
API.MutationRequest
|
emptyMutationRequest
|
||||||
{ API._mrTableRelationships =
|
& API.mrTableRelationships
|
||||||
[ API.TableRelationships
|
.~ [ API.TableRelationships
|
||||||
{ API._trSourceTable = API.TableName ("Track" :| []),
|
{ API._trSourceTable = mkTableName "Track",
|
||||||
API._trRelationships =
|
API._trRelationships =
|
||||||
HashMap.fromList
|
HashMap.fromList
|
||||||
[ ( API.RelationshipName "Genre",
|
[ ( API.RelationshipName "Genre",
|
||||||
API.Relationship
|
API.Relationship
|
||||||
{ API._rTargetTable = API.TableName ("Genre" :| []),
|
{ API._rTargetTable = mkTableName "Genre",
|
||||||
API._rRelationshipType = API.ObjectRelationship,
|
API._rRelationshipType = API.ObjectRelationship,
|
||||||
API._rColumnMapping = HashMap.fromList [(API.ColumnName "GenreId", API.ColumnName "GenreId")]
|
API._rColumnMapping = HashMap.fromList [(API.ColumnName "GenreId", API.ColumnName "GenreId")]
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
API._mrInsertSchema = [],
|
& API.mrOperations
|
||||||
API._mrOperations =
|
.~ [ API.UpdateOperation $
|
||||||
[ API.UpdateOperation $
|
API.UpdateMutationOperation
|
||||||
API.UpdateMutationOperation
|
{ API._umoTable = mkTableName "Track",
|
||||||
{ API._umoTable = API.TableName ("Track" :| []),
|
API._umoUpdates =
|
||||||
API._umoUpdates =
|
[ API.SetColumn $
|
||||||
[ API.SetColumn $
|
API.RowColumnOperatorValue
|
||||||
API.RowColumnOperatorValue
|
{ API._rcovColumn = API.ColumnName "Name",
|
||||||
{ API._rcovColumn = API.ColumnName "Name",
|
API._rcovValue = Aeson.String "Another Name",
|
||||||
API._rcovValue = Aeson.String "Another Name",
|
API._rcovValueType = API.ScalarType "string"
|
||||||
API._rcovValueType = API.ScalarType "string"
|
},
|
||||||
},
|
API.CustomUpdateColumnOperator (API.UpdateColumnOperatorName [G.name|inc|]) $
|
||||||
API.CustomUpdateColumnOperator (API.UpdateColumnOperatorName [G.name|inc|]) $
|
API.RowColumnOperatorValue
|
||||||
API.RowColumnOperatorValue
|
{ API._rcovColumn = API.ColumnName "Milliseconds",
|
||||||
{ API._rcovColumn = API.ColumnName "Milliseconds",
|
API._rcovValue = Aeson.Number 1000,
|
||||||
API._rcovValue = Aeson.Number 1000,
|
API._rcovValueType = API.ScalarType "number"
|
||||||
API._rcovValueType = API.ScalarType "number"
|
},
|
||||||
},
|
API.SetColumn $
|
||||||
API.SetColumn $
|
API.RowColumnOperatorValue
|
||||||
API.RowColumnOperatorValue
|
{ API._rcovColumn = API.ColumnName "AlbumId",
|
||||||
{ API._rcovColumn = API.ColumnName "AlbumId",
|
API._rcovValue = Aeson.Number 3,
|
||||||
API._rcovValue = Aeson.Number 3,
|
API._rcovValueType = API.ScalarType "number"
|
||||||
API._rcovValueType = API.ScalarType "number"
|
}
|
||||||
}
|
],
|
||||||
],
|
API._umoWhere =
|
||||||
API._umoWhere =
|
Just $
|
||||||
Just $
|
API.And
|
||||||
API.And
|
[ API.ApplyBinaryComparisonOperator
|
||||||
[ API.ApplyBinaryComparisonOperator
|
API.Equal
|
||||||
API.Equal
|
(API.ComparisonColumn API.CurrentTable (API.ColumnName "AlbumId") $ API.ScalarType "number")
|
||||||
(API.ComparisonColumn API.CurrentTable (API.ColumnName "AlbumId") $ API.ScalarType "number")
|
(API.ScalarValueComparison $ API.ScalarValue (Aeson.Number 3) (API.ScalarType "number")),
|
||||||
(API.ScalarValueComparison $ API.ScalarValue (Aeson.Number 3) (API.ScalarType "number")),
|
API.ApplyBinaryComparisonOperator
|
||||||
API.ApplyBinaryComparisonOperator
|
API.Equal
|
||||||
API.Equal
|
(API.ComparisonColumn API.CurrentTable (API.ColumnName "TrackId") $ API.ScalarType "number")
|
||||||
(API.ComparisonColumn API.CurrentTable (API.ColumnName "TrackId") $ API.ScalarType "number")
|
(API.ScalarValueComparison $ API.ScalarValue (Aeson.Number 3) (API.ScalarType "number"))
|
||||||
(API.ScalarValueComparison $ API.ScalarValue (Aeson.Number 3) (API.ScalarType "number"))
|
],
|
||||||
],
|
API._umoPostUpdateCheck = sharedPostUpdateCheck,
|
||||||
API._umoPostUpdateCheck = sharedPostUpdateCheck,
|
API._umoReturningFields = sharedReturning
|
||||||
API._umoReturningFields = sharedReturning
|
},
|
||||||
},
|
API.UpdateOperation $
|
||||||
API.UpdateOperation $
|
API.UpdateMutationOperation
|
||||||
API.UpdateMutationOperation
|
{ API._umoTable = mkTableName "Track",
|
||||||
{ API._umoTable = API.TableName ("Track" :| []),
|
API._umoUpdates =
|
||||||
API._umoUpdates =
|
[ API.SetColumn $
|
||||||
[ API.SetColumn $
|
API.RowColumnOperatorValue
|
||||||
API.RowColumnOperatorValue
|
{ API._rcovColumn = API.ColumnName "Name",
|
||||||
{ API._rcovColumn = API.ColumnName "Name",
|
API._rcovValue = Aeson.String "Better Name",
|
||||||
API._rcovValue = Aeson.String "Better Name",
|
API._rcovValueType = API.ScalarType "string"
|
||||||
API._rcovValueType = API.ScalarType "string"
|
},
|
||||||
},
|
API.CustomUpdateColumnOperator (API.UpdateColumnOperatorName [G.name|inc|]) $
|
||||||
API.CustomUpdateColumnOperator (API.UpdateColumnOperatorName [G.name|inc|]) $
|
API.RowColumnOperatorValue
|
||||||
API.RowColumnOperatorValue
|
{ API._rcovColumn = API.ColumnName "UnitPrice",
|
||||||
{ API._rcovColumn = API.ColumnName "UnitPrice",
|
API._rcovValue = Aeson.Number 1,
|
||||||
API._rcovValue = Aeson.Number 1,
|
API._rcovValueType = API.ScalarType "number"
|
||||||
API._rcovValueType = API.ScalarType "number"
|
},
|
||||||
},
|
API.SetColumn $
|
||||||
API.SetColumn $
|
API.RowColumnOperatorValue
|
||||||
API.RowColumnOperatorValue
|
{ API._rcovColumn = API.ColumnName "AlbumId",
|
||||||
{ API._rcovColumn = API.ColumnName "AlbumId",
|
API._rcovValue = Aeson.Number 3,
|
||||||
API._rcovValue = Aeson.Number 3,
|
API._rcovValueType = API.ScalarType "number"
|
||||||
API._rcovValueType = API.ScalarType "number"
|
}
|
||||||
}
|
],
|
||||||
],
|
API._umoWhere =
|
||||||
API._umoWhere =
|
Just $
|
||||||
Just $
|
API.And
|
||||||
API.And
|
[ API.ApplyBinaryComparisonOperator
|
||||||
[ API.ApplyBinaryComparisonOperator
|
API.Equal
|
||||||
API.Equal
|
(API.ComparisonColumn API.CurrentTable (API.ColumnName "AlbumId") $ API.ScalarType "number")
|
||||||
(API.ComparisonColumn API.CurrentTable (API.ColumnName "AlbumId") $ API.ScalarType "number")
|
(API.ScalarValueComparison $ API.ScalarValue (Aeson.Number 3) (API.ScalarType "number")),
|
||||||
(API.ScalarValueComparison $ API.ScalarValue (Aeson.Number 3) (API.ScalarType "number")),
|
API.ApplyBinaryComparisonOperator
|
||||||
API.ApplyBinaryComparisonOperator
|
API.GreaterThan
|
||||||
API.GreaterThan
|
(API.ComparisonColumn API.CurrentTable (API.ColumnName "TrackId") $ API.ScalarType "number")
|
||||||
(API.ComparisonColumn API.CurrentTable (API.ColumnName "TrackId") $ API.ScalarType "number")
|
(API.ScalarValueComparison $ API.ScalarValue (Aeson.Number 3) (API.ScalarType "number"))
|
||||||
(API.ScalarValueComparison $ API.ScalarValue (Aeson.Number 3) (API.ScalarType "number"))
|
],
|
||||||
],
|
API._umoPostUpdateCheck = sharedPostUpdateCheck,
|
||||||
API._umoPostUpdateCheck = sharedPostUpdateCheck,
|
API._umoReturningFields = sharedReturning
|
||||||
API._umoReturningFields = sharedReturning
|
}
|
||||||
}
|
]
|
||||||
]
|
|
||||||
}
|
|
||||||
_mrrRecordedRequest `shouldBe` Just (Mutation expectedRequest)
|
_mrrRecordedRequest `shouldBe` Just (Mutation expectedRequest)
|
||||||
|
|
||||||
rowsResponse :: [[(API.FieldName, API.FieldValue)]] -> API.QueryResponse
|
|
||||||
rowsResponse rows = API.QueryResponse (Just $ HashMap.fromList <$> rows) Nothing
|
|
||||||
|
@ -11,6 +11,7 @@ module Hasura.Backends.DataConnector.API.V0.Query
|
|||||||
Query (..),
|
Query (..),
|
||||||
qFields,
|
qFields,
|
||||||
qAggregates,
|
qAggregates,
|
||||||
|
qAggregatesLimit,
|
||||||
qLimit,
|
qLimit,
|
||||||
qOffset,
|
qOffset,
|
||||||
qWhere,
|
qWhere,
|
||||||
@ -92,9 +93,14 @@ data Query = Query
|
|||||||
_qFields :: Maybe (HashMap FieldName Field),
|
_qFields :: Maybe (HashMap FieldName Field),
|
||||||
-- | Map of aggregate field name to Aggregate definition
|
-- | Map of aggregate field name to Aggregate definition
|
||||||
_qAggregates :: Maybe (HashMap FieldName API.V0.Aggregate),
|
_qAggregates :: Maybe (HashMap FieldName API.V0.Aggregate),
|
||||||
-- | Optionally limit to N results.
|
-- | Optionally limit the maximum number of rows considered while applying
|
||||||
|
-- aggregations. This limit does not apply to returned rows.
|
||||||
|
_qAggregatesLimit :: Maybe Int,
|
||||||
|
-- | Optionally limit the maximum number of returned rows. This limit does not
|
||||||
|
-- apply to records considered while apply aggregations.
|
||||||
_qLimit :: Maybe Int,
|
_qLimit :: Maybe Int,
|
||||||
-- | Optionally offset from the Nth result.
|
-- | Optionally offset from the Nth result. This applies to both row
|
||||||
|
-- and aggregation results.
|
||||||
_qOffset :: Maybe Int,
|
_qOffset :: Maybe Int,
|
||||||
-- | Optionally constrain the results to satisfy some predicate.
|
-- | Optionally constrain the results to satisfy some predicate.
|
||||||
_qWhere :: Maybe API.V0.Expression,
|
_qWhere :: Maybe API.V0.Expression,
|
||||||
@ -112,9 +118,11 @@ instance HasCodec Query where
|
|||||||
.= _qFields
|
.= _qFields
|
||||||
<*> optionalFieldOrNull "aggregates" "Aggregate fields of the query"
|
<*> optionalFieldOrNull "aggregates" "Aggregate fields of the query"
|
||||||
.= _qAggregates
|
.= _qAggregates
|
||||||
<*> optionalFieldOrNull "limit" "Optionally limit to N results"
|
<*> optionalFieldOrNull "aggregates_limit" "Optionally limit the maximum number of rows considered while applying aggregations. This limit does not apply to returned rows."
|
||||||
|
.= _qAggregatesLimit
|
||||||
|
<*> optionalFieldOrNull "limit" "Optionally limit the maximum number of returned rows. This limit does not apply to records considered while apply aggregations."
|
||||||
.= _qLimit
|
.= _qLimit
|
||||||
<*> optionalFieldOrNull "offset" "Optionally offset from the Nth result"
|
<*> optionalFieldOrNull "offset" "Optionally offset from the Nth result. This applies to both row and aggregation results."
|
||||||
.= _qOffset
|
.= _qOffset
|
||||||
<*> optionalFieldOrNull "where" "Optionally constrain the results to satisfy some predicate"
|
<*> optionalFieldOrNull "where" "Optionally constrain the results to satisfy some predicate"
|
||||||
.= _qWhere
|
.= _qWhere
|
||||||
|
@ -598,7 +598,7 @@ findColumnScalarType API.SchemaResponse {..} tableName columnName =
|
|||||||
columnInfo = find (\API.ColumnInfo {..} -> _ciName == columnName) =<< API._tiColumns <$> tableInfo
|
columnInfo = find (\API.ColumnInfo {..} -> _ciName == columnName) =<< API._tiColumns <$> tableInfo
|
||||||
|
|
||||||
emptyQuery :: API.Query
|
emptyQuery :: API.Query
|
||||||
emptyQuery = API.Query Nothing Nothing Nothing Nothing Nothing Nothing
|
emptyQuery = API.Query Nothing Nothing Nothing Nothing Nothing Nothing Nothing
|
||||||
|
|
||||||
emptyMutationRequest :: API.MutationRequest
|
emptyMutationRequest :: API.MutationRequest
|
||||||
emptyMutationRequest = API.MutationRequest mempty mempty mempty
|
emptyMutationRequest = API.MutationRequest mempty mempty mempty
|
||||||
|
@ -52,12 +52,24 @@ spec TestData {..} relationshipCapabilities = describe "Aggregate Queries" $ do
|
|||||||
|
|
||||||
it "counts all rows, after applying pagination" $ do
|
it "counts all rows, after applying pagination" $ do
|
||||||
let offset = 400
|
let offset = 400
|
||||||
let limit = 20
|
let aggregatesLimit = 20
|
||||||
let aggregates = Data.mkFieldsMap [("count_all", StarCount)]
|
let aggregates = Data.mkFieldsMap [("count_all", StarCount)]
|
||||||
let queryRequest = invoicesQueryRequest aggregates & qrQuery %~ (qLimit ?~ limit >>> qOffset ?~ offset)
|
let queryRequest = invoicesQueryRequest aggregates & qrQuery %~ (qAggregatesLimit ?~ aggregatesLimit >>> qOffset ?~ offset)
|
||||||
response <- queryGuarded queryRequest
|
response <- queryGuarded queryRequest
|
||||||
|
|
||||||
let invoiceCount = length . take limit $ drop offset _tdInvoicesRows
|
let invoiceCount = length . take aggregatesLimit $ drop offset _tdInvoicesRows
|
||||||
|
let expectedAggregates = Data.mkFieldsMap [("count_all", Number $ fromIntegral invoiceCount)]
|
||||||
|
|
||||||
|
Data.responseAggregates response `jsonShouldBe` expectedAggregates
|
||||||
|
Data.responseRows response `rowsShouldBe` []
|
||||||
|
|
||||||
|
it "limit does not limit the count aggregation" $ do
|
||||||
|
let limit = 20
|
||||||
|
let aggregates = Data.mkFieldsMap [("count_all", StarCount)]
|
||||||
|
let queryRequest = invoicesQueryRequest aggregates & qrQuery . qLimit ?~ limit
|
||||||
|
response <- queryGuarded queryRequest
|
||||||
|
|
||||||
|
let invoiceCount = length _tdInvoicesRows
|
||||||
let expectedAggregates = Data.mkFieldsMap [("count_all", Number $ fromIntegral invoiceCount)]
|
let expectedAggregates = Data.mkFieldsMap [("count_all", Number $ fromIntegral invoiceCount)]
|
||||||
|
|
||||||
Data.responseAggregates response `jsonShouldBe` expectedAggregates
|
Data.responseAggregates response `jsonShouldBe` expectedAggregates
|
||||||
@ -76,16 +88,16 @@ spec TestData {..} relationshipCapabilities = describe "Aggregate Queries" $ do
|
|||||||
Data.responseRows response `rowsShouldBe` []
|
Data.responseRows response `rowsShouldBe` []
|
||||||
|
|
||||||
it "can count all rows with non-null values in a column, after applying pagination and filtering" $ do
|
it "can count all rows with non-null values in a column, after applying pagination and filtering" $ do
|
||||||
let limit = 50
|
let aggregatesLimit = 50
|
||||||
let where' = ApplyBinaryComparisonOperator GreaterThanOrEqual (_tdCurrentComparisonColumn "InvoiceId" invoiceIdScalarType) (Data.scalarValueComparison (Number 380) invoiceIdScalarType)
|
let where' = ApplyBinaryComparisonOperator GreaterThanOrEqual (_tdCurrentComparisonColumn "InvoiceId" invoiceIdScalarType) (Data.scalarValueComparison (Number 380) invoiceIdScalarType)
|
||||||
let aggregates = Data.mkFieldsMap [("count_cols", ColumnCount $ ColumnCountAggregate (_tdColumnName "BillingState") False)]
|
let aggregates = Data.mkFieldsMap [("count_cols", ColumnCount $ ColumnCountAggregate (_tdColumnName "BillingState") False)]
|
||||||
let queryRequest = invoicesQueryRequest aggregates & qrQuery %~ (qLimit ?~ limit >>> qWhere ?~ where')
|
let queryRequest = invoicesQueryRequest aggregates & qrQuery %~ (qAggregatesLimit ?~ aggregatesLimit >>> qWhere ?~ where')
|
||||||
response <- queryGuarded queryRequest
|
response <- queryGuarded queryRequest
|
||||||
|
|
||||||
let invoiceCount =
|
let invoiceCount =
|
||||||
_tdInvoicesRows
|
_tdInvoicesRows
|
||||||
& filter ((^? Data.field "InvoiceId" . Data._ColumnFieldNumber) >>> (>= Just 380))
|
& filter ((^? Data.field "InvoiceId" . Data._ColumnFieldNumber) >>> (>= Just 380))
|
||||||
& take limit
|
& take aggregatesLimit
|
||||||
& mapMaybe ((^? Data.field "BillingState" . Data._ColumnFieldString))
|
& mapMaybe ((^? Data.field "BillingState" . Data._ColumnFieldString))
|
||||||
& length
|
& length
|
||||||
|
|
||||||
@ -106,18 +118,18 @@ spec TestData {..} relationshipCapabilities = describe "Aggregate Queries" $ do
|
|||||||
Data.responseRows response `rowsShouldBe` []
|
Data.responseRows response `rowsShouldBe` []
|
||||||
|
|
||||||
it "can count all rows with distinct non-null values in a column, after applying pagination and filtering" $ do
|
it "can count all rows with distinct non-null values in a column, after applying pagination and filtering" $ do
|
||||||
let limit = 20
|
let aggregatesLimit = 20
|
||||||
let where' = ApplyBinaryComparisonOperator GreaterThanOrEqual (_tdCurrentComparisonColumn "InvoiceId" invoiceIdScalarType) (Data.scalarValueComparison (Number 380) invoiceIdScalarType)
|
let where' = ApplyBinaryComparisonOperator GreaterThanOrEqual (_tdCurrentComparisonColumn "InvoiceId" invoiceIdScalarType) (Data.scalarValueComparison (Number 380) invoiceIdScalarType)
|
||||||
-- It is important to add an explicit order by for this query as different database engines will order implicitly resulting in incorrect results
|
-- It is important to add an explicit order by for this query as different database engines will order implicitly resulting in incorrect results
|
||||||
let orderBy = OrderBy mempty $ _tdOrderByColumn [] "InvoiceId" Ascending :| []
|
let orderBy = OrderBy mempty $ _tdOrderByColumn [] "InvoiceId" Ascending :| []
|
||||||
let aggregates = Data.mkFieldsMap [("count_cols", ColumnCount $ ColumnCountAggregate (_tdColumnName "BillingState") True)]
|
let aggregates = Data.mkFieldsMap [("count_cols", ColumnCount $ ColumnCountAggregate (_tdColumnName "BillingState") True)]
|
||||||
let queryRequest = invoicesQueryRequest aggregates & qrQuery %~ (qLimit ?~ limit >>> qWhere ?~ where' >>> qOrderBy ?~ orderBy)
|
let queryRequest = invoicesQueryRequest aggregates & qrQuery %~ (qAggregatesLimit ?~ aggregatesLimit >>> qWhere ?~ where' >>> qOrderBy ?~ orderBy)
|
||||||
response <- queryGuarded queryRequest
|
response <- queryGuarded queryRequest
|
||||||
|
|
||||||
let billingStateCount =
|
let billingStateCount =
|
||||||
_tdInvoicesRows
|
_tdInvoicesRows
|
||||||
& filter ((^? Data.field "InvoiceId" . Data._ColumnFieldNumber) >>> (>= Just 380))
|
& filter ((^? Data.field "InvoiceId" . Data._ColumnFieldNumber) >>> (>= Just 380))
|
||||||
& take limit
|
& take aggregatesLimit
|
||||||
& mapMaybe ((^? Data.field "BillingState" . Data._ColumnFieldString))
|
& mapMaybe ((^? Data.field "BillingState" . Data._ColumnFieldString))
|
||||||
& HashSet.fromList
|
& HashSet.fromList
|
||||||
& length
|
& length
|
||||||
@ -127,6 +139,22 @@ spec TestData {..} relationshipCapabilities = describe "Aggregate Queries" $ do
|
|||||||
Data.responseAggregates response `jsonShouldBe` expectedAggregates
|
Data.responseAggregates response `jsonShouldBe` expectedAggregates
|
||||||
Data.responseRows response `rowsShouldBe` []
|
Data.responseRows response `rowsShouldBe` []
|
||||||
|
|
||||||
|
it "limit does not limit the column count aggregation" $ do
|
||||||
|
let limit = 50
|
||||||
|
let aggregates = Data.mkFieldsMap [("count_cols", ColumnCount $ ColumnCountAggregate (_tdColumnName "BillingState") False)]
|
||||||
|
let queryRequest = invoicesQueryRequest aggregates & qrQuery . qLimit ?~ limit
|
||||||
|
response <- queryGuarded queryRequest
|
||||||
|
|
||||||
|
let invoiceCount =
|
||||||
|
_tdInvoicesRows
|
||||||
|
& mapMaybe ((^? Data.field "BillingState" . Data._ColumnFieldString))
|
||||||
|
& length
|
||||||
|
|
||||||
|
let expectedAggregates = Data.mkFieldsMap [("count_cols", Number $ fromIntegral invoiceCount)]
|
||||||
|
|
||||||
|
Data.responseAggregates response `jsonShouldBe` expectedAggregates
|
||||||
|
Data.responseRows response `rowsShouldBe` []
|
||||||
|
|
||||||
describe "Single Column Function" $ do
|
describe "Single Column Function" $ do
|
||||||
it "can get the max total from all rows" $ do
|
it "can get the max total from all rows" $ do
|
||||||
let aggregates = Data.mkFieldsMap [("max", singleColumnAggregateMax (_tdColumnName "Total") invoiceTotalScalarType)]
|
let aggregates = Data.mkFieldsMap [("max", singleColumnAggregateMax (_tdColumnName "Total") invoiceTotalScalarType)]
|
||||||
@ -140,18 +168,18 @@ spec TestData {..} relationshipCapabilities = describe "Aggregate Queries" $ do
|
|||||||
Data.responseRows response `rowsShouldBe` []
|
Data.responseRows response `rowsShouldBe` []
|
||||||
|
|
||||||
it "can get the max total from all rows, after applying pagination, filtering and ordering" $ do
|
it "can get the max total from all rows, after applying pagination, filtering and ordering" $ do
|
||||||
let limit = 20
|
let aggregatesLimit = 20
|
||||||
let where' = ApplyBinaryComparisonOperator Equal (_tdCurrentComparisonColumn "BillingCountry" billingCountryScalarType) (Data.scalarValueComparison (String "USA") billingCountryScalarType)
|
let where' = ApplyBinaryComparisonOperator Equal (_tdCurrentComparisonColumn "BillingCountry" billingCountryScalarType) (Data.scalarValueComparison (String "USA") billingCountryScalarType)
|
||||||
let orderBy = OrderBy mempty $ _tdOrderByColumn [] "BillingPostalCode" Descending :| [_tdOrderByColumn [] "InvoiceId" Ascending]
|
let orderBy = OrderBy mempty $ _tdOrderByColumn [] "BillingPostalCode" Descending :| [_tdOrderByColumn [] "InvoiceId" Ascending]
|
||||||
let aggregates = Data.mkFieldsMap [("max", singleColumnAggregateMax (_tdColumnName "Total") invoiceTotalScalarType)]
|
let aggregates = Data.mkFieldsMap [("max", singleColumnAggregateMax (_tdColumnName "Total") invoiceTotalScalarType)]
|
||||||
let queryRequest = invoicesQueryRequest aggregates & qrQuery %~ (qLimit ?~ limit >>> qWhere ?~ where' >>> qOrderBy ?~ orderBy)
|
let queryRequest = invoicesQueryRequest aggregates & qrQuery %~ (qAggregatesLimit ?~ aggregatesLimit >>> qWhere ?~ where' >>> qOrderBy ?~ orderBy)
|
||||||
response <- queryGuarded queryRequest
|
response <- queryGuarded queryRequest
|
||||||
|
|
||||||
let maxTotal =
|
let maxTotal =
|
||||||
_tdInvoicesRows
|
_tdInvoicesRows
|
||||||
& filter ((^? Data.field "BillingCountry" . Data._ColumnFieldString) >>> (== Just "USA"))
|
& filter ((^? Data.field "BillingCountry" . Data._ColumnFieldString) >>> (== Just "USA"))
|
||||||
& sortOn (Down . (^? Data.field "BillingPostalCode"))
|
& sortOn (Down . (^? Data.field "BillingPostalCode"))
|
||||||
& take limit
|
& take aggregatesLimit
|
||||||
& mapMaybe ((^? Data.field "Total" . Data._ColumnFieldNumber))
|
& mapMaybe ((^? Data.field "Total" . Data._ColumnFieldNumber))
|
||||||
& maximum
|
& maximum
|
||||||
|
|
||||||
@ -190,6 +218,22 @@ spec TestData {..} relationshipCapabilities = describe "Aggregate Queries" $ do
|
|||||||
Data.responseAggregates response `jsonShouldBe` expectedAggregates
|
Data.responseAggregates response `jsonShouldBe` expectedAggregates
|
||||||
Data.responseRows response `rowsShouldBe` []
|
Data.responseRows response `rowsShouldBe` []
|
||||||
|
|
||||||
|
it "limit does not limit the single column function aggregation" $ do
|
||||||
|
let limit = 20
|
||||||
|
let aggregates = Data.mkFieldsMap [("max", singleColumnAggregateMax (_tdColumnName "Total") invoiceTotalScalarType)]
|
||||||
|
let queryRequest = invoicesQueryRequest aggregates & qrQuery . qLimit ?~ limit
|
||||||
|
response <- queryGuarded queryRequest
|
||||||
|
|
||||||
|
let maxTotal =
|
||||||
|
_tdInvoicesRows
|
||||||
|
& mapMaybe ((^? Data.field "Total" . Data._ColumnFieldNumber))
|
||||||
|
& maximum
|
||||||
|
|
||||||
|
let expectedAggregates = Data.mkFieldsMap [("max", Number maxTotal)]
|
||||||
|
|
||||||
|
Data.responseAggregates response `jsonShouldBe` expectedAggregates
|
||||||
|
Data.responseRows response `rowsShouldBe` []
|
||||||
|
|
||||||
describe "Multiple Aggregates and Returning Rows" $ do
|
describe "Multiple Aggregates and Returning Rows" $ do
|
||||||
it "can get the max total from all rows, the count and the distinct count, simultaneously" $ do
|
it "can get the max total from all rows, the count and the distinct count, simultaneously" $ do
|
||||||
let aggregates =
|
let aggregates =
|
||||||
@ -246,7 +290,7 @@ spec TestData {..} relationshipCapabilities = describe "Aggregate Queries" $ do
|
|||||||
let where' = ApplyBinaryComparisonOperator Equal (_tdCurrentComparisonColumn "BillingCountry" billingCountryScalarType) (Data.scalarValueComparison (String "Canada") billingCountryScalarType)
|
let where' = ApplyBinaryComparisonOperator Equal (_tdCurrentComparisonColumn "BillingCountry" billingCountryScalarType) (Data.scalarValueComparison (String "Canada") billingCountryScalarType)
|
||||||
let orderBy = OrderBy mempty $ _tdOrderByColumn [] "BillingAddress" Ascending :| [_tdOrderByColumn [] "InvoiceId" Ascending]
|
let orderBy = OrderBy mempty $ _tdOrderByColumn [] "BillingAddress" Ascending :| [_tdOrderByColumn [] "InvoiceId" Ascending]
|
||||||
let aggregates = Data.mkFieldsMap [("min", singleColumnAggregateMin (_tdColumnName "Total") invoiceTotalScalarType)]
|
let aggregates = Data.mkFieldsMap [("min", singleColumnAggregateMin (_tdColumnName "Total") invoiceTotalScalarType)]
|
||||||
let queryRequest = invoicesQueryRequest aggregates & qrQuery %~ (qFields ?~ fields >>> qLimit ?~ limit >>> qWhere ?~ where' >>> qOrderBy ?~ orderBy)
|
let queryRequest = invoicesQueryRequest aggregates & qrQuery %~ (qFields ?~ fields >>> qLimit ?~ limit >>> qAggregatesLimit ?~ limit >>> qWhere ?~ where' >>> qOrderBy ?~ orderBy)
|
||||||
response <- queryGuarded queryRequest
|
response <- queryGuarded queryRequest
|
||||||
|
|
||||||
let invoiceRows =
|
let invoiceRows =
|
||||||
@ -266,6 +310,56 @@ spec TestData {..} relationshipCapabilities = describe "Aggregate Queries" $ do
|
|||||||
Data.responseRows response `rowsShouldBe` expectedRows
|
Data.responseRows response `rowsShouldBe` expectedRows
|
||||||
Data.responseAggregates response `jsonShouldBe` expectedAggregates
|
Data.responseAggregates response `jsonShouldBe` expectedAggregates
|
||||||
|
|
||||||
|
it "limit limits the number of returned rows but not the rows considered by the aggregate function" $ do
|
||||||
|
let limit = 20
|
||||||
|
let fields = Data.mkFieldsMap [("InvoiceId", _tdColumnField _tdInvoicesTableName "InvoiceId")]
|
||||||
|
let orderBy = OrderBy mempty $ _tdOrderByColumn [] "InvoiceId" Ascending :| []
|
||||||
|
let aggregates = Data.mkFieldsMap [("count_all", StarCount)]
|
||||||
|
let queryRequest = invoicesQueryRequest aggregates & qrQuery %~ (qFields ?~ fields >>> qLimit ?~ limit >>> qOrderBy ?~ orderBy)
|
||||||
|
response <- queryGuarded queryRequest
|
||||||
|
|
||||||
|
let invoiceCount = length _tdInvoicesRows
|
||||||
|
let expectedAggregates = Data.mkFieldsMap [("count_all", Number $ fromIntegral invoiceCount)]
|
||||||
|
let expectedRows = take limit $ Data.filterColumnsByQueryFields (_qrQuery queryRequest) <$> _tdInvoicesRows
|
||||||
|
|
||||||
|
Data.responseAggregates response `jsonShouldBe` expectedAggregates
|
||||||
|
Data.responseRows response `rowsShouldBe` expectedRows
|
||||||
|
|
||||||
|
it "aggregates limit is applied separately to row limit" $ do
|
||||||
|
let aggregatesLimit = 30
|
||||||
|
let limit = 20
|
||||||
|
let fields =
|
||||||
|
Data.mkFieldsMap
|
||||||
|
[ ("InvoiceId", _tdColumnField _tdInvoicesTableName "InvoiceId"),
|
||||||
|
("BillingCountry", _tdColumnField _tdInvoicesTableName "BillingCountry")
|
||||||
|
]
|
||||||
|
let where' = ApplyBinaryComparisonOperator Equal (_tdCurrentComparisonColumn "BillingCountry" billingCountryScalarType) (Data.scalarValueComparison (String "Canada") billingCountryScalarType)
|
||||||
|
let orderBy = OrderBy mempty $ _tdOrderByColumn [] "BillingAddress" Ascending :| [_tdOrderByColumn [] "InvoiceId" Ascending]
|
||||||
|
let aggregates = Data.mkFieldsMap [("min", singleColumnAggregateMin (_tdColumnName "Total") invoiceTotalScalarType)]
|
||||||
|
let queryRequest = invoicesQueryRequest aggregates & qrQuery %~ (qFields ?~ fields >>> qAggregatesLimit ?~ aggregatesLimit >>> qLimit ?~ limit >>> qWhere ?~ where' >>> qOrderBy ?~ orderBy)
|
||||||
|
response <- queryGuarded queryRequest
|
||||||
|
|
||||||
|
let aggregateLimitedInvoiceRows =
|
||||||
|
_tdInvoicesRows
|
||||||
|
& filter ((^? Data.field "BillingCountry" . Data._ColumnFieldString) >>> (== Just "Canada"))
|
||||||
|
& sortOn (^? Data.field "BillingAddress")
|
||||||
|
& take aggregatesLimit
|
||||||
|
|
||||||
|
-- Limit is smaller than aggregatesLimit, so we can just take from the aggregateLimitedInvoiceRows
|
||||||
|
let invoiceRows = take limit aggregateLimitedInvoiceRows
|
||||||
|
|
||||||
|
let maxTotal =
|
||||||
|
aggregateLimitedInvoiceRows
|
||||||
|
& take limit
|
||||||
|
& mapMaybe ((^? Data.field "Total" . Data._ColumnFieldNumber))
|
||||||
|
& aggregate (Number . minimum)
|
||||||
|
|
||||||
|
let expectedAggregates = Data.mkFieldsMap [("min", maxTotal)]
|
||||||
|
let expectedRows = Data.filterColumnsByQueryFields (_qrQuery queryRequest) <$> invoiceRows
|
||||||
|
|
||||||
|
Data.responseRows response `rowsShouldBe` expectedRows
|
||||||
|
Data.responseAggregates response `jsonShouldBe` expectedAggregates
|
||||||
|
|
||||||
when (isJust relationshipCapabilities) $
|
when (isJust relationshipCapabilities) $
|
||||||
describe "Aggregates via Relationships" $ do
|
describe "Aggregates via Relationships" $ do
|
||||||
it "can query aggregates via an array relationship" $ do
|
it "can query aggregates via an array relationship" $ do
|
||||||
@ -387,8 +481,8 @@ spec TestData {..} relationshipCapabilities = describe "Aggregate Queries" $ do
|
|||||||
describe "Aggregates over ordered and paginated tables" $ do
|
describe "Aggregates over ordered and paginated tables" $ do
|
||||||
it "orders by a column" $ do
|
it "orders by a column" $ do
|
||||||
let offset = 2
|
let offset = 2
|
||||||
let limit = 5
|
let aggregatesLimit = 5
|
||||||
let orderBy = OrderBy mempty $ _tdOrderByColumn [] "Title" Descending :| []
|
let orderBy = OrderBy mempty $ _tdOrderByColumn [] "Title" Ascending :| []
|
||||||
let aggregates = Data.mkFieldsMap [("max", singleColumnAggregateMax (_tdColumnName "Title") albumTitleScalarType)]
|
let aggregates = Data.mkFieldsMap [("max", singleColumnAggregateMax (_tdColumnName "Title") albumTitleScalarType)]
|
||||||
let queryRequest =
|
let queryRequest =
|
||||||
albumsQueryRequest
|
albumsQueryRequest
|
||||||
@ -396,15 +490,15 @@ spec TestData {..} relationshipCapabilities = describe "Aggregate Queries" $ do
|
|||||||
%~ ( qAggregates ?~ aggregates
|
%~ ( qAggregates ?~ aggregates
|
||||||
>>> qOrderBy ?~ orderBy
|
>>> qOrderBy ?~ orderBy
|
||||||
>>> qOffset ?~ offset
|
>>> qOffset ?~ offset
|
||||||
>>> qLimit ?~ limit
|
>>> qAggregatesLimit ?~ aggregatesLimit
|
||||||
)
|
)
|
||||||
response <- queryGuarded queryRequest
|
response <- queryGuarded queryRequest
|
||||||
|
|
||||||
let names =
|
let names =
|
||||||
_tdAlbumsRows
|
_tdAlbumsRows
|
||||||
& sortOn (Down . (^? Data.field "Title"))
|
& sortOn ((^? Data.field "Title"))
|
||||||
& drop offset
|
& drop offset
|
||||||
& take limit
|
& take aggregatesLimit
|
||||||
& mapMaybe (^? Data.field "Title" . Data._ColumnFieldString)
|
& mapMaybe (^? Data.field "Title" . Data._ColumnFieldString)
|
||||||
|
|
||||||
let expectedAggregates = Data.mkFieldsMap [("max", aggregate (String . maximum) names)]
|
let expectedAggregates = Data.mkFieldsMap [("max", aggregate (String . maximum) names)]
|
||||||
@ -415,7 +509,7 @@ spec TestData {..} relationshipCapabilities = describe "Aggregate Queries" $ do
|
|||||||
when (isJust relationshipCapabilities) . describe "involving related tables in the ordering" $ do
|
when (isJust relationshipCapabilities) . describe "involving related tables in the ordering" $ do
|
||||||
it "orders by a column" $ do
|
it "orders by a column" $ do
|
||||||
let offset = 10
|
let offset = 10
|
||||||
let limit = 50
|
let aggregatesLimit = 50
|
||||||
let orderByRelations = HashMap.fromList [(_tdArtistRelationshipName, OrderByRelation Nothing mempty)]
|
let orderByRelations = HashMap.fromList [(_tdArtistRelationshipName, OrderByRelation Nothing mempty)]
|
||||||
let orderBy =
|
let orderBy =
|
||||||
OrderBy orderByRelations $
|
OrderBy orderByRelations $
|
||||||
@ -431,7 +525,7 @@ spec TestData {..} relationshipCapabilities = describe "Aggregate Queries" $ do
|
|||||||
%~ ( qAggregates ?~ aggregates
|
%~ ( qAggregates ?~ aggregates
|
||||||
>>> qOrderBy ?~ orderBy
|
>>> qOrderBy ?~ orderBy
|
||||||
>>> qOffset ?~ offset
|
>>> qOffset ?~ offset
|
||||||
>>> qLimit ?~ limit
|
>>> qAggregatesLimit ?~ aggregatesLimit
|
||||||
)
|
)
|
||||||
response <- queryGuarded queryRequest
|
response <- queryGuarded queryRequest
|
||||||
|
|
||||||
@ -442,7 +536,7 @@ spec TestData {..} relationshipCapabilities = describe "Aggregate Queries" $ do
|
|||||||
_tdAlbumsRows
|
_tdAlbumsRows
|
||||||
& sortOn (\album -> getRelatedArtist album ^? _Just . Data.field "Name")
|
& sortOn (\album -> getRelatedArtist album ^? _Just . Data.field "Name")
|
||||||
& drop offset
|
& drop offset
|
||||||
& take limit
|
& take aggregatesLimit
|
||||||
& mapMaybe (^? Data.field "Title" . Data._ColumnFieldString)
|
& mapMaybe (^? Data.field "Title" . Data._ColumnFieldString)
|
||||||
|
|
||||||
let expectedAggregates = Data.mkFieldsMap [("max", aggregate (String . maximum) names)]
|
let expectedAggregates = Data.mkFieldsMap [("max", aggregate (String . maximum) names)]
|
||||||
@ -452,7 +546,7 @@ spec TestData {..} relationshipCapabilities = describe "Aggregate Queries" $ do
|
|||||||
|
|
||||||
it "orders by an aggregate" $ do
|
it "orders by an aggregate" $ do
|
||||||
let offset = 15
|
let offset = 15
|
||||||
let limit = 10
|
let aggregatesLimit = 10
|
||||||
let orderByRelations = HashMap.fromList [(_tdTracksRelationshipName, OrderByRelation Nothing mempty)]
|
let orderByRelations = HashMap.fromList [(_tdTracksRelationshipName, OrderByRelation Nothing mempty)]
|
||||||
let orderBy =
|
let orderBy =
|
||||||
OrderBy orderByRelations $
|
OrderBy orderByRelations $
|
||||||
@ -468,7 +562,7 @@ spec TestData {..} relationshipCapabilities = describe "Aggregate Queries" $ do
|
|||||||
%~ ( qAggregates ?~ aggregates
|
%~ ( qAggregates ?~ aggregates
|
||||||
>>> qOrderBy ?~ orderBy
|
>>> qOrderBy ?~ orderBy
|
||||||
>>> qOffset ?~ offset
|
>>> qOffset ?~ offset
|
||||||
>>> qLimit ?~ limit
|
>>> qAggregatesLimit ?~ aggregatesLimit
|
||||||
)
|
)
|
||||||
response <- queryGuarded queryRequest
|
response <- queryGuarded queryRequest
|
||||||
|
|
||||||
@ -480,7 +574,7 @@ spec TestData {..} relationshipCapabilities = describe "Aggregate Queries" $ do
|
|||||||
_tdAlbumsRows
|
_tdAlbumsRows
|
||||||
& sortOn (\album -> (Down $ getRelatedTracksCount album, Down $ album ^? Data.field "Title" . Data._ColumnFieldString))
|
& sortOn (\album -> (Down $ getRelatedTracksCount album, Down $ album ^? Data.field "Title" . Data._ColumnFieldString))
|
||||||
& drop offset
|
& drop offset
|
||||||
& take limit
|
& take aggregatesLimit
|
||||||
& mapMaybe (^? Data.field "Title" . Data._ColumnFieldString)
|
& mapMaybe (^? Data.field "Title" . Data._ColumnFieldString)
|
||||||
|
|
||||||
let expectedAggregates = Data.mkFieldsMap [("max", aggregate (String . maximum) names)]
|
let expectedAggregates = Data.mkFieldsMap [("max", aggregate (String . maximum) names)]
|
||||||
@ -549,7 +643,7 @@ spec TestData {..} relationshipCapabilities = describe "Aggregate Queries" $ do
|
|||||||
tracksAggregates = Data.mkFieldsMap [("aggregate_count", StarCount)]
|
tracksAggregates = Data.mkFieldsMap [("aggregate_count", StarCount)]
|
||||||
tracksWhere = ApplyBinaryComparisonOperator LessThan (_tdCurrentComparisonColumn "Milliseconds" millisecondsScalarType) (Data.scalarValueComparison (Number 300000) millisecondsScalarType)
|
tracksWhere = ApplyBinaryComparisonOperator LessThan (_tdCurrentComparisonColumn "Milliseconds" millisecondsScalarType) (Data.scalarValueComparison (Number 300000) millisecondsScalarType)
|
||||||
tracksOrderBy = OrderBy mempty $ _tdOrderByColumn [] "Name" Descending :| []
|
tracksOrderBy = OrderBy mempty $ _tdOrderByColumn [] "Name" Descending :| []
|
||||||
tracksSubquery = Query (Just tracksFields) (Just tracksAggregates) Nothing Nothing (Just tracksWhere) (Just tracksOrderBy)
|
tracksSubquery = Query (Just tracksFields) (Just tracksAggregates) Nothing Nothing Nothing (Just tracksWhere) (Just tracksOrderBy)
|
||||||
albumsFields =
|
albumsFields =
|
||||||
Data.mkFieldsMap
|
Data.mkFieldsMap
|
||||||
[ ("nodes_Title", _tdColumnField _tdAlbumsTableName "Title"),
|
[ ("nodes_Title", _tdColumnField _tdAlbumsTableName "Title"),
|
||||||
@ -568,7 +662,7 @@ spec TestData {..} relationshipCapabilities = describe "Aggregate Queries" $ do
|
|||||||
ApplyBinaryComparisonOperator LessThan (_tdCurrentComparisonColumn "Name" artistNameScalarType) (Data.scalarValueComparison (String "B") artistNameScalarType)
|
ApplyBinaryComparisonOperator LessThan (_tdCurrentComparisonColumn "Name" artistNameScalarType) (Data.scalarValueComparison (String "B") artistNameScalarType)
|
||||||
]
|
]
|
||||||
artistOrderBy = OrderBy mempty $ _tdOrderByColumn [] "Name" Descending :| []
|
artistOrderBy = OrderBy mempty $ _tdOrderByColumn [] "Name" Descending :| []
|
||||||
artistQuery = Query (Just artistFields) Nothing (Just 3) (Just 1) (Just artistWhere) (Just artistOrderBy)
|
artistQuery = Query (Just artistFields) Nothing Nothing (Just 3) (Just 1) (Just artistWhere) (Just artistOrderBy)
|
||||||
in QueryRequest
|
in QueryRequest
|
||||||
_tdArtistsTableName
|
_tdArtistsTableName
|
||||||
[ Data.onlyKeepRelationships [_tdAlbumsRelationshipName] _tdArtistsTableRelationships,
|
[ Data.onlyKeepRelationships [_tdAlbumsRelationshipName] _tdArtistsTableRelationships,
|
||||||
|
@ -146,6 +146,7 @@ translateAnnSelect sessionVariables translateFieldsAndAggregates tableName selec
|
|||||||
API.Query
|
API.Query
|
||||||
{ _qFields = mapFieldNameHashMap <$> _faaFields,
|
{ _qFields = mapFieldNameHashMap <$> _faaFields,
|
||||||
_qAggregates = mapFieldNameHashMap <$> _faaAggregates,
|
_qAggregates = mapFieldNameHashMap <$> _faaAggregates,
|
||||||
|
_qAggregatesLimit = _saLimit (_asnArgs selectG) <* _faaAggregates, -- Only include the aggregates limit if we actually have aggregrates
|
||||||
_qLimit =
|
_qLimit =
|
||||||
fmap getMin $
|
fmap getMin $
|
||||||
foldMap
|
foldMap
|
||||||
@ -310,6 +311,7 @@ translateAnnField sessionVariables sourceTableName = \case
|
|||||||
{ _qFields = Just $ mapFieldNameHashMap fields,
|
{ _qFields = Just $ mapFieldNameHashMap fields,
|
||||||
_qAggregates = mempty,
|
_qAggregates = mempty,
|
||||||
_qWhere = whereClause,
|
_qWhere = whereClause,
|
||||||
|
_qAggregatesLimit = Nothing,
|
||||||
_qLimit = Nothing,
|
_qLimit = Nothing,
|
||||||
_qOffset = Nothing,
|
_qOffset = Nothing,
|
||||||
_qOrderBy = Nothing
|
_qOrderBy = Nothing
|
||||||
|
@ -89,6 +89,7 @@ mkRemoteRelationshipPlan sessionVariables _sourceConfig joinIds joinIdsSchema ar
|
|||||||
API.Query
|
API.Query
|
||||||
{ _qFields = Just $ mapFieldNameHashMap fields,
|
{ _qFields = Just $ mapFieldNameHashMap fields,
|
||||||
_qAggregates = Nothing,
|
_qAggregates = Nothing,
|
||||||
|
_qAggregatesLimit = Nothing,
|
||||||
_qLimit = Nothing,
|
_qLimit = Nothing,
|
||||||
_qOffset = Nothing,
|
_qOffset = Nothing,
|
||||||
_qWhere = whereClause,
|
_qWhere = whereClause,
|
||||||
|
@ -41,7 +41,7 @@ spec = do
|
|||||||
}
|
}
|
||||||
|]
|
|]
|
||||||
describe "RelationshipField" $ do
|
describe "RelationshipField" $ do
|
||||||
let query = Query (Just mempty) Nothing Nothing Nothing Nothing Nothing
|
let query = Query (Just mempty) Nothing Nothing Nothing Nothing Nothing Nothing
|
||||||
testToFromJSONToSchema
|
testToFromJSONToSchema
|
||||||
(RelField $ RelationshipField (RelationshipName "a_relationship") query)
|
(RelField $ RelationshipField (RelationshipName "a_relationship") query)
|
||||||
[aesonQQ|
|
[aesonQQ|
|
||||||
@ -57,6 +57,7 @@ spec = do
|
|||||||
Query
|
Query
|
||||||
{ _qFields = Just $ HashMap.fromList [(FieldName "my_field_alias", ColumnField (ColumnName "my_field_name") (ScalarType "string"))],
|
{ _qFields = Just $ HashMap.fromList [(FieldName "my_field_alias", ColumnField (ColumnName "my_field_name") (ScalarType "string"))],
|
||||||
_qAggregates = Just $ HashMap.fromList [(FieldName "my_aggregate", StarCount)],
|
_qAggregates = Just $ HashMap.fromList [(FieldName "my_aggregate", StarCount)],
|
||||||
|
_qAggregatesLimit = Just 5,
|
||||||
_qLimit = Just 10,
|
_qLimit = Just 10,
|
||||||
_qOffset = Just 20,
|
_qOffset = Just 20,
|
||||||
_qWhere = Just $ And [],
|
_qWhere = Just $ And [],
|
||||||
@ -67,6 +68,7 @@ spec = do
|
|||||||
[aesonQQ|
|
[aesonQQ|
|
||||||
{ "fields": {"my_field_alias": {"type": "column", "column": "my_field_name", "column_type": "string"}},
|
{ "fields": {"my_field_alias": {"type": "column", "column": "my_field_name", "column_type": "string"}},
|
||||||
"aggregates": { "my_aggregate": { "type": "star_count" } },
|
"aggregates": { "my_aggregate": { "type": "star_count" } },
|
||||||
|
"aggregates_limit": 5,
|
||||||
"limit": 10,
|
"limit": 10,
|
||||||
"offset": 20,
|
"offset": 20,
|
||||||
"where": {"type": "and", "expressions": []},
|
"where": {"type": "and", "expressions": []},
|
||||||
@ -91,7 +93,7 @@ spec = do
|
|||||||
QueryRequest
|
QueryRequest
|
||||||
{ _qrTable = TableName ["my_table"],
|
{ _qrTable = TableName ["my_table"],
|
||||||
_qrTableRelationships = [],
|
_qrTableRelationships = [],
|
||||||
_qrQuery = Query (Just mempty) Nothing Nothing Nothing Nothing Nothing,
|
_qrQuery = Query (Just mempty) Nothing Nothing Nothing Nothing Nothing Nothing,
|
||||||
_qrForeach = Just (HashMap.fromList [(ColumnName "my_id", ScalarValue (J.Number 666) (ScalarType "number"))] :| [])
|
_qrForeach = Just (HashMap.fromList [(ColumnName "my_id", ScalarValue (J.Number 666) (ScalarType "number"))] :| [])
|
||||||
}
|
}
|
||||||
testToFromJSONToSchema
|
testToFromJSONToSchema
|
||||||
@ -181,6 +183,7 @@ genQuery =
|
|||||||
<*> Gen.maybe (genFieldMap genAggregate)
|
<*> Gen.maybe (genFieldMap genAggregate)
|
||||||
<*> Gen.maybe (Gen.int defaultRange)
|
<*> Gen.maybe (Gen.int defaultRange)
|
||||||
<*> Gen.maybe (Gen.int defaultRange)
|
<*> Gen.maybe (Gen.int defaultRange)
|
||||||
|
<*> Gen.maybe (Gen.int defaultRange)
|
||||||
<*> Gen.maybe genExpression
|
<*> Gen.maybe genExpression
|
||||||
<*> Gen.maybe genOrderBy
|
<*> Gen.maybe genOrderBy
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user