mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-14 08:02:15 +03:00
Use JSON instead of GraphQL for comparison operators
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/6563 GitOrigin-RevId: 0819414df199292e0146ce3009295ce3e49f2439
This commit is contained in:
parent
72dbafc319
commit
87bcdb97c7
@ -133,9 +133,8 @@ The `GET /capabilities` endpoint is used by `graphql-engine` to discover the cap
|
||||
"column_nullability": "nullable_and_non_nullable"
|
||||
},
|
||||
"relationships": {},
|
||||
"graphql_schema": "scalar DateTime\n\ninput DateTimeComparisons {\n in_year: Number\n}",
|
||||
"scalar_types": {
|
||||
"DateTime": {"comparisonType": "DateTimeComparisons"}
|
||||
"DateTime": {"comparison_operators": {"DateTime": {"in_year": "Number"}}}
|
||||
}
|
||||
},
|
||||
"config_schemas": {
|
||||
@ -166,7 +165,6 @@ The `capabilities` section describes the _capabilities_ of the service. This inc
|
||||
- `data_schema`: What sorts of features the agent supports when describing its data schema
|
||||
- `relationships`: whether or not the agent supports relationships
|
||||
- `scalar_types`: custom scalar types and the operations they support. See [Scalar types capabilities](#scalar-type-capabilities).
|
||||
- `graphql_schema`: a GraphQL schema document containing type definitions referenced by the `scalar_types` capabilities.
|
||||
|
||||
The `config_schema` property contains an [OpenAPI 3 Schema](https://swagger.io/specification/#schema-object) object that represents the schema of the configuration object. It can use references (`$ref`) to refer to other schemas defined in the `other_schemas` object by name.
|
||||
|
||||
@ -180,7 +178,7 @@ If the agent only supports table columns that are always nullable, then it shoul
|
||||
#### Scalar type capabilities
|
||||
|
||||
The agent is expected to support a default set of scalar types (`Number`, `String`, `Bool`) and a default set of [comparison operators](#filters) on these types.
|
||||
Agents may optionally declare support for their own custom scalar types and custom comparison operators on those types.
|
||||
Agents may optionally declare support for their own custom scalar types, along with custom comparison operators and aggregate functions on those types.
|
||||
Hasura GraphQL Engine does not validate the JSON format for values of custom scalar types.
|
||||
It passes them through transparently to the agent when they are used as GraphQL input values and returns them transparently when they are produced by the agent.
|
||||
It is the agent's responsibility to validate the values provided as GraphQL inputs.
|
||||
@ -188,33 +186,31 @@ It is the agent's responsibility to validate the values provided as GraphQL inpu
|
||||
Custom scalar types are declared by adding a property to the `scalar_types` section of the [capabilities](#capabilities-and-configuration-schema) and
|
||||
by adding scalar type declaration with the same name in the `graphql_schema` capabilities property.
|
||||
|
||||
Custom comparison types can be defined by adding a `comparisonType` property to the scalar type capabilities object.
|
||||
The `comparisonType` property gives the name of a GraphQL input object type, which must be defined in the `graphql_schema` capabilities property.
|
||||
The input object type will be spliced into the `where` argument for any columns of the scalar type in the GraphQL schema.
|
||||
Custom comparison types can be defined by adding a `comparison_operators` property to the scalar type capabilities object.
|
||||
The `comparison_operators` property is an object where each key specifies a comparison operator name.
|
||||
The operator name must be a valid GraphQL name.
|
||||
The value associated with each key should be a string specifying the argument type, which must be a valid scalar type.
|
||||
|
||||
Custom aggregate functions can be defined by adding a `aggregate_functions` property to the scalar type capabilities object.
|
||||
Custom aggregate functions can be defined by adding an `aggregate_functions` property to the scalar type capabilities object.
|
||||
The `aggregate_functions` property must be an object mapping aggregate function names to their result types.
|
||||
Aggregate function names must be must be valid GraphQL names.
|
||||
Result types must be valid scalar types.
|
||||
|
||||
Example:
|
||||
|
||||
```yaml
|
||||
capabilities:
|
||||
graphql_schema: |
|
||||
scalar DateTime
|
||||
|
||||
input DateTimeComparisons {
|
||||
in_year: Number
|
||||
}
|
||||
scalar_types:
|
||||
DateTime:
|
||||
comparisonType: DateTimeComparisons
|
||||
comparison_operators:
|
||||
in_year: Number
|
||||
aggregate_functions:
|
||||
max: 'DateTime'
|
||||
min: 'DateTime'
|
||||
```
|
||||
|
||||
This example declares a custom scalar type `DateTime`, with comparison operators defined by the GraphQL input object type `DateTimeComparisons`.
|
||||
The input type `DateTimeComparisons` defines one comparison operator `in_year` which takes a `Number` argument
|
||||
This example declares a custom scalar type `DateTime`.
|
||||
The type supports a comparison operator `in_year`, which takes an argument of type `Number`.
|
||||
|
||||
An example GraphQL query using the custom comparison operator might look like below:
|
||||
```graphql
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@hasura/dc-api-types",
|
||||
"version": "0.13.0",
|
||||
"version": "0.14.0",
|
||||
"description": "Hasura GraphQL Engine Data Connector Agent API types",
|
||||
"author": "Hasura (https://github.com/hasura/graphql-engine)",
|
||||
"license": "Apache-2.0",
|
||||
|
@ -312,9 +312,6 @@
|
||||
"explain": {
|
||||
"$ref": "#/components/schemas/ExplainCapabilities"
|
||||
},
|
||||
"graphql_schema": {
|
||||
"$ref": "#/components/schemas/GraphQLTypeDefinitions"
|
||||
},
|
||||
"metrics": {
|
||||
"$ref": "#/components/schemas/MetricsCapabilities"
|
||||
},
|
||||
@ -367,10 +364,6 @@
|
||||
"QueryCapabilities": {},
|
||||
"MutationCapabilities": {},
|
||||
"SubscriptionCapabilities": {},
|
||||
"GraphQLName": {
|
||||
"description": "A valid GraphQL name",
|
||||
"type": "string"
|
||||
},
|
||||
"ScalarType": {
|
||||
"additionalProperties": true,
|
||||
"anyOf": [
|
||||
@ -387,6 +380,13 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"ComparisonOperators": {
|
||||
"additionalProperties": {
|
||||
"$ref": "#/components/schemas/ScalarType"
|
||||
},
|
||||
"description": "A map from comparison operator names to their argument types.\nOperator and argument type names must be valid GraphQL names.\nResult type names must be defined scalar types - either builtin or declared in ScalarTypesCapabilities.\n",
|
||||
"type": "object"
|
||||
},
|
||||
"AggregateFunctions": {
|
||||
"additionalProperties": {
|
||||
"$ref": "#/components/schemas/ScalarType"
|
||||
@ -395,13 +395,13 @@
|
||||
"type": "object"
|
||||
},
|
||||
"ScalarTypeCapabilities": {
|
||||
"description": "Capabilities of a scalar type.\ncomparison_type: Name of the GraphQL input object to be used for comparison operations on the scalar type. The input object type must be defined in the `graphql_schema`.\naggregate_functions: The aggregate functions supported by the scalar type.\n",
|
||||
"description": "Capabilities of a scalar type.\ncomparison_operators: The comparison operators supported by the scalar type.\naggregate_functions: The aggregate functions supported by the scalar type.\n",
|
||||
"properties": {
|
||||
"aggregate_functions": {
|
||||
"$ref": "#/components/schemas/AggregateFunctions"
|
||||
},
|
||||
"comparison_type": {
|
||||
"$ref": "#/components/schemas/GraphQLName"
|
||||
"comparison_operators": {
|
||||
"$ref": "#/components/schemas/ComparisonOperators"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
@ -413,10 +413,6 @@
|
||||
"description": "A map from scalar type names to their capabilities.\nKeys must be valid GraphQL names and must be defined as scalar types in the `graphql_schema`\n",
|
||||
"type": "object"
|
||||
},
|
||||
"GraphQLTypeDefinitions": {
|
||||
"description": "A valid GraphQL schema document containing type definitions",
|
||||
"type": "string"
|
||||
},
|
||||
"RelationshipCapabilities": {},
|
||||
"SubqueryComparisonCapabilities": {
|
||||
"nullable": true,
|
||||
|
@ -20,6 +20,7 @@ export type { ColumnInfo } from './models/ColumnInfo';
|
||||
export type { ColumnNullability } from './models/ColumnNullability';
|
||||
export type { ComparisonCapabilities } from './models/ComparisonCapabilities';
|
||||
export type { ComparisonColumn } from './models/ComparisonColumn';
|
||||
export type { ComparisonOperators } from './models/ComparisonOperators';
|
||||
export type { ComparisonValue } from './models/ComparisonValue';
|
||||
export type { ConfigSchemaResponse } from './models/ConfigSchemaResponse';
|
||||
export type { Constraint } from './models/Constraint';
|
||||
@ -32,8 +33,6 @@ export type { ExplainCapabilities } from './models/ExplainCapabilities';
|
||||
export type { ExplainResponse } from './models/ExplainResponse';
|
||||
export type { Expression } from './models/Expression';
|
||||
export type { Field } from './models/Field';
|
||||
export type { GraphQLName } from './models/GraphQLName';
|
||||
export type { GraphQLTypeDefinitions } from './models/GraphQLTypeDefinitions';
|
||||
export type { MetricsCapabilities } from './models/MetricsCapabilities';
|
||||
export type { MutationCapabilities } from './models/MutationCapabilities';
|
||||
export type { NotExpression } from './models/NotExpression';
|
||||
|
@ -5,7 +5,6 @@
|
||||
import type { ComparisonCapabilities } from './ComparisonCapabilities';
|
||||
import type { DataSchemaCapabilities } from './DataSchemaCapabilities';
|
||||
import type { ExplainCapabilities } from './ExplainCapabilities';
|
||||
import type { GraphQLTypeDefinitions } from './GraphQLTypeDefinitions';
|
||||
import type { MetricsCapabilities } from './MetricsCapabilities';
|
||||
import type { MutationCapabilities } from './MutationCapabilities';
|
||||
import type { QueryCapabilities } from './QueryCapabilities';
|
||||
@ -18,7 +17,6 @@ export type Capabilities = {
|
||||
comparisons?: ComparisonCapabilities;
|
||||
data_schema?: DataSchemaCapabilities;
|
||||
explain?: ExplainCapabilities;
|
||||
graphql_schema?: GraphQLTypeDefinitions;
|
||||
metrics?: MetricsCapabilities;
|
||||
mutations?: MutationCapabilities;
|
||||
queries?: QueryCapabilities;
|
||||
|
13
dc-agents/dc-api-types/src/models/ComparisonOperators.ts
Normal file
13
dc-agents/dc-api-types/src/models/ComparisonOperators.ts
Normal file
@ -0,0 +1,13 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
import type { ScalarType } from './ScalarType';
|
||||
|
||||
/**
|
||||
* A map from comparison operator names to their argument types.
|
||||
* Operator and argument type names must be valid GraphQL names.
|
||||
* Result type names must be defined scalar types - either builtin or declared in ScalarTypesCapabilities.
|
||||
*
|
||||
*/
|
||||
export type ComparisonOperators = Record<string, ScalarType>;
|
@ -1,8 +0,0 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
/**
|
||||
* A valid GraphQL name
|
||||
*/
|
||||
export type GraphQLName = string;
|
@ -1,8 +0,0 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
/**
|
||||
* A valid GraphQL schema document containing type definitions
|
||||
*/
|
||||
export type GraphQLTypeDefinitions = string;
|
@ -3,16 +3,16 @@
|
||||
/* eslint-disable */
|
||||
|
||||
import type { AggregateFunctions } from './AggregateFunctions';
|
||||
import type { GraphQLName } from './GraphQLName';
|
||||
import type { ComparisonOperators } from './ComparisonOperators';
|
||||
|
||||
/**
|
||||
* Capabilities of a scalar type.
|
||||
* comparison_type: Name of the GraphQL input object to be used for comparison operations on the scalar type. The input object type must be defined in the `graphql_schema`.
|
||||
* comparison_operators: The comparison operators supported by the scalar type.
|
||||
* aggregate_functions: The aggregate functions supported by the scalar type.
|
||||
*
|
||||
*/
|
||||
export type ScalarTypeCapabilities = {
|
||||
aggregate_functions?: AggregateFunctions;
|
||||
comparison_type?: GraphQLName;
|
||||
comparison_operators?: ComparisonOperators;
|
||||
};
|
||||
|
||||
|
10
dc-agents/package-lock.json
generated
10
dc-agents/package-lock.json
generated
@ -24,7 +24,7 @@
|
||||
},
|
||||
"dc-api-types": {
|
||||
"name": "@hasura/dc-api-types",
|
||||
"version": "0.13.0",
|
||||
"version": "0.14.0",
|
||||
"license": "Apache-2.0",
|
||||
"devDependencies": {
|
||||
"@tsconfig/node16": "^1.0.3",
|
||||
@ -631,7 +631,7 @@
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@fastify/cors": "^7.0.0",
|
||||
"@hasura/dc-api-types": "0.13.0",
|
||||
"@hasura/dc-api-types": "0.14.0",
|
||||
"fastify": "^3.29.0",
|
||||
"mathjs": "^11.0.0",
|
||||
"pino-pretty": "^8.0.0",
|
||||
@ -1389,7 +1389,7 @@
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@fastify/cors": "^8.1.0",
|
||||
"@hasura/dc-api-types": "0.13.0",
|
||||
"@hasura/dc-api-types": "0.14.0",
|
||||
"fastify": "^4.4.0",
|
||||
"fastify-metrics": "^9.2.1",
|
||||
"nanoid": "^3.3.4",
|
||||
@ -3122,7 +3122,7 @@
|
||||
"version": "file:reference",
|
||||
"requires": {
|
||||
"@fastify/cors": "^7.0.0",
|
||||
"@hasura/dc-api-types": "0.13.0",
|
||||
"@hasura/dc-api-types": "0.14.0",
|
||||
"@tsconfig/node16": "^1.0.3",
|
||||
"@types/node": "^16.11.49",
|
||||
"@types/xml2js": "^0.4.11",
|
||||
@ -3613,7 +3613,7 @@
|
||||
"version": "file:sqlite",
|
||||
"requires": {
|
||||
"@fastify/cors": "^8.1.0",
|
||||
"@hasura/dc-api-types": "0.13.0",
|
||||
"@hasura/dc-api-types": "0.14.0",
|
||||
"@tsconfig/node16": "^1.0.3",
|
||||
"@types/node": "^16.11.49",
|
||||
"@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",
|
||||
"dependencies": {
|
||||
"@fastify/cors": "^7.0.0",
|
||||
"@hasura/dc-api-types": "0.13.0",
|
||||
"@hasura/dc-api-types": "0.14.0",
|
||||
"fastify": "^3.29.0",
|
||||
"mathjs": "^11.0.0",
|
||||
"pino-pretty": "^8.0.0",
|
||||
@ -44,7 +44,7 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@hasura/dc-api-types": {
|
||||
"version": "0.13.0",
|
||||
"version": "0.14.0",
|
||||
"license": "Apache-2.0",
|
||||
"devDependencies": {
|
||||
"@tsconfig/node16": "^1.0.3",
|
||||
|
@ -22,7 +22,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@fastify/cors": "^7.0.0",
|
||||
"@hasura/dc-api-types": "0.13.0",
|
||||
"@hasura/dc-api-types": "0.14.0",
|
||||
"fastify": "^3.29.0",
|
||||
"mathjs": "^11.0.0",
|
||||
"pino-pretty": "^8.0.0",
|
||||
|
@ -1,17 +1,11 @@
|
||||
import { configSchema } from "./config"
|
||||
import { Capabilities, CapabilitiesResponse, ScalarTypeCapabilities, ScalarTypesCapabilities } from "@hasura/dc-api-types"
|
||||
|
||||
const schemaDoc: string =
|
||||
`scalar DateTime
|
||||
|
||||
input DateTimeComparisons {
|
||||
same_day_as: DateTime
|
||||
in_year: Int
|
||||
}
|
||||
`
|
||||
|
||||
const dateTimeCapabilities: ScalarTypeCapabilities = {
|
||||
comparison_type: 'DateTimeComparisons',
|
||||
comparison_operators: {
|
||||
same_day_as: 'DateTime',
|
||||
in_year: 'Int'
|
||||
},
|
||||
aggregate_functions: {
|
||||
max: 'DateTime',
|
||||
min: 'DateTime'
|
||||
@ -43,7 +37,6 @@ const capabilities: Capabilities = {
|
||||
supports_relations: true
|
||||
}
|
||||
},
|
||||
graphql_schema: schemaDoc,
|
||||
scalar_types: scalarTypes
|
||||
}
|
||||
|
||||
|
4
dc-agents/sqlite/package-lock.json
generated
4
dc-agents/sqlite/package-lock.json
generated
@ -10,7 +10,7 @@
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@fastify/cors": "^8.1.0",
|
||||
"@hasura/dc-api-types": "0.13.0",
|
||||
"@hasura/dc-api-types": "0.14.0",
|
||||
"fastify": "^4.4.0",
|
||||
"fastify-metrics": "^9.2.1",
|
||||
"nanoid": "^3.3.4",
|
||||
@ -54,7 +54,7 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@hasura/dc-api-types": {
|
||||
"version": "0.13.0",
|
||||
"version": "0.14.0",
|
||||
"license": "Apache-2.0",
|
||||
"devDependencies": {
|
||||
"@tsconfig/node16": "^1.0.3",
|
||||
|
@ -22,7 +22,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@fastify/cors": "^8.1.0",
|
||||
"@hasura/dc-api-types": "0.13.0",
|
||||
"@hasura/dc-api-types": "0.14.0",
|
||||
"fastify-metrics": "^9.2.1",
|
||||
"fastify": "^4.4.0",
|
||||
"nanoid": "^3.3.4",
|
||||
|
@ -10,7 +10,6 @@ export const capabilitiesResponse: CapabilitiesResponse = {
|
||||
supports_foreign_keys: true,
|
||||
column_nullability: "nullable_and_non_nullable",
|
||||
},
|
||||
graphql_schema: "scalar DateTime",
|
||||
scalar_types: {
|
||||
DateTime: {}
|
||||
},
|
||||
|
@ -13,10 +13,10 @@ module Hasura.Backends.DataConnector.API.V0.Capabilities
|
||||
QueryCapabilities (..),
|
||||
MutationCapabilities (..),
|
||||
SubscriptionCapabilities (..),
|
||||
ComparisonOperators (..),
|
||||
AggregateFunctions (..),
|
||||
ScalarTypeCapabilities (..),
|
||||
ScalarTypesCapabilities (..),
|
||||
GraphQLTypeDefinitions,
|
||||
RelationshipCapabilities (..),
|
||||
ComparisonCapabilities (..),
|
||||
SubqueryComparisonCapabilities (..),
|
||||
@ -24,8 +24,6 @@ module Hasura.Backends.DataConnector.API.V0.Capabilities
|
||||
ExplainCapabilities (..),
|
||||
RawCapabilities (..),
|
||||
CapabilitiesResponse (..),
|
||||
lookupComparisonInputObjectDefinition,
|
||||
mkGraphQLTypeDefinitions,
|
||||
)
|
||||
where
|
||||
|
||||
@ -70,8 +68,7 @@ data Capabilities = Capabilities
|
||||
_cQueries :: Maybe QueryCapabilities,
|
||||
_cMutations :: Maybe MutationCapabilities,
|
||||
_cSubscriptions :: Maybe SubscriptionCapabilities,
|
||||
_cScalarTypes :: Maybe ScalarTypesCapabilities,
|
||||
_cGraphQLTypeDefinitions :: Maybe GraphQLTypeDefinitions,
|
||||
_cScalarTypes :: ScalarTypesCapabilities,
|
||||
_cRelationships :: Maybe RelationshipCapabilities,
|
||||
_cComparisons :: Maybe ComparisonCapabilities,
|
||||
_cMetrics :: Maybe MetricsCapabilities,
|
||||
@ -83,7 +80,7 @@ data Capabilities = Capabilities
|
||||
deriving (FromJSON, ToJSON, ToSchema) via Autodocodec Capabilities
|
||||
|
||||
defaultCapabilities :: Capabilities
|
||||
defaultCapabilities = Capabilities defaultDataSchemaCapabilities Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing
|
||||
defaultCapabilities = Capabilities defaultDataSchemaCapabilities Nothing Nothing Nothing mempty Nothing Nothing Nothing Nothing Nothing
|
||||
|
||||
instance HasCodec Capabilities where
|
||||
codec =
|
||||
@ -93,8 +90,7 @@ instance HasCodec Capabilities where
|
||||
<*> optionalField "queries" "The agent's query capabilities" .= _cQueries
|
||||
<*> optionalField "mutations" "The agent's mutation capabilities" .= _cMutations
|
||||
<*> optionalField "subscriptions" "The agent's subscription capabilities" .= _cSubscriptions
|
||||
<*> optionalField "scalar_types" "The agent's scalar types and their capabilities" .= _cScalarTypes
|
||||
<*> optionalField "graphql_schema" "A GraphQL Schema Document describing the agent's scalar types and input object types for comparison operators" .= _cGraphQLTypeDefinitions
|
||||
<*> optionalFieldWithOmittedDefault "scalar_types" mempty "The agent's scalar types and their capabilities" .= _cScalarTypes
|
||||
<*> optionalField "relationships" "The agent's relationship capabilities" .= _cRelationships
|
||||
<*> optionalField "comparisons" "The agent's comparison capabilities" .= _cComparisons
|
||||
<*> optionalField "metrics" "The agent's metrics capabilities" .= _cMetrics
|
||||
@ -170,11 +166,29 @@ data RelationshipCapabilities = RelationshipCapabilities {}
|
||||
instance HasCodec RelationshipCapabilities where
|
||||
codec = object "RelationshipCapabilities" $ pure RelationshipCapabilities
|
||||
|
||||
newtype ComparisonOperators = ComparisonOperators
|
||||
{ unComparisonOperators :: HashMap GQL.Syntax.Name ScalarType
|
||||
}
|
||||
deriving stock (Eq, Ord, Show, Generic)
|
||||
deriving anyclass (NFData, Hashable)
|
||||
deriving newtype (Semigroup, Monoid)
|
||||
deriving (FromJSON, ToJSON, ToSchema) via Autodocodec ComparisonOperators
|
||||
|
||||
instance HasCodec ComparisonOperators where
|
||||
codec =
|
||||
named "ComparisonOperators" $
|
||||
dimapCodec ComparisonOperators unComparisonOperators (hashMapCodec codec)
|
||||
<??> [ "A map from comparison operator names to their argument types.",
|
||||
"Operator and argument type names must be valid GraphQL names.",
|
||||
"Result type names must be defined scalar types - either builtin or declared in ScalarTypesCapabilities."
|
||||
]
|
||||
|
||||
newtype AggregateFunctions = AggregateFunctions
|
||||
{ unAggregateFunctions :: HashMap GQL.Syntax.Name ScalarType
|
||||
}
|
||||
deriving stock (Eq, Ord, Show, Generic)
|
||||
deriving anyclass (NFData, Hashable)
|
||||
deriving newtype (Semigroup, Monoid)
|
||||
deriving (FromJSON, ToJSON, ToSchema) via Autodocodec AggregateFunctions
|
||||
|
||||
instance HasCodec AggregateFunctions where
|
||||
@ -187,8 +201,8 @@ instance HasCodec AggregateFunctions where
|
||||
]
|
||||
|
||||
data ScalarTypeCapabilities = ScalarTypeCapabilities
|
||||
{ _stcComparisonInputObject :: Maybe GQL.Syntax.Name,
|
||||
_stcAggregateFunctions :: Maybe AggregateFunctions
|
||||
{ _stcComparisonOperators :: ComparisonOperators,
|
||||
_stcAggregateFunctions :: AggregateFunctions
|
||||
}
|
||||
deriving stock (Eq, Ord, Show, Generic)
|
||||
deriving anyclass (NFData, Hashable)
|
||||
@ -199,11 +213,11 @@ instance HasCodec ScalarTypeCapabilities where
|
||||
object
|
||||
"ScalarTypeCapabilities"
|
||||
( ScalarTypeCapabilities
|
||||
<$> optionalFieldWith' "comparison_type" nameCodec .= _stcComparisonInputObject
|
||||
<*> optionalField' "aggregate_functions" .= _stcAggregateFunctions
|
||||
<$> optionalFieldWithOmittedDefault' "comparison_operators" mempty .= _stcComparisonOperators
|
||||
<*> optionalFieldWithOmittedDefault' "aggregate_functions" mempty .= _stcAggregateFunctions
|
||||
)
|
||||
<??> [ "Capabilities of a scalar type.",
|
||||
"comparison_type: Name of the GraphQL input object to be used for comparison operations on the scalar type. The input object type must be defined in the `graphql_schema`.",
|
||||
"comparison_operators: The comparison operators supported by the scalar type.",
|
||||
"aggregate_functions: The aggregate functions supported by the scalar type."
|
||||
]
|
||||
|
||||
@ -223,63 +237,6 @@ instance HasCodec ScalarTypesCapabilities where
|
||||
"Keys must be valid GraphQL names and must be defined as scalar types in the `graphql_schema`"
|
||||
]
|
||||
|
||||
type TypeDefinition = GQL.Syntax.TypeDefinition () GQL.Syntax.InputValueDefinition
|
||||
|
||||
mkGraphQLTypeDefinitions :: NonEmpty TypeDefinition -> GraphQLTypeDefinitions
|
||||
mkGraphQLTypeDefinitions =
|
||||
GraphQLTypeDefinitions
|
||||
. InsOrdHashMap.fromList
|
||||
. toList
|
||||
. fmap (\td -> (getName td, td))
|
||||
where
|
||||
getName :: TypeDefinition -> GQL.Syntax.Name
|
||||
getName = \case
|
||||
GQL.Syntax.TypeDefinitionScalar GQL.Syntax.ScalarTypeDefinition {..} -> _stdName
|
||||
GQL.Syntax.TypeDefinitionObject GQL.Syntax.ObjectTypeDefinition {..} -> _otdName
|
||||
GQL.Syntax.TypeDefinitionInterface GQL.Syntax.InterfaceTypeDefinition {..} -> _itdName
|
||||
GQL.Syntax.TypeDefinitionUnion GQL.Syntax.UnionTypeDefinition {..} -> _utdName
|
||||
GQL.Syntax.TypeDefinitionEnum GQL.Syntax.EnumTypeDefinition {..} -> _etdName
|
||||
GQL.Syntax.TypeDefinitionInputObject GQL.Syntax.InputObjectTypeDefinition {..} -> _iotdName
|
||||
|
||||
newtype GraphQLTypeDefinitions = GraphQLTypeDefinitions
|
||||
{ _gtdTypeDefinitions :: InsOrdHashMap GQL.Syntax.Name TypeDefinition
|
||||
}
|
||||
deriving stock (Eq, Show, Generic)
|
||||
deriving anyclass (NFData, Hashable)
|
||||
deriving (FromJSON, ToJSON, ToSchema) via Autodocodec GraphQLTypeDefinitions
|
||||
|
||||
instance HasCodec GraphQLTypeDefinitions where
|
||||
codec =
|
||||
bimapCodec parseTypeDefinitions printTypeDefinitions (StringCodec (Just "GraphQLTypeDefinitions"))
|
||||
<?> "A valid GraphQL schema document containing type definitions"
|
||||
where
|
||||
-- Note: any `SchemaDefinition`s in the parsed `SchemaDocument` will be ignored.
|
||||
-- We don't need them, we're only interested in the `TypeDefinition`s defined in the document.
|
||||
getTypeDefinition :: GQL.Syntax.TypeSystemDefinition -> Maybe TypeDefinition
|
||||
getTypeDefinition = \case
|
||||
GQL.Syntax.TypeSystemDefinitionSchema _ -> Nothing
|
||||
GQL.Syntax.TypeSystemDefinitionType td -> Just td
|
||||
|
||||
fromSchemaDocument :: GQL.Syntax.SchemaDocument -> Either String GraphQLTypeDefinitions
|
||||
fromSchemaDocument (GQL.Syntax.SchemaDocument typeSystemDefinitions) =
|
||||
case nonEmpty $ mapMaybe getTypeDefinition typeSystemDefinitions of
|
||||
Nothing -> Left "No type definitions found in schema document"
|
||||
Just typeDefinitions -> Right $ mkGraphQLTypeDefinitions typeDefinitions
|
||||
|
||||
parseTypeDefinitions :: Text -> Either String GraphQLTypeDefinitions
|
||||
parseTypeDefinitions =
|
||||
fromSchemaDocument <=< first Text.unpack . GQL.Parser.parseSchemaDocument
|
||||
|
||||
printTypeDefinitions :: GraphQLTypeDefinitions -> Text
|
||||
printTypeDefinitions =
|
||||
toStrict
|
||||
. Builder.toLazyText
|
||||
. GQL.Printer.schemaDocument
|
||||
. GQL.Syntax.SchemaDocument
|
||||
. fmap GQL.Syntax.TypeSystemDefinitionType
|
||||
. toList
|
||||
. _gtdTypeDefinitions
|
||||
|
||||
data ComparisonCapabilities = ComparisonCapabilities
|
||||
{_ccSubqueryComparisonCapabilities :: Maybe SubqueryComparisonCapabilities}
|
||||
deriving stock (Eq, Ord, Show, Generic, Data)
|
||||
@ -365,14 +322,3 @@ instance ToSchema CapabilitiesResponse where
|
||||
}
|
||||
|
||||
pure $ NamedSchema (Just "CapabilitiesResponse") schema
|
||||
|
||||
lookupComparisonInputObjectDefinition :: Capabilities -> ScalarType -> Maybe (GQL.Syntax.InputObjectTypeDefinition GQL.Syntax.InputValueDefinition)
|
||||
lookupComparisonInputObjectDefinition Capabilities {..} typeName = do
|
||||
scalarTypesMap <- _cScalarTypes
|
||||
ScalarTypeCapabilities {..} <- HashMap.lookup typeName $ unScalarTypesCapabilities scalarTypesMap
|
||||
comparisonTypeName <- _stcComparisonInputObject
|
||||
typeDefinitions <- _cGraphQLTypeDefinitions
|
||||
typeDefinition <- InsOrdHashMap.lookup comparisonTypeName $ _gtdTypeDefinitions typeDefinitions
|
||||
case typeDefinition of
|
||||
GQL.Syntax.TypeDefinitionInputObject inputObjectTypeDefinition -> Just inputObjectTypeDefinition
|
||||
_ -> Nothing
|
||||
|
@ -42,8 +42,7 @@ capabilities =
|
||||
API._cQueries = Just API.QueryCapabilities,
|
||||
API._cMutations = Nothing,
|
||||
API._cSubscriptions = Nothing,
|
||||
API._cScalarTypes = Nothing,
|
||||
API._cGraphQLTypeDefinitions = Nothing,
|
||||
API._cScalarTypes = mempty,
|
||||
API._cRelationships = Just API.RelationshipCapabilities {},
|
||||
API._cComparisons =
|
||||
Just
|
||||
|
@ -56,8 +56,6 @@ defaultBackendCapabilities = \case
|
||||
supports_foreign_keys: true
|
||||
scalar_types:
|
||||
DateTime: {}
|
||||
graphql_schema: |-
|
||||
scalar DateTime
|
||||
queries: {}
|
||||
relationships: {}
|
||||
comparisons:
|
||||
@ -74,19 +72,15 @@ defaultBackendCapabilities = \case
|
||||
supports_primary_keys: true
|
||||
supports_foreign_keys: true
|
||||
queries: {}
|
||||
graphql_schema: |-
|
||||
scalar DateTime
|
||||
|
||||
input DateTimeComparisons {in_year: Int
|
||||
same_day_as: DateTime
|
||||
}
|
||||
relationships: {}
|
||||
comparisons:
|
||||
subquery:
|
||||
supports_relations: true
|
||||
scalar_types:
|
||||
DateTime:
|
||||
comparison_type: DateTimeComparisons
|
||||
comparison_operators:
|
||||
same_day_as: DateTime
|
||||
in_year: Int
|
||||
aggregate_functions:
|
||||
max: DateTime
|
||||
min: DateTime
|
||||
|
@ -92,10 +92,10 @@ instance Backend 'DataConnector where
|
||||
getCustomAggregateOperators Adapter.SourceConfig {..} =
|
||||
HashMap.foldrWithKey insertOps mempty scalarTypesCapabilities
|
||||
where
|
||||
scalarTypesCapabilities = maybe mempty API.unScalarTypesCapabilities $ API._cScalarTypes _scCapabilities
|
||||
scalarTypesCapabilities = API.unScalarTypesCapabilities $ API._cScalarTypes _scCapabilities
|
||||
insertOps typeName API.ScalarTypeCapabilities {..} m =
|
||||
HashMap.foldrWithKey insertOp m $
|
||||
maybe mempty API.unAggregateFunctions _stcAggregateFunctions
|
||||
API.unAggregateFunctions _stcAggregateFunctions
|
||||
where
|
||||
insertOp funtionName resultTypeName =
|
||||
HashMap.insertWith HashMap.union funtionName $
|
||||
|
@ -12,7 +12,7 @@ import Data.HashMap.Strict qualified as Map
|
||||
import Data.List.NonEmpty qualified as NE
|
||||
import Data.Text.Casing (GQLNameIdentifier, fromCustomName)
|
||||
import Data.Text.Extended ((<<>))
|
||||
import Hasura.Backends.DataConnector.API.V0.Capabilities (lookupComparisonInputObjectDefinition)
|
||||
import Hasura.Backends.DataConnector.API qualified as API
|
||||
import Hasura.Backends.DataConnector.Adapter.Backend (CustomBooleanOperator (..), columnTypeToScalarType)
|
||||
import Hasura.Backends.DataConnector.Adapter.Types qualified as DC
|
||||
import Hasura.Base.Error
|
||||
@ -204,28 +204,28 @@ comparisonExps' sourceInfo columnType = P.memoizeOn 'comparisonExps' (dataConnec
|
||||
GS.C.SchemaT r m [P.InputFieldsParser n (Maybe (CustomBooleanOperator (IR.UnpreparedValue 'DataConnector)))]
|
||||
mkCustomOperators tCase collapseIfNull typeName = do
|
||||
let capabilities = sourceInfo ^. RQL.siConfiguration . DC.scCapabilities
|
||||
case lookupComparisonInputObjectDefinition capabilities (Witch.from $ DC.fromGQLType typeName) of
|
||||
case Map.lookup (Witch.from $ DC.fromGQLType typeName) (API.unScalarTypesCapabilities $ API._cScalarTypes capabilities) of
|
||||
Nothing -> pure []
|
||||
Just GQL.InputObjectTypeDefinition {..} -> do
|
||||
traverse (mkCustomOperator tCase collapseIfNull) _iotdValueDefinitions
|
||||
Just API.ScalarTypeCapabilities {..} -> do
|
||||
traverse (mkCustomOperator tCase collapseIfNull) $ Map.toList $ fmap Witch.from $ API.unComparisonOperators $ _stcComparisonOperators
|
||||
|
||||
mkCustomOperator ::
|
||||
NamingCase ->
|
||||
Options.DangerouslyCollapseBooleans ->
|
||||
GQL.InputValueDefinition ->
|
||||
(GQL.Name, DC.ScalarType) ->
|
||||
GS.C.SchemaT r m (P.InputFieldsParser n (Maybe (CustomBooleanOperator (IR.UnpreparedValue 'DataConnector))))
|
||||
mkCustomOperator tCase collapseIfNull GQL.InputValueDefinition {..} = do
|
||||
argParser <- mkArgParser _ivdType
|
||||
mkCustomOperator tCase collapseIfNull (operatorName, argType) = do
|
||||
argParser <- mkArgParser argType
|
||||
pure $
|
||||
GS.BE.mkBoolOperator tCase collapseIfNull (fromCustomName _ivdName) _ivdDescription $
|
||||
CustomBooleanOperator (GQL.unName _ivdName) . Just . Right <$> argParser
|
||||
GS.BE.mkBoolOperator tCase collapseIfNull (fromCustomName operatorName) Nothing $
|
||||
CustomBooleanOperator (GQL.unName operatorName) . Just . Right <$> argParser
|
||||
|
||||
mkArgParser :: GQL.GType -> GS.C.SchemaT r m (P.Parser 'P.Both n (IR.UnpreparedValue 'DataConnector))
|
||||
mkArgParser :: DC.ScalarType -> GS.C.SchemaT r m (P.Parser 'P.Both n (IR.UnpreparedValue 'DataConnector))
|
||||
mkArgParser argType =
|
||||
fmap IR.mkParameter
|
||||
<$> columnParser'
|
||||
(RQL.ColumnScalar $ DC.fromGQLType $ GQL.getBaseType argType)
|
||||
(GQL.Nullability $ GQL.isNotNull argType)
|
||||
(RQL.ColumnScalar argType)
|
||||
(GQL.Nullability True)
|
||||
|
||||
tableArgs' ::
|
||||
forall r m n.
|
||||
|
@ -3,10 +3,8 @@
|
||||
|
||||
module Hasura.Backends.DataConnector.API.V0.CapabilitiesSpec (spec) where
|
||||
|
||||
import Data.Aeson (Value (..))
|
||||
import Data.Aeson.QQ.Simple (aesonQQ)
|
||||
import Data.HashMap.Strict qualified as HashMap
|
||||
import Data.Text.RawString (raw)
|
||||
import Hasura.Backends.DataConnector.API.V0.Capabilities
|
||||
import Hasura.Backends.DataConnector.API.V0.ConfigSchema
|
||||
import Hasura.Backends.DataConnector.API.V0.Scalar (ScalarType (..))
|
||||
@ -15,8 +13,6 @@ import Hasura.Generator.Common
|
||||
import Hasura.Prelude
|
||||
import Hedgehog
|
||||
import Hedgehog.Gen qualified as Gen
|
||||
import Language.GraphQL.Draft.Generator (genTypeDefinition)
|
||||
import Language.GraphQL.Draft.Syntax qualified as G
|
||||
import Language.GraphQL.Draft.Syntax.QQ qualified as G
|
||||
import Test.Aeson.Utils
|
||||
import Test.Hspec
|
||||
@ -31,36 +27,21 @@ spec = do
|
||||
(CapabilitiesResponse (defaultCapabilities {_cRelationships = Just RelationshipCapabilities {}}) emptyConfigSchemaResponse)
|
||||
[aesonQQ|{"capabilities": {"relationships": {}}, "config_schemas": {"config_schema": {}, "other_schemas": {}}}|]
|
||||
describe "ScalarTypesCapabilities" $ do
|
||||
testToFromJSONToSchema (ScalarTypesCapabilities (HashMap.singleton StringTy (ScalarTypeCapabilities Nothing Nothing))) [aesonQQ|{"string": {}}|]
|
||||
testToFromJSONToSchema (ScalarTypesCapabilities (HashMap.singleton StringTy (ScalarTypeCapabilities mempty mempty))) [aesonQQ|{"string": {}}|]
|
||||
jsonOpenApiProperties genScalarTypesCapabilities
|
||||
describe "ScalarTypeCapabilities" $ do
|
||||
testToFromJSONToSchema (ScalarTypeCapabilities (Just [G.name|DateTimeComparisons|]) Nothing) [aesonQQ|{"comparison_type": "DateTimeComparisons"}|]
|
||||
describe "GraphQLTypeDefinitions" $ do
|
||||
testToFromJSONToSchema sampleGraphQLTypeDefinitions sampleGraphQLTypeDefinitionsJSON
|
||||
|
||||
sampleGraphQLTypeDefinitions :: GraphQLTypeDefinitions
|
||||
sampleGraphQLTypeDefinitions =
|
||||
mkGraphQLTypeDefinitions
|
||||
[ G.TypeDefinitionScalar $ G.ScalarTypeDefinition Nothing [G.name|DateTime|] [],
|
||||
G.TypeDefinitionInputObject $
|
||||
G.InputObjectTypeDefinition
|
||||
Nothing
|
||||
[G.name|DateTimeComparisons|]
|
||||
[]
|
||||
[ G.InputValueDefinition Nothing [G.name|after|] (G.TypeNamed (G.Nullability True) [G.name|DateTime|]) Nothing [],
|
||||
G.InputValueDefinition Nothing [G.name|before|] (G.TypeNamed (G.Nullability True) [G.name|DateTime|]) Nothing [],
|
||||
G.InputValueDefinition Nothing [G.name|in_year|] (G.TypeNamed (G.Nullability True) [G.name|Int|]) Nothing []
|
||||
]
|
||||
]
|
||||
|
||||
sampleGraphQLTypeDefinitionsJSON :: Value
|
||||
sampleGraphQLTypeDefinitionsJSON =
|
||||
[raw|scalar DateTime
|
||||
|
||||
input DateTimeComparisons {after: DateTime
|
||||
before: DateTime
|
||||
in_year: Int
|
||||
let comparisonOperators = ComparisonOperators $ HashMap.fromList [([G.name|same_day_as|], CustomTy "DateTime")]
|
||||
let aggregateFunctions = AggregateFunctions $ HashMap.fromList [([G.name|max|], CustomTy "DateTime")]
|
||||
let json =
|
||||
[aesonQQ|{
|
||||
"comparison_operators": {
|
||||
"same_day_as": "DateTime"
|
||||
},
|
||||
"aggregate_functions": {
|
||||
"max": "DateTime"
|
||||
}
|
||||
}|]
|
||||
testToFromJSONToSchema (ScalarTypeCapabilities comparisonOperators aggregateFunctions) json
|
||||
|
||||
genDataSchemaCapabilities :: MonadGen m => m DataSchemaCapabilities
|
||||
genDataSchemaCapabilities =
|
||||
@ -82,6 +63,10 @@ genMutationCapabilities = pure MutationCapabilities {}
|
||||
genSubscriptionCapabilities :: MonadGen m => m SubscriptionCapabilities
|
||||
genSubscriptionCapabilities = pure SubscriptionCapabilities {}
|
||||
|
||||
genComparisonOperators :: MonadGen m => m ComparisonOperators
|
||||
genComparisonOperators =
|
||||
ComparisonOperators <$> genHashMap (genGName defaultRange) genScalarType defaultRange
|
||||
|
||||
genAggregateFunctions :: MonadGen m => m AggregateFunctions
|
||||
genAggregateFunctions =
|
||||
AggregateFunctions <$> genHashMap (genGName defaultRange) genScalarType defaultRange
|
||||
@ -89,55 +74,13 @@ genAggregateFunctions =
|
||||
genScalarTypeCapabilities :: MonadGen m => m ScalarTypeCapabilities
|
||||
genScalarTypeCapabilities =
|
||||
ScalarTypeCapabilities
|
||||
<$> Gen.maybe (genGName defaultRange)
|
||||
<*> Gen.maybe genAggregateFunctions
|
||||
<$> genComparisonOperators
|
||||
<*> genAggregateFunctions
|
||||
|
||||
genScalarTypesCapabilities :: MonadGen m => m ScalarTypesCapabilities
|
||||
genScalarTypesCapabilities =
|
||||
ScalarTypesCapabilities <$> genHashMap genScalarType genScalarTypeCapabilities defaultRange
|
||||
|
||||
-- | 'genTypeDefinition' generates invalid type definitions so we need to filter them out.
|
||||
-- The printers also sort various lists upon printing, so we need to pre-sort them for round-tripping to work.
|
||||
-- The printer for 'ObjectTypeDefinition' prints directives in the wrong place so we only allow
|
||||
-- definitions with no directives.
|
||||
-- TODO: fix this in `graphql-parser-hs`.
|
||||
isValidTypeDefinition :: Ord inputType => G.TypeDefinition possibleTypes inputType -> Maybe (G.TypeDefinition possibleTypes inputType)
|
||||
isValidTypeDefinition = \case
|
||||
t@(G.TypeDefinitionScalar G.ScalarTypeDefinition {}) -> Just t
|
||||
G.TypeDefinitionObject G.ObjectTypeDefinition {..} -> do
|
||||
guard $ not $ null _otdFieldsDefinition
|
||||
Just $
|
||||
G.TypeDefinitionObject
|
||||
G.ObjectTypeDefinition
|
||||
{ _otdFieldsDefinition = sort _otdFieldsDefinition,
|
||||
_otdDirectives = [],
|
||||
..
|
||||
}
|
||||
G.TypeDefinitionInterface G.InterfaceTypeDefinition {..} -> do
|
||||
guard $ not $ null _itdFieldsDefinition
|
||||
Just $
|
||||
G.TypeDefinitionInterface
|
||||
G.InterfaceTypeDefinition {_itdFieldsDefinition = sort _itdFieldsDefinition, ..}
|
||||
G.TypeDefinitionUnion G.UnionTypeDefinition {..} -> do
|
||||
guard $ not $ null _utdMemberTypes
|
||||
Just $
|
||||
G.TypeDefinitionUnion
|
||||
G.UnionTypeDefinition {_utdMemberTypes = sort _utdMemberTypes, ..}
|
||||
G.TypeDefinitionEnum G.EnumTypeDefinition {..} -> do
|
||||
guard $ not $ null _etdValueDefinitions
|
||||
Just $
|
||||
G.TypeDefinitionEnum
|
||||
G.EnumTypeDefinition {_etdValueDefinitions = sort _etdValueDefinitions, ..}
|
||||
G.TypeDefinitionInputObject G.InputObjectTypeDefinition {..} -> do
|
||||
guard $ not $ null _iotdValueDefinitions
|
||||
Just $
|
||||
G.TypeDefinitionInputObject
|
||||
G.InputObjectTypeDefinition {_iotdValueDefinitions = sort _iotdValueDefinitions, ..}
|
||||
|
||||
genGraphQLTypeDefinitions :: Gen GraphQLTypeDefinitions
|
||||
genGraphQLTypeDefinitions =
|
||||
mkGraphQLTypeDefinitions <$> Gen.nonEmpty defaultRange (Gen.mapMaybe isValidTypeDefinition genTypeDefinition)
|
||||
|
||||
genRelationshipCapabilities :: MonadGen m => m RelationshipCapabilities
|
||||
genRelationshipCapabilities = pure RelationshipCapabilities {}
|
||||
|
||||
@ -167,8 +110,7 @@ genCapabilities =
|
||||
<*> Gen.maybe genQueryCapabilities
|
||||
<*> Gen.maybe genMutationCapabilities
|
||||
<*> Gen.maybe genSubscriptionCapabilities
|
||||
<*> Gen.maybe genScalarTypesCapabilities
|
||||
<*> Gen.maybe genGraphQLTypeDefinitions
|
||||
<*> genScalarTypesCapabilities
|
||||
<*> Gen.maybe genRelationshipCapabilities
|
||||
<*> Gen.maybe genComparisonCapabilities
|
||||
<*> Gen.maybe genMetricsCapabilities
|
||||
|
Loading…
Reference in New Issue
Block a user