Release OrderByExpression (#1289)

<!-- The PR description should answer 2 important questions: -->

### What

Release `OrderByExpression` and version 2 of `Model`. These have been
working behind feature flags for a while.

### How

Remove feature flags, remove `hidden` pragmas on `open-dds` metadata.

V3_GIT_ORIGIN_REV_ID: dfb7e9316171c11d2605dfbf01552db093d81d63
This commit is contained in:
Daniel Harvey 2024-10-28 17:18:04 +00:00 committed by hasura-bot
parent 84bec972ce
commit 4b285a7460
10 changed files with 600 additions and 41 deletions

View File

@ -4,6 +4,31 @@
### Added ### Added
#### Order by Nested Fields
Add support for ordering by nested fields.
Example query:
```graphql
query MyQuery {
InstitutionMany(order_by: { location: { city: Asc } }) {
id
location {
city
campuses
}
}
}
```
This will order by the value of the nested field `city` within the `location`
JSONB column.
- New metadata item `OrderByExpression`
- New metadata item `Model` version 2
### Fixed ### Fixed
### Changed ### Changed
@ -285,27 +310,6 @@ query MyQuery {
This query would return us details of `Chalmers University of Technology`, where This query would return us details of `Chalmers University of Technology`, where
`John Hughes` is a member of staff. `John Hughes` is a member of staff.
#### Order by Nested Fields
Add support for ordering by nested fields.
Example query:
```graphql
query MyQuery {
InstitutionMany(order_by: { location: { city: Asc } }) {
id
location {
city
campuses
}
}
}
```
This will order by the value of the nested field `city` within the `location`
JSONB column.
### Fixed ### Fixed
- Stack overflow error on startup. Even if the (experimental) SQL feature was - Stack overflow error on startup. Even if the (experimental) SQL feature was

View File

@ -17,7 +17,6 @@
)] )]
#[serde(rename_all = "snake_case")] #[serde(rename_all = "snake_case")]
pub enum UnstableFeature { pub enum UnstableFeature {
EnableOrderByExpressions,
EnableNdcV02Support, EnableNdcV02Support,
EnableJsonApi, EnableJsonApi,
EnableAggregationPredicates, EnableAggregationPredicates,
@ -30,9 +29,6 @@ pub fn resolve_unstable_features(
for unstable_feature in unstable_features { for unstable_feature in unstable_features {
match unstable_feature { match unstable_feature {
UnstableFeature::EnableOrderByExpressions => {
features.enable_order_by_expressions = true;
}
UnstableFeature::EnableNdcV02Support => { UnstableFeature::EnableNdcV02Support => {
features.enable_ndc_v02_support = true; features.enable_ndc_v02_support = true;
} }

View File

@ -478,7 +478,6 @@ pub fn test_execute_explain(
let configuration = metadata_resolve::configuration::Configuration { let configuration = metadata_resolve::configuration::Configuration {
unstable_features: metadata_resolve::configuration::UnstableFeatures { unstable_features: metadata_resolve::configuration::UnstableFeatures {
enable_order_by_expressions: false,
enable_ndc_v02_support: true, enable_ndc_v02_support: true,
enable_jsonapi: false, enable_jsonapi: false,
..Default::default() ..Default::default()
@ -539,7 +538,6 @@ pub(crate) fn test_metadata_resolve_configuration() -> metadata_resolve::configu
{ {
metadata_resolve::configuration::Configuration { metadata_resolve::configuration::Configuration {
unstable_features: metadata_resolve::configuration::UnstableFeatures { unstable_features: metadata_resolve::configuration::UnstableFeatures {
enable_order_by_expressions: false,
enable_ndc_v02_support: true, enable_ndc_v02_support: true,
enable_jsonapi: false, enable_jsonapi: false,
..Default::default() ..Default::default()

View File

@ -205,7 +205,6 @@ fn create_default_session() -> hasura_authn_core::Session {
fn get_metadata_resolve_configuration() -> metadata_resolve::configuration::Configuration { fn get_metadata_resolve_configuration() -> metadata_resolve::configuration::Configuration {
let unstable_features = metadata_resolve::configuration::UnstableFeatures { let unstable_features = metadata_resolve::configuration::UnstableFeatures {
enable_order_by_expressions: false,
enable_ndc_v02_support: false, enable_ndc_v02_support: false,
enable_jsonapi: true, enable_jsonapi: true,
enable_aggregation_predicates: false, enable_aggregation_predicates: false,

View File

@ -14,7 +14,6 @@ pub struct Configuration {
#[serde(default, deny_unknown_fields, rename_all = "camelCase")] #[serde(default, deny_unknown_fields, rename_all = "camelCase")]
#[allow(clippy::struct_excessive_bools)] #[allow(clippy::struct_excessive_bools)]
pub struct UnstableFeatures { pub struct UnstableFeatures {
pub enable_order_by_expressions: bool,
pub enable_ndc_v02_support: bool, pub enable_ndc_v02_support: bool,
pub enable_jsonapi: bool, pub enable_jsonapi: bool,
pub enable_aggregation_predicates: bool, pub enable_aggregation_predicates: bool,

View File

@ -81,7 +81,6 @@ fn read_test_configuration(
directory: &Path, directory: &Path,
) -> Result<configuration::Configuration, Box<dyn std::error::Error>> { ) -> Result<configuration::Configuration, Box<dyn std::error::Error>> {
let unstable_features = configuration::UnstableFeatures { let unstable_features = configuration::UnstableFeatures {
enable_order_by_expressions: false,
enable_ndc_v02_support: false, enable_ndc_v02_support: false,
enable_jsonapi: false, enable_jsonapi: false,
enable_aggregation_predicates: true, enable_aggregation_predicates: true,

View File

@ -2470,6 +2470,101 @@
}, },
"additionalProperties": false "additionalProperties": false
}, },
"ModelGraphQlDefinitionV2": {
"$id": "https://hasura.io/jsonschemas/metadata/ModelGraphQlDefinitionV2",
"title": "ModelGraphQlDefinitionV2",
"description": "The definition of how a model appears in the GraphQL API. Note: ModelGraphQlDefinitionV2 removed the `order_by_expression_type` property. See rfcs/open-dd-expression-type-changes.md.",
"examples": [
{
"selectUniques": [
{
"queryRootField": "ArticleByID",
"uniqueIdentifier": [
"article_id"
],
"description": "Description for the select unique ArticleByID"
}
],
"selectMany": {
"queryRootField": "ArticleMany",
"description": "Description for the select many ArticleMany"
},
"aggregate": {
"queryRootField": "ArticleAggregate",
"description": "Aggregate over Articles"
}
}
],
"type": "object",
"required": [
"selectUniques"
],
"properties": {
"selectUniques": {
"description": "For each select unique defined here, a query root field is added to the GraphQL API that can be used to select a unique object from the model.",
"type": "array",
"items": {
"$ref": "#/definitions/SelectUniqueGraphQlDefinition"
}
},
"selectMany": {
"description": "Select many configuration for a model adds a query root field to the GraphQl API that can be used to retrieve multiple objects from the model.",
"anyOf": [
{
"$ref": "#/definitions/SelectManyGraphQlDefinition"
},
{
"type": "null"
}
]
},
"argumentsInputType": {
"description": "The type name of the input type used to hold the arguments of the model.",
"anyOf": [
{
"$ref": "#/definitions/GraphQlTypeName"
},
{
"type": "null"
}
]
},
"apolloFederation": {
"description": "Apollo Federation configuration",
"anyOf": [
{
"$ref": "#/definitions/ModelApolloFederationConfiguration"
},
{
"type": "null"
}
]
},
"filterInputTypeName": {
"description": "The type name of the input type used to hold the filtering settings used by aggregates (etc) to filter their input before processing",
"anyOf": [
{
"$ref": "#/definitions/GraphQlTypeName"
},
{
"type": "null"
}
]
},
"aggregate": {
"description": "Configures the query root field added to the GraphQL API that can be used to aggregate over the model",
"anyOf": [
{
"$ref": "#/definitions/ModelAggregateGraphQlDefinition"
},
{
"type": "null"
}
]
}
},
"additionalProperties": false
},
"ModelName": { "ModelName": {
"$id": "https://hasura.io/jsonschemas/metadata/ModelName", "$id": "https://hasura.io/jsonschemas/metadata/ModelName",
"title": "ModelName", "title": "ModelName",
@ -2928,6 +3023,110 @@
}, },
"additionalProperties": false "additionalProperties": false
}, },
"ModelV2": {
"$id": "https://hasura.io/jsonschemas/metadata/ModelV2",
"title": "ModelV2",
"description": "The definition of a data model. A data model is a collection of objects of a particular type. Models can support one or more CRUD operations. ModelV2 implements the changes described in rfcs/open-dd-expression-type-changes.md.",
"type": "object",
"required": [
"name",
"objectType"
],
"properties": {
"name": {
"description": "The name of the data model.",
"allOf": [
{
"$ref": "#/definitions/ModelName"
}
]
},
"objectType": {
"description": "The type of the objects of which this model is a collection.",
"allOf": [
{
"$ref": "#/definitions/CustomTypeName"
}
]
},
"globalIdSource": {
"description": "Whether this model should be used as the global ID source for all objects of its type.",
"default": false,
"type": "boolean"
},
"arguments": {
"description": "A list of arguments accepted by this model. Defaults to no arguments.",
"default": [],
"type": "array",
"items": {
"$ref": "#/definitions/ArgumentDefinition"
}
},
"source": {
"description": "The source configuration for this model.",
"anyOf": [
{
"$ref": "#/definitions/ModelSource"
},
{
"type": "null"
}
]
},
"filterExpressionType": {
"description": "The boolean expression type that should be used to perform filtering on this model.",
"anyOf": [
{
"$ref": "#/definitions/CustomTypeName"
},
{
"type": "null"
}
]
},
"orderByExpression": {
"description": "The order by expression to use for this model.",
"anyOf": [
{
"$ref": "#/definitions/OrderByExpressionName"
},
{
"type": "null"
}
]
},
"aggregateExpression": {
"description": "The name of the AggregateExpression that defines how to aggregate over this model",
"anyOf": [
{
"$ref": "#/definitions/AggregateExpressionName"
},
{
"type": "null"
}
]
},
"graphql": {
"description": "Configuration for how this model should appear in the GraphQL schema.",
"anyOf": [
{
"$ref": "#/definitions/ModelGraphQlDefinitionV2"
},
{
"type": "null"
}
]
},
"description": {
"description": "The description of the model. Gets added to the description of the model in the graphql schema.",
"type": [
"string",
"null"
]
}
},
"additionalProperties": false
},
"MutationGraphqlConfig": { "MutationGraphqlConfig": {
"$id": "https://hasura.io/jsonschemas/metadata/MutationGraphqlConfig", "$id": "https://hasura.io/jsonschemas/metadata/MutationGraphqlConfig",
"title": "MutationGraphqlConfig", "title": "MutationGraphqlConfig",
@ -3861,6 +4060,96 @@
} }
] ]
}, },
{
"$id": "https://hasura.io/jsonschemas/metadata/OrderByExpression",
"title": "OrderByExpression",
"description": "Definition of an order by expression on an OpenDD type.",
"examples": [
{
"kind": "OrderByExpression",
"version": "v1",
"definition": {
"name": "Album_order_by_exp",
"operand": {
"object": {
"orderedType": "Album",
"orderableFields": [
{
"fieldName": "AlbumId",
"orderByExpression": "Int_order_by_exp"
},
{
"fieldName": "ArtistId",
"orderByExpression": "Int_order_by_exp"
},
{
"fieldName": "Address",
"orderByExpression": "Address_order_by_default_exp"
}
],
"orderableRelationships": [
{
"relationshipName": "artist",
"orderByExpression": "Artist_order_by_default_exp"
}
]
}
},
"graphql": {
"expressionTypeName": "App_Album_order_by_exp"
},
"description": "Order by expression for Albums"
}
},
{
"kind": "OrderByExpression",
"version": "v1",
"definition": {
"name": "Int_order_by_exp",
"operand": {
"scalar": {
"orderedType": "Int",
"enableOrderByDirections": {
"enableAll": true
}
}
},
"graphql": {
"expressionTypeName": "App_Int_order_by_exp"
},
"description": "Order by expression for Int"
}
}
],
"oneOf": [
{
"type": "object",
"required": [
"definition",
"kind",
"version"
],
"properties": {
"kind": {
"type": "string",
"enum": [
"OrderByExpression"
]
},
"version": {
"type": "string",
"enum": [
"v1"
]
},
"definition": {
"$ref": "#/definitions/OrderByExpressionV1"
}
},
"additionalProperties": false
}
]
},
{ {
"$id": "https://hasura.io/jsonschemas/metadata/DataConnectorScalarRepresentation", "$id": "https://hasura.io/jsonschemas/metadata/DataConnectorScalarRepresentation",
"title": "DataConnectorScalarRepresentation", "title": "DataConnectorScalarRepresentation",
@ -4039,6 +4328,32 @@
} }
}, },
"additionalProperties": false "additionalProperties": false
},
{
"type": "object",
"required": [
"definition",
"kind",
"version"
],
"properties": {
"kind": {
"type": "string",
"enum": [
"Model"
]
},
"version": {
"type": "string",
"enum": [
"v2"
]
},
"definition": {
"$ref": "#/definitions/ModelV2"
}
},
"additionalProperties": false
} }
] ]
}, },
@ -4586,6 +4901,230 @@
}, },
"additionalProperties": false "additionalProperties": false
}, },
"OrderByExpressionGraphQlConfiguration": {
"$id": "https://hasura.io/jsonschemas/metadata/OrderByExpressionGraphQlConfiguration",
"title": "OrderByExpressionGraphQlConfiguration",
"description": "GraphQL configuration settings for a type representing an order by expression on an OpenDD type.",
"type": "object",
"required": [
"expressionTypeName"
],
"properties": {
"expressionTypeName": {
"$ref": "#/definitions/GraphQlTypeName"
}
},
"additionalProperties": false
},
"OrderByExpressionName": {
"$id": "https://hasura.io/jsonschemas/metadata/OrderByExpressionName",
"title": "OrderByExpressionName",
"description": "The name of an order by expression.",
"type": "string",
"pattern": "^[_a-zA-Z][_a-zA-Z0-9]*$"
},
"OrderByExpressionObjectOperand": {
"$id": "https://hasura.io/jsonschemas/metadata/OrderByExpressionObjectOperand",
"title": "OrderByExpressionObjectOperand",
"description": "Definition of an type representing an order by expression on an OpenDD object type.",
"type": "object",
"required": [
"orderableFields",
"orderableRelationships",
"orderedType"
],
"properties": {
"orderedType": {
"description": "The type that this expression applies to.",
"allOf": [
{
"$ref": "#/definitions/CustomTypeName"
}
]
},
"orderableFields": {
"description": "Orderable fields of the `orderedType`",
"type": "array",
"items": {
"$ref": "#/definitions/OrderByExpressionOrderableField"
}
},
"orderableRelationships": {
"description": "Orderable relationships",
"type": "array",
"items": {
"$ref": "#/definitions/OrderByExpressionOrderableRelationship"
}
}
},
"additionalProperties": false
},
"OrderByExpressionOperand": {
"$id": "https://hasura.io/jsonschemas/metadata/OrderByExpressionOperand",
"title": "OrderByExpressionOperand",
"description": "Configuration for object or scalar order by expression",
"oneOf": [
{
"title": "Object",
"description": "Definition of an order by expression on an OpenDD object type",
"type": "object",
"required": [
"object"
],
"properties": {
"object": {
"$ref": "#/definitions/OrderByExpressionObjectOperand"
}
},
"additionalProperties": false
},
{
"title": "Scalar",
"description": "Definition of an order by expression on an OpenDD scalar type",
"type": "object",
"required": [
"scalar"
],
"properties": {
"scalar": {
"$ref": "#/definitions/OrderByExpressionScalarOperand"
}
},
"additionalProperties": false
}
]
},
"OrderByExpressionOrderableField": {
"$id": "https://hasura.io/jsonschemas/metadata/OrderByExpressionOrderableField",
"title": "OrderByExpressionOrderableField",
"description": "Definition of a field in a type representing an order by expression on an OpenDD type.",
"type": "object",
"required": [
"fieldName",
"orderByExpression"
],
"properties": {
"fieldName": {
"$ref": "#/definitions/FieldName"
},
"orderByExpression": {
"description": "OrderByExpression to use for this field.",
"allOf": [
{
"$ref": "#/definitions/OrderByExpressionName"
}
]
}
},
"additionalProperties": false
},
"OrderByExpressionOrderableRelationship": {
"$id": "https://hasura.io/jsonschemas/metadata/OrderByExpressionOrderableRelationship",
"title": "OrderByExpressionOrderableRelationship",
"description": "Definition of a relationship in a type representing an order by expression on an OpenDD type.",
"type": "object",
"required": [
"relationshipName"
],
"properties": {
"relationshipName": {
"description": "The name of the relationship.",
"allOf": [
{
"$ref": "#/definitions/RelationshipName"
}
]
},
"orderByExpression": {
"description": "The OrderByExpression to use for this relationship. This is optional for model relationships. If not specified we use the model's OrderByExpression configuration. For local command relationships this is required.",
"anyOf": [
{
"$ref": "#/definitions/OrderByExpressionName"
},
{
"type": "null"
}
]
}
},
"additionalProperties": false
},
"OrderByExpressionScalarOperand": {
"$id": "https://hasura.io/jsonschemas/metadata/OrderByExpressionScalarOperand",
"title": "OrderByExpressionScalarOperand",
"description": "Definition of a type representing an order by expression on an OpenDD scalar type.",
"type": "object",
"required": [
"enableOrderByDirections",
"orderedType"
],
"properties": {
"orderedType": {
"description": "The type that this expression applies to.",
"allOf": [
{
"$ref": "#/definitions/TypeName"
}
]
},
"enableOrderByDirections": {
"description": "Order by directions supported by this scalar type.",
"allOf": [
{
"$ref": "#/definitions/EnableAllOrSpecific_for_OrderByDirection"
}
]
}
},
"additionalProperties": false
},
"OrderByExpressionV1": {
"$id": "https://hasura.io/jsonschemas/metadata/OrderByExpressionV1",
"title": "OrderByExpressionV1",
"description": "Definition of a type representing an order by expression on an OpenDD type.",
"type": "object",
"required": [
"name",
"operand"
],
"properties": {
"name": {
"description": "The name used to refer to this expression. This name is unique only in the context of the `orderedType`",
"allOf": [
{
"$ref": "#/definitions/OrderByExpressionName"
}
]
},
"operand": {
"description": "The type that this expression applies to.",
"allOf": [
{
"$ref": "#/definitions/OrderByExpressionOperand"
}
]
},
"graphql": {
"description": "Configuration for how this order by expression should appear in the GraphQL schema.",
"anyOf": [
{
"$ref": "#/definitions/OrderByExpressionGraphQlConfiguration"
},
{
"type": "null"
}
]
},
"description": {
"description": "The description of the order by expression.",
"type": [
"string",
"null"
]
}
},
"additionalProperties": false
},
"OrderByInputGraphqlConfig": { "OrderByInputGraphqlConfig": {
"$id": "https://hasura.io/jsonschemas/metadata/OrderByInputGraphqlConfig", "$id": "https://hasura.io/jsonschemas/metadata/OrderByInputGraphqlConfig",
"title": "OrderByInputGraphqlConfig", "title": "OrderByInputGraphqlConfig",

View File

@ -99,7 +99,6 @@ pub enum OpenDdSubgraphObject {
BooleanExpressionType(boolean_expression::BooleanExpressionType), BooleanExpressionType(boolean_expression::BooleanExpressionType),
// OrderBy Expressions // OrderBy Expressions
#[opendd(hidden = true)]
OrderByExpression(order_by_expression::OrderByExpression), OrderByExpression(order_by_expression::OrderByExpression),
// Data Connector Scalar Representation // Data Connector Scalar Representation

View File

@ -27,7 +27,6 @@ str_newtype!(ModelName over Identifier | doc "The name of data model.");
)] )]
pub enum Model { pub enum Model {
V1(ModelV1), V1(ModelV1),
#[opendd(hidden = true)]
V2(ModelV2), V2(ModelV2),
} }

View File

@ -14,14 +14,18 @@ use crate::{
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
#[opendd( #[opendd(
as_versioned_with_definition, as_versioned_with_definition,
json_schema(title = "OrderByExpression", example = "OrderByExpression::example") json_schema(
title = "OrderByExpression",
example = "OrderByExpression::object_example",
example = "OrderByExpression::scalar_example",
)
)] )]
pub enum OrderByExpression { pub enum OrderByExpression {
V1(OrderByExpressionV1), V1(OrderByExpressionV1),
} }
impl OrderByExpression { impl OrderByExpression {
fn example() -> serde_json::Value { fn object_example() -> serde_json::Value {
serde_json::json!( serde_json::json!(
{ {
"kind": "OrderByExpression", "kind": "OrderByExpression",
@ -34,16 +38,11 @@ impl OrderByExpression {
"orderableFields": [ "orderableFields": [
{ {
"fieldName": "AlbumId", "fieldName": "AlbumId",
"enableOrderByDirections": [ "orderByExpression": "Int_order_by_exp"
"Asc",
"Desc"
]
}, },
{ {
"fieldName": "ArtistId", "fieldName": "ArtistId",
"enableOrderByDirections": [ "orderByExpression": "Int_order_by_exp"
"Asc"
]
}, },
{ {
"fieldName": "Address", "fieldName": "Address",
@ -67,6 +66,30 @@ impl OrderByExpression {
) )
} }
fn scalar_example() -> serde_json::Value {
serde_json::json!(
{
"kind": "OrderByExpression",
"version": "v1",
"definition": {
"name": "Int_order_by_exp",
"operand": {
"scalar": {
"orderedType": "Int",
"enableOrderByDirections": {
"enableAll": true
}
}
},
"graphql": {
"expressionTypeName": "App_Int_order_by_exp"
},
"description": "Order by expression for Int"
}
}
)
}
pub fn upgrade(self) -> OrderByExpressionV1 { pub fn upgrade(self) -> OrderByExpressionV1 {
match self { match self {
OrderByExpression::V1(v1) => v1, OrderByExpression::V1(v1) => v1,
@ -79,6 +102,7 @@ str_newtype!(OrderByExpressionName over Identifier | doc "The name of an order b
#[derive(Serialize, Clone, Debug, PartialEq, opendds_derive::OpenDd)] #[derive(Serialize, Clone, Debug, PartialEq, opendds_derive::OpenDd)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
#[opendd(json_schema(title = "OrderByExpressionV1",))] #[opendd(json_schema(title = "OrderByExpressionV1",))]
/// Definition of a type representing an order by expression on an OpenDD type.
pub struct OrderByExpressionV1 { pub struct OrderByExpressionV1 {
/// The name used to refer to this expression. /// The name used to refer to this expression.
/// This name is unique only in the context of the `orderedType` /// This name is unique only in the context of the `orderedType`
@ -137,6 +161,7 @@ pub struct OrderByExpressionScalarOperand {
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, opendds_derive::OpenDd)] #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, opendds_derive::OpenDd)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
#[opendd(json_schema(title = "OrderByExpressionOrderableField",))] #[opendd(json_schema(title = "OrderByExpressionOrderableField",))]
/// Definition of a field in a type representing an order by expression on an OpenDD type.
pub struct OrderByExpressionOrderableField { pub struct OrderByExpressionOrderableField {
pub field_name: FieldName, pub field_name: FieldName,
@ -147,6 +172,7 @@ pub struct OrderByExpressionOrderableField {
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, opendds_derive::OpenDd)] #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, opendds_derive::OpenDd)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
#[opendd(json_schema(title = "OrderByExpressionOrderableRelationship",))] #[opendd(json_schema(title = "OrderByExpressionOrderableRelationship",))]
/// Definition of a relationship in a type representing an order by expression on an OpenDD type.
pub struct OrderByExpressionOrderableRelationship { pub struct OrderByExpressionOrderableRelationship {
/// The name of the relationship. /// The name of the relationship.
pub relationship_name: RelationshipName, pub relationship_name: RelationshipName,
@ -161,6 +187,7 @@ pub struct OrderByExpressionOrderableRelationship {
#[derive(Serialize, Clone, Debug, PartialEq, opendds_derive::OpenDd)] #[derive(Serialize, Clone, Debug, PartialEq, opendds_derive::OpenDd)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
#[opendd(json_schema(title = "OrderByExpressionGraphQlConfiguration",))] #[opendd(json_schema(title = "OrderByExpressionGraphQlConfiguration",))]
/// GraphQL configuration settings for a type representing an order by expression on an OpenDD type.
pub struct OrderByExpressionGraphQlConfiguration { pub struct OrderByExpressionGraphQlConfiguration {
pub expression_type_name: GraphQlTypeName, pub expression_type_name: GraphQlTypeName,
} }