Support joins on nested fields for MongoDB

PR-URL: https://github.com/hasura/graphql-engine-mono/pull/10345
GitOrigin-RevId: 1a4886b7ac5110ddf9233596068810963bde3371
This commit is contained in:
David Overton 2023-10-30 13:25:57 +11:00 committed by hasura-bot
parent 04e21a34af
commit 82fa13db6e
70 changed files with 908 additions and 314 deletions

View File

@ -1,6 +1,6 @@
{
"name": "@hasura/dc-api-types",
"version": "0.42.0",
"version": "0.43.0",
"description": "Hasura GraphQL Engine Data Connector Agent API types",
"author": "Hasura (https://github.com/hasura/graphql-engine)",
"license": "Apache-2.0",

View File

@ -1334,11 +1334,42 @@
"Constraint": {
"properties": {
"column_mapping": {
"additionalProperties": {
"type": "string"
},
"description": "The columns on which you want want to define the foreign key.",
"type": "object"
"additionalProperties": true,
"anyOf": [
{
"additionalProperties": {
"oneOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "string"
}
]
},
"type": "object"
},
{
"additionalProperties": {
"oneOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "string"
}
]
},
"type": "object"
}
],
"description": "The columns on which you want want to define the foreign key."
},
"foreign_table": {
"$ref": "#/components/schemas/TableName"
@ -1845,11 +1876,42 @@
"Relationship": {
"properties": {
"column_mapping": {
"additionalProperties": {
"type": "string"
},
"description": "A mapping between columns on the source table to columns on the target table",
"type": "object"
"additionalProperties": true,
"anyOf": [
{
"additionalProperties": {
"oneOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "string"
}
]
},
"type": "object"
},
{
"additionalProperties": {
"oneOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "string"
}
]
},
"type": "object"
}
],
"description": "A mapping between columns on the source table to columns on the target table"
},
"relationship_type": {
"$ref": "#/components/schemas/RelationshipType"
@ -2068,19 +2130,18 @@
"$ref": "#/components/schemas/ScalarType"
},
"name": {
"additionalProperties": true,
"anyOf": [
{
"type": "string"
},
"description": "The name of the column",
"oneOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "string"
}
],
"description": "The name of the column"
]
},
"path": {
"default": [],
@ -2620,16 +2681,15 @@
"OrderByColumn": {
"properties": {
"column": {
"additionalProperties": true,
"anyOf": [
{
"type": "string"
},
"oneOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "string"
}
]
},

View File

@ -10,7 +10,7 @@ export type ComparisonColumn = {
/**
* The name of the column
*/
name: (string | Array<string>);
name: (Array<string> | string);
/**
* The path to the table that contains the specified column. Missing or empty array means the current table. ["$"] means the query table. No other values are supported at this time.
*/

View File

@ -8,7 +8,7 @@ export type Constraint = {
/**
* The columns on which you want want to define the foreign key.
*/
column_mapping: Record<string, string>;
column_mapping: Record<string, (Array<string> | string)>;
foreign_table: TableName;
};

View File

@ -5,7 +5,7 @@
import type { RedactionExpressionName } from './RedactionExpressionName';
export type OrderByColumn = {
column: (string | Array<string>);
column: (Array<string> | string);
redaction_expression?: RedactionExpressionName;
type: 'column';
};

View File

@ -9,7 +9,7 @@ export type Relationship = {
/**
* A mapping between columns on the source table to columns on the target table
*/
column_mapping: Record<string, string>;
column_mapping: Record<string, (Array<string> | string)>;
relationship_type: RelationshipType;
target: Target;
};

View File

@ -24,7 +24,7 @@
},
"dc-api-types": {
"name": "@hasura/dc-api-types",
"version": "0.42.0",
"version": "0.43.0",
"license": "Apache-2.0",
"devDependencies": {
"@tsconfig/node16": "^1.0.3",
@ -2227,7 +2227,7 @@
"license": "Apache-2.0",
"dependencies": {
"@fastify/cors": "^8.1.0",
"@hasura/dc-api-types": "0.42.0",
"@hasura/dc-api-types": "0.43.0",
"fastify": "^4.13.0",
"mathjs": "^11.0.0",
"pino-pretty": "^8.0.0",
@ -2547,7 +2547,7 @@
"license": "Apache-2.0",
"dependencies": {
"@fastify/cors": "^8.1.0",
"@hasura/dc-api-types": "0.42.0",
"@hasura/dc-api-types": "0.43.0",
"fastify": "^4.13.0",
"fastify-metrics": "^9.2.1",
"nanoid": "^3.3.4",
@ -2868,7 +2868,7 @@
"version": "file:reference",
"requires": {
"@fastify/cors": "^8.1.0",
"@hasura/dc-api-types": "0.42.0",
"@hasura/dc-api-types": "0.43.0",
"@tsconfig/node16": "^1.0.3",
"@types/node": "^16.11.49",
"@types/xml2js": "^0.4.11",
@ -3080,7 +3080,7 @@
"version": "file:sqlite",
"requires": {
"@fastify/cors": "^8.1.0",
"@hasura/dc-api-types": "0.42.0",
"@hasura/dc-api-types": "0.43.0",
"@tsconfig/node16": "^1.0.3",
"@types/node": "^16.11.49",
"@types/sqlite3": "^3.1.8",

View File

@ -10,7 +10,7 @@
"license": "Apache-2.0",
"dependencies": {
"@fastify/cors": "^8.1.0",
"@hasura/dc-api-types": "0.42.0",
"@hasura/dc-api-types": "0.43.0",
"fastify": "^4.13.0",
"mathjs": "^11.0.0",
"pino-pretty": "^8.0.0",
@ -52,7 +52,7 @@
"integrity": "sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ=="
},
"node_modules/@hasura/dc-api-types": {
"version": "0.42.0",
"version": "0.43.0",
"license": "Apache-2.0",
"devDependencies": {
"@tsconfig/node16": "^1.0.3",

View File

@ -22,7 +22,7 @@
},
"dependencies": {
"@fastify/cors": "^8.1.0",
"@hasura/dc-api-types": "0.42.0",
"@hasura/dc-api-types": "0.43.0",
"fastify": "^4.13.0",
"mathjs": "^11.0.0",
"pino-pretty": "^8.0.0",

View File

@ -175,7 +175,7 @@ export const getSchema = (store: Record<string, StaticData>, config: Config, req
? mapObjectValues(table.foreign_keys, constraint => ({
...constraint,
foreign_table: prefixSchemaToTableName(constraint.foreign_table.map(applyTableNameCasing)),
column_mapping: mapObject(constraint.column_mapping, ([outer, inner]) => [applyColumnNameCasing(outer), applyColumnNameCasing(inner)])
column_mapping: mapObject(constraint.column_mapping as Record<string, string>, ([outer, inner]) => [applyColumnNameCasing(outer), applyColumnNameCasing(inner)])
}))
: table.foreign_keys,
columns: table.columns?.map(column => ({

View File

@ -484,7 +484,7 @@ const makeApplyRedaction = (
const createFilterExpressionForRelationshipJoin = (row: Record<string, RawScalarValue>, relationship: Relationship): Expression | null => {
const columnMappings = Object.entries(relationship.column_mapping);
const filterConditions: Expression[] = columnMappings
.map(([outerColumnName, innerColumnName]): [RawScalarValue, string] => [row[outerColumnName], innerColumnName])
.map(([outerColumnName, innerColumnName]): [RawScalarValue, string] => [row[outerColumnName], innerColumnName as string])
.filter((x): x is [RawScalarValue, string] => {
const [outerValue, _] = x;
return outerValue !== null;

View File

@ -10,7 +10,7 @@
"license": "Apache-2.0",
"dependencies": {
"@fastify/cors": "^8.1.0",
"@hasura/dc-api-types": "0.42.0",
"@hasura/dc-api-types": "0.43.0",
"fastify": "^4.13.0",
"fastify-metrics": "^9.2.1",
"nanoid": "^3.3.4",
@ -57,7 +57,7 @@
"integrity": "sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ=="
},
"node_modules/@hasura/dc-api-types": {
"version": "0.42.0",
"version": "0.43.0",
"license": "Apache-2.0",
"devDependencies": {
"@tsconfig/node16": "^1.0.3",

View File

@ -22,7 +22,7 @@
},
"dependencies": {
"@fastify/cors": "^8.1.0",
"@hasura/dc-api-types": "0.42.0",
"@hasura/dc-api-types": "0.43.0",
"fastify-metrics": "^9.2.1",
"fastify": "^4.13.0",
"nanoid": "^3.3.4",

View File

@ -234,7 +234,7 @@ function generateRelationshipJoinComparisonFragments(relationship: Relationship,
return Object
.entries(relationship.column_mapping)
.map(([sourceColumnName, targetColumnName]) =>
`${sourceTablePrefix}${escapeIdentifier(sourceColumnName)} = ${targetTableAlias}.${escapeIdentifier(targetColumnName)}`);
`${sourceTablePrefix}${escapeIdentifier(sourceColumnName)} = ${targetTableAlias}.${escapeIdentifier(targetColumnName as string)}`);
}
function generateComparisonColumnFragment(comparisonColumn: ComparisonColumn, queryTableAlias: string, currentTableAlias: string): string {
@ -419,7 +419,7 @@ function target_query( // TODO: Rename as `target_query`
function relationship(ts: Relationships[], r: Relationship, field: RelationshipField, sourceTableAlias: string): string {
const relationshipJoinInfo = {
sourceTableAlias,
columnMapping: r.column_mapping,
columnMapping: r.column_mapping as Record<string, string>,
};
// We force a limit of 1 for object relationships in case the user has configured a manual
@ -638,7 +638,7 @@ function generateOrderByAggregateTargetJoinInfo(
default: unreachable(element.target["type"]);
}
});
const joinColumns = Object.values(relationship.column_mapping).map(escapeIdentifier);
const joinColumns = Object.values(relationship.column_mapping as Record<string, string>).map(escapeIdentifier);
const selectColumns = [...joinColumns, aggregateColumnsFragments];
const whereClause = whereExpression ? `WHERE ${where_clause(allTableRelationships, whereExpression, relationship.target, subqueryTableAlias)}` : "";
const aggregateSubquery = `SELECT ${selectColumns.join(", ")} FROM ${escapeTargetName(relationship.target)} AS ${subqueryTableAlias} ${whereClause} GROUP BY ${joinColumns.join(", ")}`

View File

@ -965,10 +965,21 @@
"BigqueryRelManualNativeQueryConfig": {
"properties": {
"column_mapping": {
"additionalProperties": {
"type": "string"
},
"type": "object"
"additionalProperties": true,
"anyOf": [
{
"additionalProperties": {
"type": "string"
},
"type": "object"
},
{
"additionalProperties": {
"type": "string"
},
"type": "object"
}
]
},
"insertion_order": {
"enum": [
@ -991,10 +1002,21 @@
"BigqueryRelManualTableConfig": {
"properties": {
"column_mapping": {
"additionalProperties": {
"type": "string"
},
"type": "object"
"additionalProperties": true,
"anyOf": [
{
"additionalProperties": {
"type": "string"
},
"type": "object"
},
{
"additionalProperties": {
"type": "string"
},
"type": "object"
}
]
},
"insertion_order": {
"enum": [
@ -1946,10 +1968,21 @@
"CitusRelManualNativeQueryConfig": {
"properties": {
"column_mapping": {
"additionalProperties": {
"type": "string"
},
"type": "object"
"additionalProperties": true,
"anyOf": [
{
"additionalProperties": {
"type": "string"
},
"type": "object"
},
{
"additionalProperties": {
"type": "string"
},
"type": "object"
}
]
},
"insertion_order": {
"enum": [
@ -1972,10 +2005,21 @@
"CitusRelManualTableConfig": {
"properties": {
"column_mapping": {
"additionalProperties": {
"type": "string"
},
"type": "object"
"additionalProperties": true,
"anyOf": [
{
"additionalProperties": {
"type": "string"
},
"type": "object"
},
{
"additionalProperties": {
"type": "string"
},
"type": "object"
}
]
},
"insertion_order": {
"enum": [
@ -2954,10 +2998,21 @@
"CockroachRelManualNativeQueryConfig": {
"properties": {
"column_mapping": {
"additionalProperties": {
"type": "string"
},
"type": "object"
"additionalProperties": true,
"anyOf": [
{
"additionalProperties": {
"type": "string"
},
"type": "object"
},
{
"additionalProperties": {
"type": "string"
},
"type": "object"
}
]
},
"insertion_order": {
"enum": [
@ -2980,10 +3035,21 @@
"CockroachRelManualTableConfig": {
"properties": {
"column_mapping": {
"additionalProperties": {
"type": "string"
},
"type": "object"
"additionalProperties": true,
"anyOf": [
{
"additionalProperties": {
"type": "string"
},
"type": "object"
},
{
"additionalProperties": {
"type": "string"
},
"type": "object"
}
]
},
"insertion_order": {
"enum": [
@ -3733,7 +3799,17 @@
"properties": {
"columns": {
"items": {
"type": "string"
"oneOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "string"
}
]
},
"type": "array"
},
@ -3753,7 +3829,17 @@
"DataconnectorArrRelUsingFKeyOnSingleColumn": {
"properties": {
"column": {
"type": "string"
"oneOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "string"
}
]
},
"table": {
"items": {
@ -4055,7 +4141,17 @@
"properties": {
"columns": {
"items": {
"type": "string"
"oneOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "string"
}
]
},
"type": "array"
},
@ -4075,7 +4171,17 @@
"DataconnectorObjRelRemoteTableSingleColumn": {
"properties": {
"column": {
"type": "string"
"oneOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "string"
}
]
},
"table": {
"items": {
@ -4112,10 +4218,41 @@
"DataconnectorRelManualNativeQueryConfig": {
"properties": {
"column_mapping": {
"additionalProperties": {
"type": "string"
},
"type": "object"
"additionalProperties": true,
"anyOf": [
{
"additionalProperties": {
"oneOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "string"
}
]
},
"type": "object"
},
{
"additionalProperties": {
"oneOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "string"
}
]
},
"type": "object"
}
]
},
"insertion_order": {
"enum": [
@ -4138,10 +4275,41 @@
"DataconnectorRelManualTableConfig": {
"properties": {
"column_mapping": {
"additionalProperties": {
"type": "string"
},
"type": "object"
"additionalProperties": true,
"anyOf": [
{
"additionalProperties": {
"oneOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "string"
}
]
},
"type": "object"
},
{
"additionalProperties": {
"oneOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "string"
}
]
},
"type": "object"
}
]
},
"insertion_order": {
"enum": [
@ -5825,10 +5993,21 @@
"MssqlRelManualNativeQueryConfig": {
"properties": {
"column_mapping": {
"additionalProperties": {
"type": "string"
},
"type": "object"
"additionalProperties": true,
"anyOf": [
{
"additionalProperties": {
"type": "string"
},
"type": "object"
},
{
"additionalProperties": {
"type": "string"
},
"type": "object"
}
]
},
"insertion_order": {
"enum": [
@ -5851,10 +6030,21 @@
"MssqlRelManualTableConfig": {
"properties": {
"column_mapping": {
"additionalProperties": {
"type": "string"
},
"type": "object"
"additionalProperties": true,
"anyOf": [
{
"additionalProperties": {
"type": "string"
},
"type": "object"
},
{
"additionalProperties": {
"type": "string"
},
"type": "object"
}
]
},
"insertion_order": {
"enum": [
@ -7208,10 +7398,21 @@
"PostgresRelManualNativeQueryConfig": {
"properties": {
"column_mapping": {
"additionalProperties": {
"type": "string"
},
"type": "object"
"additionalProperties": true,
"anyOf": [
{
"additionalProperties": {
"type": "string"
},
"type": "object"
},
{
"additionalProperties": {
"type": "string"
},
"type": "object"
}
]
},
"insertion_order": {
"enum": [
@ -7234,10 +7435,21 @@
"PostgresRelManualTableConfig": {
"properties": {
"column_mapping": {
"additionalProperties": {
"type": "string"
},
"type": "object"
"additionalProperties": true,
"anyOf": [
{
"additionalProperties": {
"type": "string"
},
"type": "object"
},
{
"additionalProperties": {
"type": "string"
},
"type": "object"
}
]
},
"insertion_order": {
"enum": [
@ -7933,12 +8145,28 @@
"properties": {
"foreign_key_constraint_on": {
"oneOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "string"
},
{
"items": {
"type": "string"
"oneOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "string"
}
]
},
"type": "array"
},

View File

@ -177,7 +177,7 @@ tests = describe "Aggregate Query Tests" $ do
API.Relationship
{ _rTarget = mkTableTarget "Album",
_rRelationshipType = API.ArrayRelationship,
_rColumnMapping = HashMap.fromList [(API.ColumnName "ArtistId", API.ColumnName "ArtistId")]
_rColumnMapping = API.ColumnPathMapping $ HashMap.fromList [(API.mkColumnSelector $ API.ColumnName "ArtistId", API.mkColumnSelector $ API.ColumnName "ArtistId")]
}
)
]
@ -300,7 +300,7 @@ tests = describe "Aggregate Query Tests" $ do
API.Relationship
{ _rTarget = mkTableTarget "InvoiceLine",
_rRelationshipType = API.ArrayRelationship,
_rColumnMapping = HashMap.fromList [(API.ColumnName "InvoiceId", API.ColumnName "InvoiceId")]
_rColumnMapping = API.ColumnPathMapping $ HashMap.fromList [(API.mkColumnSelector $ API.ColumnName "InvoiceId", API.mkColumnSelector $ API.ColumnName "InvoiceId")]
}
)
]

View File

@ -18,7 +18,7 @@ import Harness.Test.BackendType qualified as BackendType
import Harness.Test.Fixture qualified as Fixture
import Harness.TestEnvironment (GlobalTestEnvironment, TestEnvironment)
import Harness.Yaml (shouldBeYaml)
import Hasura.Backends.DataConnector.API (ColumnName (..), ScalarType (..), ScalarValue (..))
import Hasura.Backends.DataConnector.API (ColumnName (..), ScalarType (..), ScalarValue (..), mkColumnSelector)
import Hasura.Backends.DataConnector.API qualified as API
import Hasura.Backends.DataConnector.API.V0.Expression
import Hasura.Prelude

View File

@ -189,7 +189,7 @@ tests = do
API.Relationship
{ API._rTarget = mkTableTarget "Artist",
API._rRelationshipType = API.ObjectRelationship,
API._rColumnMapping = HashMap.fromList [(API.ColumnName "ArtistId", API.ColumnName "ArtistId")]
API._rColumnMapping = API.ColumnPathMapping $ HashMap.fromList [(API.mkColumnSelector $ API.ColumnName "ArtistId", API.mkColumnSelector $ API.ColumnName "ArtistId")]
}
)
]
@ -298,7 +298,7 @@ tests = do
API.Relationship
{ API._rTarget = mkTableTarget "Artist",
API._rRelationshipType = API.ObjectRelationship,
API._rColumnMapping = HashMap.fromList [(API.ColumnName "ArtistId", API.ColumnName "ArtistId")]
API._rColumnMapping = API.ColumnPathMapping $ HashMap.fromList [(API.mkColumnSelector $ API.ColumnName "ArtistId", API.mkColumnSelector $ API.ColumnName "ArtistId")]
}
)
]

View File

@ -181,7 +181,7 @@ tests = do
API.Relationship
{ API._rTarget = mkTableTarget "Artist",
API._rRelationshipType = API.ObjectRelationship,
API._rColumnMapping = HashMap.fromList [(API.ColumnName "ArtistId", API.ColumnName "ArtistId")]
API._rColumnMapping = API.ColumnPathMapping $ HashMap.fromList [(API.mkColumnSelector $ API.ColumnName "ArtistId", API.mkColumnSelector $ API.ColumnName "ArtistId")]
}
)
]

View File

@ -200,7 +200,7 @@ tests = describe "Order By Tests" $ do
API.Relationship
{ _rTarget = mkTableTarget "Album",
_rRelationshipType = API.ArrayRelationship,
_rColumnMapping = HashMap.fromList [(API.ColumnName "ArtistId", API.ColumnName "ArtistId")]
_rColumnMapping = API.ColumnPathMapping $ HashMap.fromList [(API.mkColumnSelector $ API.ColumnName "ArtistId", API.mkColumnSelector $ API.ColumnName "ArtistId")]
}
)
]

View File

@ -228,7 +228,7 @@ tests = describe "Object Relationships Tests" $ do
API.Relationship
{ _rTarget = mkTableTarget "Genre",
_rRelationshipType = API.ObjectRelationship,
_rColumnMapping = HashMap.fromList [(API.ColumnName "GenreId", API.ColumnName "GenreId")]
_rColumnMapping = API.ColumnPathMapping $ HashMap.fromList [(API.mkColumnSelector $ API.ColumnName "GenreId", API.mkColumnSelector $ API.ColumnName "GenreId")]
}
),
( API.RelationshipName "MediaType",
@ -236,8 +236,9 @@ tests = describe "Object Relationships Tests" $ do
{ _rTarget = mkTableTarget "MediaType",
_rRelationshipType = API.ObjectRelationship,
_rColumnMapping =
HashMap.fromList
[(API.ColumnName "MediaTypeId", API.ColumnName "MediaTypeId")]
API.ColumnPathMapping
$ HashMap.fromList
[(API.mkColumnSelector $ API.ColumnName "MediaTypeId", API.mkColumnSelector $ API.ColumnName "MediaTypeId")]
}
)
]
@ -354,7 +355,9 @@ tests = describe "Object Relationships Tests" $ do
API.Relationship
{ _rTarget = mkTableTarget "Album",
_rRelationshipType = API.ObjectRelationship,
_rColumnMapping = HashMap.fromList [(API.ColumnName "AlbumId", API.ColumnName "AlbumId")]
_rColumnMapping =
API.ColumnPathMapping
$ HashMap.fromList [(API.mkColumnSelector $ API.ColumnName "AlbumId", API.mkColumnSelector $ API.ColumnName "AlbumId")]
}
)
]
@ -368,7 +371,9 @@ tests = describe "Object Relationships Tests" $ do
API.Relationship
{ _rTarget = mkTableTarget "Artist",
_rRelationshipType = API.ObjectRelationship,
_rColumnMapping = HashMap.fromList [(API.ColumnName "ArtistId", API.ColumnName "ArtistId")]
_rColumnMapping =
API.ColumnPathMapping
$ HashMap.fromList [(API.mkColumnSelector $ API.ColumnName "ArtistId", API.mkColumnSelector $ API.ColumnName "ArtistId")]
}
)
]
@ -449,7 +454,7 @@ tests = describe "Object Relationships Tests" $ do
API.Relationship
{ _rTarget = mkTableTarget "Employee",
_rRelationshipType = API.ObjectRelationship,
_rColumnMapping = HashMap.fromList [(API.ColumnName "SupportRepId", API.ColumnName "EmployeeId")]
_rColumnMapping = API.ColumnPathMapping $ HashMap.fromList [(API.mkColumnSelector $ API.ColumnName "SupportRepId", API.mkColumnSelector $ API.ColumnName "EmployeeId")]
}
)
]
@ -463,7 +468,7 @@ tests = describe "Object Relationships Tests" $ do
API.Relationship
{ _rTarget = mkTableTarget "Customer",
_rRelationshipType = API.ArrayRelationship,
_rColumnMapping = HashMap.fromList [(API.ColumnName "EmployeeId", API.ColumnName "SupportRepId")]
_rColumnMapping = API.ColumnPathMapping $ HashMap.fromList [(API.mkColumnSelector $ API.ColumnName "EmployeeId", API.mkColumnSelector $ API.ColumnName "SupportRepId")]
}
)
]

View File

@ -203,7 +203,7 @@ tests = do
API.Relationship
{ API._rTarget = mkTableTarget "Genre",
API._rRelationshipType = API.ObjectRelationship,
API._rColumnMapping = HashMap.fromList [(API.ColumnName "GenreId", API.ColumnName "GenreId")]
API._rColumnMapping = API.ColumnPathMapping $ HashMap.fromList [(API.mkColumnSelector $ API.ColumnName "GenreId", API.mkColumnSelector $ API.ColumnName "GenreId")]
}
)
]
@ -394,7 +394,7 @@ tests = do
API.Relationship
{ API._rTarget = mkTableTarget "Genre",
API._rRelationshipType = API.ObjectRelationship,
API._rColumnMapping = HashMap.fromList [(API.ColumnName "GenreId", API.ColumnName "GenreId")]
API._rColumnMapping = API.ColumnPathMapping $ HashMap.fromList [(API.mkColumnSelector $ API.ColumnName "GenreId", API.mkColumnSelector $ API.ColumnName "GenreId")]
}
)
]

View File

@ -3,6 +3,8 @@
module Hasura.Backends.DataConnector.API.V0.Column
( ColumnName (..),
ColumnSelector (..),
mkColumnSelector,
ColumnType (..),
ColumnInfo (..),
ciName,
@ -13,19 +15,24 @@ module Hasura.Backends.DataConnector.API.V0.Column
ciUpdatable,
ciValueGenerated,
ColumnValueGenerationStrategy (..),
ColumnPathMapping (..),
)
where
--------------------------------------------------------------------------------
import Autodocodec
import Autodocodec.Extended
import Autodocodec.OpenAPI ()
import Control.DeepSeq (NFData)
import Control.Lens.TH (makeLenses)
import Data.Aeson (FromJSON, FromJSONKey, ToJSON, ToJSONKey)
import Data.Bitraversable (bitraverse)
import Data.Data (Data)
import Data.Either.Extra (maybeToEither)
import Data.HashMap.Strict (HashMap)
import Data.HashMap.Strict qualified as HashMap
import Data.Hashable (Hashable)
import Data.List.NonEmpty (NonEmpty (..))
import Data.OpenApi (ToSchema)
import Data.Text (Text)
import GHC.Generics (Generic)
@ -46,6 +53,31 @@ instance HasCodec ColumnName where
--------------------------------------------------------------------------------
data ColumnSelector
= ColumnSelectorPath (NonEmpty ColumnName)
| ColumnSelectorColumn (ColumnName)
deriving stock (Eq, Ord, Show, Generic)
deriving (FromJSON, ToJSON, ToSchema) via Autodocodec ColumnSelector
deriving anyclass (Hashable, NFData)
instance HasCodec ColumnSelector where
codec = disjointMatchChoiceCodec pathCodec columnCodec chooser
where
pathCodec = dimapCodec ColumnSelectorPath id (codec @(NonEmpty ColumnName))
columnCodec = dimapCodec ColumnSelectorColumn id (codec @ColumnName)
chooser = \case
ColumnSelectorPath p -> Left p
ColumnSelectorColumn c -> Right c
instance FromJSONKey ColumnSelector
instance ToJSONKey ColumnSelector
mkColumnSelector :: ColumnName -> ColumnSelector
mkColumnSelector = ColumnSelectorColumn
--------------------------------------------------------------------------------
data ColumnType
= ColumnTypeScalar API.V0.Scalar.ScalarType
| ColumnTypeObject G.Name
@ -135,3 +167,33 @@ instance HasCodec ColumnValueGenerationStrategy where
]
$(makeLenses ''ColumnInfo)
newtype ColumnPathMapping = ColumnPathMapping {unColumnPathMapping :: HashMap ColumnSelector ColumnSelector}
deriving stock (Eq, Ord, Show, Generic)
deriving newtype (NFData, Hashable)
deriving (FromJSON, ToJSON, ToSchema) via Autodocodec ColumnPathMapping
-- If all keys in the ColumnPathMapping are ColumnSelectors with a single column then we
-- want to represent the mapping as a JSON object with the source columns as properties
-- (using `codec @(HashMap ColumnName ColumnSelector)).
-- This is required for backwards compatibility of the DC API.
-- If some of the keys are not singletons then we can't use a JSON object so we use
-- an array of pairs instead, as provided by `codec @(HashMap ColumnSelector ColumnSelector)`.
instance HasCodec ColumnPathMapping where
codec =
matchChoiceCodec
(dimapCodec ColumnPathMapping unColumnPathMapping $ codec @(HashMap ColumnSelector ColumnSelector))
(dimapCodec columnMappingToColumnPathMapping id $ codec @(HashMap ColumnName ColumnSelector))
\m -> maybeToEither m (tryColumnPathMappingToColumnMapping m)
where
columnMappingToColumnPathMapping :: HashMap ColumnName ColumnSelector -> ColumnPathMapping
columnMappingToColumnPathMapping = ColumnPathMapping . HashMap.mapKeys mkColumnSelector
tryColumnPathMappingToColumnMapping :: ColumnPathMapping -> Maybe (HashMap ColumnName ColumnSelector)
tryColumnPathMappingToColumnMapping =
fmap HashMap.fromList . traverse (bitraverse tryColumnSelectorToColumnName pure) . HashMap.toList . unColumnPathMapping
tryColumnSelectorToColumnName :: ColumnSelector -> Maybe ColumnName
tryColumnSelectorToColumnName = \case
ColumnSelectorColumn columnName -> Just columnName
_ -> Nothing

View File

@ -14,8 +14,6 @@ module Hasura.Backends.DataConnector.API.V0.Expression
ccColumnType,
ccRedactionExpression,
ColumnPath (..),
ColumnSelector (..),
mkColumnSelector,
ComparisonValue (..),
TargetRedactionExpressions (..),
RedactionExpressionName (..),
@ -32,8 +30,6 @@ import Data.Data (Data)
import Data.HashMap.Strict (HashMap)
import Data.HashMap.Strict qualified as HashMap
import Data.Hashable (Hashable)
import Data.List.NonEmpty (NonEmpty (..))
import Data.List.NonEmpty qualified as NonEmpty
import Data.OpenApi (ToSchema)
import Data.Set (Set)
import Data.Text (Text)
@ -258,7 +254,7 @@ data ComparisonColumn = ComparisonColumn
{ -- | The path to the table that contains the specified column.
_ccPath :: ColumnPath,
-- | The name of the column
_ccName :: ColumnSelector,
_ccName :: API.V0.ColumnSelector,
-- | The scalar type of the column
_ccColumnType :: API.V0.ScalarType,
-- | If present, the name of the redaction expression to evaluate.
@ -309,20 +305,6 @@ instance HasCodec ColumnPath where
CurrentTable -> []
QueryTable -> ["$"]
newtype ColumnSelector = ColumnSelector {unColumnSelector :: NonEmpty API.V0.ColumnName}
deriving stock (Eq, Ord, Show, Generic)
deriving (FromJSON, ToJSON, ToSchema) via Autodocodec ColumnSelector
deriving anyclass (Hashable, NFData)
instance HasCodec ColumnSelector where
codec = bimapCodec dec enc oneOrManyCodec
where
dec = maybe (Left "Unexpected empty list in ColumnSelector") (Right . ColumnSelector) . NonEmpty.nonEmpty
enc = NonEmpty.toList . unColumnSelector
mkColumnSelector :: API.V0.ColumnName -> ColumnSelector
mkColumnSelector = ColumnSelector . NonEmpty.singleton
-- | A serializable representation of comparison values used in comparisons inside 'Expression's.
data ComparisonValue
= -- | Allows a comparison to a column on the current table or another table

View File

@ -30,6 +30,7 @@ import Data.List.NonEmpty (NonEmpty)
import Data.OpenApi (ToSchema)
import GHC.Generics (Generic)
import Hasura.Backends.DataConnector.API.V0.Aggregate qualified as API.V0
import Hasura.Backends.DataConnector.API.V0.Column qualified as API.V0
import Hasura.Backends.DataConnector.API.V0.Expression qualified as API.V0
import Hasura.Backends.DataConnector.API.V0.Relationships qualified as API.V0
import Prelude

View File

@ -33,6 +33,7 @@ module Hasura.Backends.DataConnector.API.V0.Query
qrAggregates,
qrInterpolatedQueries,
FieldValue,
unFieldValue,
mkColumnFieldValue,
mkRelationshipFieldValue,
mkNestedObjFieldValue,
@ -299,7 +300,7 @@ instance HasStatus QueryResponse where
-- field values (mainly for testing purposes), we must compare them using 'QueryResponse',
-- since raw JSON comparisons will show up immaterial differences between null properties
-- and missing properties (which we consider to be the same thing here).
newtype FieldValue = FieldValue J.Value
newtype FieldValue = FieldValue {unFieldValue :: J.Value}
deriving (ToJSON, FromJSON, ToSchema) via Autodocodec FieldValue
instance Eq FieldValue where

View File

@ -30,6 +30,7 @@ import Control.DeepSeq (NFData)
import Control.Lens (makeLenses, makePrisms)
import Data.Aeson (FromJSON, FromJSONKey, ToJSON, ToJSONKey)
import Data.Data (Data)
import Data.HashMap.Strict (HashMap)
import Data.HashMap.Strict qualified as HashMap
import Data.Hashable (Hashable)
import Data.OpenApi (ToSchema)
@ -43,13 +44,13 @@ import Hasura.Backends.DataConnector.API.V0.Target qualified as API.V0
import Prelude
data Relationships = RTable TableRelationships | RFunction FunctionRelationships | RInterpolated InterpolatedRelationships
deriving stock (Eq, Ord, Show, Generic, Data)
deriving stock (Eq, Ord, Show, Generic)
deriving (FromJSON, ToJSON, ToSchema) via Autodocodec Relationships
pattern RTableRelationships :: API.V0.TableName -> HashMap.HashMap RelationshipName Relationship -> Relationships
pattern RTableRelationships :: API.V0.TableName -> HashMap RelationshipName Relationship -> Relationships
pattern RTableRelationships source rels = RTable (TableRelationships source rels)
pattern RFunctionRelationships :: API.V0.FunctionName -> HashMap.HashMap RelationshipName Relationship -> Relationships
pattern RFunctionRelationships :: API.V0.FunctionName -> HashMap RelationshipName Relationship -> Relationships
pattern RFunctionRelationships source rels = RFunction (FunctionRelationships source rels)
instance HasCodec Relationships where
@ -71,9 +72,9 @@ instance HasCodec Relationships where
data InterpolatedRelationships = InterpolatedRelationships
{ _irSource :: API.V0.InterpolatedQueryId,
_irRelationships :: HashMap.HashMap RelationshipName Relationship
_irRelationships :: HashMap RelationshipName Relationship
}
deriving stock (Eq, Ord, Show, Generic, Data)
deriving stock (Eq, Ord, Show, Generic)
instance HasObjectCodec InterpolatedRelationships where
objectCodec =
@ -84,9 +85,9 @@ instance HasObjectCodec InterpolatedRelationships where
-- NOTE: Prefix is `trel` due to TableRequest conflicting with `tr` prefix.
data TableRelationships = TableRelationships
{ _trelSourceTable :: API.V0.TableName,
_trelRelationships :: HashMap.HashMap RelationshipName Relationship
_trelRelationships :: HashMap RelationshipName Relationship
}
deriving stock (Eq, Ord, Show, Generic, Data)
deriving stock (Eq, Ord, Show, Generic)
instance HasObjectCodec TableRelationships where
objectCodec =
@ -96,9 +97,9 @@ instance HasObjectCodec TableRelationships where
data FunctionRelationships = FunctionRelationships
{ _frelSourceFunction :: API.V0.FunctionName,
_frelRelationships :: HashMap.HashMap RelationshipName Relationship
_frelRelationships :: HashMap RelationshipName Relationship
}
deriving stock (Eq, Ord, Show, Generic, Data)
deriving stock (Eq, Ord, Show, Generic)
instance HasObjectCodec FunctionRelationships where
objectCodec =
@ -110,9 +111,9 @@ instance HasObjectCodec FunctionRelationships where
data Relationship = Relationship
{ _rTarget :: API.V0.Target,
_rRelationshipType :: RelationshipType,
_rColumnMapping :: HashMap.HashMap SourceColumnName TargetColumnName
_rColumnMapping :: API.V0.ColumnPathMapping
}
deriving stock (Eq, Ord, Show, Generic, Data)
deriving stock (Eq, Ord, Show, Generic)
deriving (FromJSON, ToJSON, ToSchema) via Autodocodec Relationship
instance HasCodec Relationship where
@ -140,9 +141,9 @@ instance HasCodec RelationshipType where
named "RelationshipType" $
stringConstCodec [(ObjectRelationship, "object"), (ArrayRelationship, "array")]
type SourceColumnName = API.V0.ColumnName
type SourceColumnName = API.V0.ColumnSelector
type TargetColumnName = API.V0.ColumnName
type TargetColumnName = API.V0.ColumnSelector
$(makeLenses 'TableRelationships)
$(makeLenses 'Relationship)

View File

@ -122,7 +122,7 @@ instance HasCodec TableType where
--------------------------------------------------------------------------------
newtype ForeignKeys = ForeignKeys {_unForeignKeys :: HashMap ConstraintName Constraint}
deriving stock (Eq, Ord, Show, Generic, Data)
deriving stock (Eq, Ord, Show, Generic)
deriving anyclass (NFData, Hashable)
deriving (FromJSON, ToJSON) via Autodocodec ForeignKeys
@ -138,9 +138,9 @@ newtype ConstraintName = ConstraintName {unConstraintName :: Text}
data Constraint = Constraint
{ _cForeignTable :: TableName,
_cColumnMapping :: HashMap API.V0.ColumnName API.V0.ColumnName
_cColumnMapping :: API.V0.ColumnPathMapping
}
deriving stock (Eq, Ord, Show, Generic, Data)
deriving stock (Eq, Ord, Show, Generic)
deriving anyclass (NFData, Hashable)
deriving (FromJSON, ToJSON) via Autodocodec Constraint

View File

@ -155,7 +155,7 @@ albumsRelationshipName = API.RelationshipName "Albums"
artistsTableRelationships :: API.TableRelationships
artistsTableRelationships =
let joinFieldMapping = HashMap.fromList [(API.ColumnName "ArtistId", API.ColumnName "ArtistId")]
let joinFieldMapping = API.ColumnPathMapping $ HashMap.fromList [(API.mkColumnSelector $ API.ColumnName "ArtistId", API.mkColumnSelector $ API.ColumnName "ArtistId")]
in API.TableRelationships
artistsTableName
( HashMap.fromList
@ -175,8 +175,8 @@ albumsRowsById =
albumsTableRelationships :: API.TableRelationships
albumsTableRelationships =
let artistsJoinFieldMapping = HashMap.fromList [(API.ColumnName "ArtistId", API.ColumnName "ArtistId")]
tracksJoinFieldMapping = HashMap.fromList [(API.ColumnName "AlbumId", API.ColumnName "AlbumId")]
let artistsJoinFieldMapping = API.ColumnPathMapping $ HashMap.fromList [(API.mkColumnSelector $ API.ColumnName "ArtistId", API.mkColumnSelector $ API.ColumnName "ArtistId")]
tracksJoinFieldMapping = API.ColumnPathMapping $ HashMap.fromList [(API.mkColumnSelector $ API.ColumnName "AlbumId", API.mkColumnSelector $ API.ColumnName "AlbumId")]
in API.TableRelationships
albumsTableName
( HashMap.fromList
@ -203,8 +203,8 @@ customersRowsById =
customersTableRelationships :: API.TableRelationships
customersTableRelationships =
let supportRepJoinFieldMapping = HashMap.fromList [(API.ColumnName "SupportRepId", API.ColumnName "EmployeeId")]
invoicesJoinFieldMapping = HashMap.fromList [(API.ColumnName "CustomerId", API.ColumnName "CustomerId")]
let supportRepJoinFieldMapping = API.ColumnPathMapping $ HashMap.fromList [(API.mkColumnSelector $ API.ColumnName "SupportRepId", API.mkColumnSelector $ API.ColumnName "EmployeeId")]
invoicesJoinFieldMapping = API.ColumnPathMapping $ HashMap.fromList [(API.mkColumnSelector $ API.ColumnName "CustomerId", API.mkColumnSelector $ API.ColumnName "CustomerId")]
in API.TableRelationships
customersTableName
( HashMap.fromList
@ -231,8 +231,8 @@ employeesRowsById =
employeesTableRelationships :: API.TableRelationships
employeesTableRelationships =
let supportRepJoinFieldMapping = HashMap.fromList [(API.ColumnName "EmployeeId", API.ColumnName "SupportRepId")]
reportsToEmployeeJoinFieldMapping = HashMap.fromList [(API.ColumnName "ReportsTo", API.ColumnName "EmployeeId")]
let supportRepJoinFieldMapping = API.ColumnPathMapping $ HashMap.fromList [(API.mkColumnSelector $ API.ColumnName "EmployeeId", API.mkColumnSelector $ API.ColumnName "SupportRepId")]
reportsToEmployeeJoinFieldMapping = API.ColumnPathMapping $ HashMap.fromList [(API.mkColumnSelector $ API.ColumnName "ReportsTo", API.mkColumnSelector $ API.ColumnName "EmployeeId")]
in API.TableRelationships
employeesTableName
( HashMap.fromList
@ -259,8 +259,8 @@ invoicesRowsById =
invoicesTableRelationships :: API.TableRelationships
invoicesTableRelationships =
let invoiceLinesJoinFieldMapping = HashMap.fromList [(API.ColumnName "InvoiceId", API.ColumnName "InvoiceId")]
customersJoinFieldMapping = HashMap.fromList [(API.ColumnName "CustomerId", API.ColumnName "CustomerId")]
let invoiceLinesJoinFieldMapping = API.ColumnPathMapping $ HashMap.fromList [(API.mkColumnSelector $ API.ColumnName "InvoiceId", API.mkColumnSelector $ API.ColumnName "InvoiceId")]
customersJoinFieldMapping = API.ColumnPathMapping $ HashMap.fromList [(API.mkColumnSelector $ API.ColumnName "CustomerId", API.mkColumnSelector $ API.ColumnName "CustomerId")]
in API.TableRelationships
invoicesTableName
( HashMap.fromList
@ -280,8 +280,8 @@ invoiceLinesRows = sortBy (API.FieldName "InvoiceLineId") $ readTableFromXmlInto
invoiceLinesTableRelationships :: API.TableRelationships
invoiceLinesTableRelationships =
let invoiceJoinFieldMapping = HashMap.fromList [(API.ColumnName "InvoiceId", API.ColumnName "InvoiceId")]
tracksJoinFieldMapping = HashMap.fromList [(API.ColumnName "TrackId", API.ColumnName "TrackId")]
let invoiceJoinFieldMapping = API.ColumnPathMapping $ HashMap.fromList [(API.mkColumnSelector $ API.ColumnName "InvoiceId", API.mkColumnSelector $ API.ColumnName "InvoiceId")]
tracksJoinFieldMapping = API.ColumnPathMapping $ HashMap.fromList [(API.mkColumnSelector $ API.ColumnName "TrackId", API.mkColumnSelector $ API.ColumnName "TrackId")]
in API.TableRelationships
invoiceLinesTableName
( HashMap.fromList
@ -314,11 +314,11 @@ tracksRowsById =
tracksTableRelationships :: API.TableRelationships
tracksTableRelationships =
let invoiceLinesJoinFieldMapping = HashMap.fromList [(API.ColumnName "TrackId", API.ColumnName "TrackId")]
mediaTypeJoinFieldMapping = HashMap.fromList [(API.ColumnName "MediaTypeId", API.ColumnName "MediaTypeId")]
albumJoinFieldMapping = HashMap.fromList [(API.ColumnName "AlbumId", API.ColumnName "AlbumId")]
genreJoinFieldMapping = HashMap.fromList [(API.ColumnName "GenreId", API.ColumnName "GenreId")]
playlistTracksJoinFieldMapping = HashMap.fromList [(API.ColumnName "TrackId", API.ColumnName "TrackId")]
let invoiceLinesJoinFieldMapping = API.ColumnPathMapping $ HashMap.fromList [(API.mkColumnSelector $ API.ColumnName "TrackId", API.mkColumnSelector $ API.ColumnName "TrackId")]
mediaTypeJoinFieldMapping = API.ColumnPathMapping $ HashMap.fromList [(API.mkColumnSelector $ API.ColumnName "MediaTypeId", API.mkColumnSelector $ API.ColumnName "MediaTypeId")]
albumJoinFieldMapping = API.ColumnPathMapping $ HashMap.fromList [(API.mkColumnSelector $ API.ColumnName "AlbumId", API.mkColumnSelector $ API.ColumnName "AlbumId")]
genreJoinFieldMapping = API.ColumnPathMapping $ HashMap.fromList [(API.mkColumnSelector $ API.ColumnName "GenreId", API.mkColumnSelector $ API.ColumnName "GenreId")]
playlistTracksJoinFieldMapping = API.ColumnPathMapping $ HashMap.fromList [(API.mkColumnSelector $ API.ColumnName "TrackId", API.mkColumnSelector $ API.ColumnName "TrackId")]
in API.TableRelationships
tracksTableName
( HashMap.fromList
@ -359,7 +359,7 @@ mkFibonacciRows n = take n $ fibonacciRow <$> fibs
genresTableRelationships :: API.TableRelationships
genresTableRelationships =
let joinFieldMapping = HashMap.fromList [(API.ColumnName "GenreId", API.ColumnName "GenreId")]
let joinFieldMapping = API.ColumnPathMapping $ HashMap.fromList [(API.mkColumnSelector $ API.ColumnName "GenreId", API.mkColumnSelector $ API.ColumnName "GenreId")]
in API.TableRelationships
genresTableName
( HashMap.fromList
@ -538,7 +538,13 @@ mkTestData schemaResponse testConfig =
formatTableRelationships :: API.TableRelationships -> API.TableRelationships
formatTableRelationships =
prefixTableRelationships
>>> API.trelRelationships . traverse . API.rColumnMapping %~ (HashMap.toList >>> fmap (bimap (formatColumnName testConfig) (formatColumnName testConfig)) >>> HashMap.fromList)
>>> API.trelRelationships . traverse . API.rColumnMapping
%~ ( API.unColumnPathMapping
>>> HashMap.toList
>>> fmap (bimap (formatColumnSelector testConfig) (formatColumnSelector testConfig))
>>> HashMap.fromList
>>> API.ColumnPathMapping
)
prefixTableRelationships :: API.TableRelationships -> API.TableRelationships
prefixTableRelationships =
@ -623,7 +629,7 @@ formatTableInfo testConfig =
>>> API.tiPrimaryKey . _Just . traverse %~ formatColumnName testConfig
>>> API.tiForeignKeys . API.unForeignKeys . traverse
%~ ( API.cForeignTable %~ formatTableName testConfig
>>> API.cColumnMapping %~ (HashMap.toList >>> fmap (bimap (formatColumnName testConfig) (formatColumnName testConfig)) >>> HashMap.fromList)
>>> API.cColumnMapping %~ (API.unColumnPathMapping >>> HashMap.toList >>> fmap (bimap (formatColumnSelector testConfig) (formatColumnSelector testConfig)) >>> HashMap.fromList >>> API.ColumnPathMapping)
)
applyTableNamePrefix :: [Text] -> API.TableName -> API.TableName
@ -647,6 +653,11 @@ applyNameCasing casing text = case casing of
formatColumnName :: TestConfig -> API.ColumnName -> API.ColumnName
formatColumnName TestConfig {..} = API.ColumnName . applyNameCasing _tcColumnNameCasing . API.unColumnName
formatColumnSelector :: TestConfig -> API.ColumnSelector -> API.ColumnSelector
formatColumnSelector testConfig = \case
API.ColumnSelectorPath p -> API.ColumnSelectorPath $ formatColumnName testConfig <$> p
API.ColumnSelectorColumn c -> API.ColumnSelectorColumn $ formatColumnName testConfig c
columnField :: API.SchemaResponse -> TestConfig -> API.TableName -> Text -> API.Field
columnField schemaResponse testConfig tableName columnName =
API.ColumnField columnName' scalarType Nothing

View File

@ -116,7 +116,7 @@ spec testConfig API.Capabilities {} = describe "supports functions" $ preloadAge
]
query' = Data.emptyQuery & qFields ?~ fields
authorRelationship =
let authorsJoinFieldMapping = HashMap.fromList [(API.ColumnName "author_id", API.ColumnName "id")]
let authorsJoinFieldMapping = API.ColumnPathMapping $ HashMap.fromList [(API.mkColumnSelector $ API.ColumnName "author_id", API.mkColumnSelector $ API.ColumnName "id")]
in API.FunctionRelationships
_ftdSearchArticlesFunctionName
( HashMap.fromList
@ -164,7 +164,7 @@ spec testConfig API.Capabilities {} = describe "supports functions" $ preloadAge
(API.ScalarValueComparison (API.ScalarValue (Number 10) (API.ScalarType "number")))
query' = Data.emptyQuery & qFields ?~ fields & qWhere ?~ whereClause & qLimit ?~ 2
authorRelationship =
let authorsJoinFieldMapping = HashMap.fromList [(API.ColumnName "author_id", API.ColumnName "id")]
let authorsJoinFieldMapping = API.ColumnPathMapping $ HashMap.fromList [(API.mkColumnSelector $ API.ColumnName "author_id", API.mkColumnSelector $ API.ColumnName "id")]
in API.FunctionRelationships
_ftdSearchArticlesFunctionName
( HashMap.fromList

View File

@ -220,7 +220,12 @@ schema =
API._tiDescription = Just "Collection of music albums created by artists",
API._tiForeignKeys =
API.ForeignKeys
$ HashMap.singleton (API.ConstraintName "Artist") (API.Constraint (mkTableName "Artist") (HashMap.singleton (API.ColumnName "ArtistId") (API.ColumnName "ArtistId"))),
$ HashMap.singleton
(API.ConstraintName "Artist")
( API.Constraint
(mkTableName "Artist")
(API.ColumnPathMapping $ HashMap.singleton (API.mkColumnSelector $ API.ColumnName "ArtistId") (API.mkColumnSelector $ API.ColumnName "ArtistId"))
),
API._tiInsertable = True,
API._tiUpdatable = True,
API._tiDeletable = True
@ -351,7 +356,12 @@ schema =
API._tiDescription = Just "Collection of customers who can buy tracks",
API._tiForeignKeys =
API.ForeignKeys
$ HashMap.singleton (API.ConstraintName "CustomerSupportRep") (API.Constraint (mkTableName "Employee") (HashMap.singleton (API.ColumnName "SupportRepId") (API.ColumnName "EmployeeId"))),
$ HashMap.singleton
(API.ConstraintName "CustomerSupportRep")
( API.Constraint
(mkTableName "Employee")
(API.ColumnPathMapping $ HashMap.singleton (API.mkColumnSelector $ API.ColumnName "SupportRepId") (API.mkColumnSelector $ API.ColumnName "EmployeeId"))
),
API._tiInsertable = True,
API._tiUpdatable = True,
API._tiDeletable = True
@ -500,7 +510,12 @@ schema =
API._tiDescription = Just "Collection of employees who work for the business",
API._tiForeignKeys =
API.ForeignKeys
$ HashMap.singleton (API.ConstraintName "EmployeeReportsTo") (API.Constraint (mkTableName "Employee") (HashMap.singleton (API.ColumnName "ReportsTo") (API.ColumnName "EmployeeId"))),
$ HashMap.singleton
(API.ConstraintName "EmployeeReportsTo")
( API.Constraint
(mkTableName "Employee")
(API.ColumnPathMapping $ HashMap.singleton (API.mkColumnSelector $ API.ColumnName "ReportsTo") (API.mkColumnSelector $ API.ColumnName "EmployeeId"))
),
API._tiInsertable = True,
API._tiUpdatable = True,
API._tiDeletable = True
@ -626,7 +641,9 @@ schema =
API._tiForeignKeys =
API.ForeignKeys
$ HashMap.singleton (API.ConstraintName "InvoiceCustomer")
$ API.Constraint (mkTableName "Customer") (HashMap.singleton (API.ColumnName "CustomerId") (API.ColumnName "CustomerId")),
$ API.Constraint
(mkTableName "Customer")
(API.ColumnPathMapping $ HashMap.singleton (API.mkColumnSelector $ API.ColumnName "CustomerId") (API.mkColumnSelector $ API.ColumnName "CustomerId")),
API._tiInsertable = True,
API._tiUpdatable = True,
API._tiDeletable = True
@ -686,8 +703,16 @@ schema =
API._tiForeignKeys =
API.ForeignKeys
$ HashMap.fromList
[ (API.ConstraintName "Invoice", API.Constraint (mkTableName "Invoice") (HashMap.singleton (API.ColumnName "InvoiceId") (API.ColumnName "InvoiceId"))),
(API.ConstraintName "Track", API.Constraint (mkTableName "Track") (HashMap.singleton (API.ColumnName "TrackId") (API.ColumnName "TrackId")))
[ ( API.ConstraintName "Invoice",
API.Constraint
(mkTableName "Invoice")
(API.ColumnPathMapping $ HashMap.singleton (API.mkColumnSelector $ API.ColumnName "InvoiceId") (API.mkColumnSelector $ API.ColumnName "InvoiceId"))
),
( API.ConstraintName "Track",
API.Constraint
(mkTableName "Track")
(API.ColumnPathMapping $ HashMap.singleton (API.mkColumnSelector $ API.ColumnName "TrackId") (API.mkColumnSelector $ API.ColumnName "TrackId"))
)
],
API._tiInsertable = True,
API._tiUpdatable = True,
@ -814,9 +839,21 @@ schema =
API._tiForeignKeys =
API.ForeignKeys
$ HashMap.fromList
[ (API.ConstraintName "Album", API.Constraint (mkTableName "Album") (HashMap.singleton (API.ColumnName "AlbumId") (API.ColumnName "AlbumId"))),
(API.ConstraintName "Genre", API.Constraint (mkTableName "Genre") (HashMap.singleton (API.ColumnName "GenreId") (API.ColumnName "GenreId"))),
(API.ConstraintName "MediaType", API.Constraint (mkTableName "MediaType") (HashMap.singleton (API.ColumnName "MediaTypeId") (API.ColumnName "MediaTypeId")))
[ ( API.ConstraintName "Album",
API.Constraint
(mkTableName "Album")
(API.ColumnPathMapping $ HashMap.singleton (API.mkColumnSelector $ API.ColumnName "AlbumId") (API.mkColumnSelector $ API.ColumnName "AlbumId"))
),
( API.ConstraintName "Genre",
API.Constraint
(mkTableName "Genre")
(API.ColumnPathMapping $ HashMap.singleton (API.mkColumnSelector $ API.ColumnName "GenreId") (API.mkColumnSelector $ API.ColumnName "GenreId"))
),
( API.ConstraintName "MediaType",
API.Constraint
(mkTableName "MediaType")
(API.ColumnPathMapping $ HashMap.singleton (API.mkColumnSelector $ API.ColumnName "MediaTypeId") (API.mkColumnSelector $ API.ColumnName "MediaTypeId"))
)
],
API._tiInsertable = True,
API._tiUpdatable = True,

View File

@ -632,7 +632,7 @@ unfurlAnnotatedOrderByElement =
pure (fieldName, expression)
Ir.AOCObjectRelation Rql.RelInfo {riTarget = Rql.RelTargetNativeQuery _} _annBoolExp _annOrderByElementG ->
error "unfurlAnnotatedOrderByElement RelTargetNativeQuery"
Ir.AOCObjectRelation Rql.RelInfo {riMapping = mapping, riTarget = Rql.RelTargetTable tableName} annBoolExp annOrderByElementG -> do
Ir.AOCObjectRelation Rql.RelInfo {riMapping = Rql.RelMapping mapping, riTarget = Rql.RelTargetTable tableName} annBoolExp annOrderByElementG -> do
selectFrom <- lift (lift (fromQualifiedTable tableName))
joinAliasEntity <-
lift (lift (generateEntityAlias (ForOrderAlias (tableNameText tableName))))
@ -674,7 +674,7 @@ unfurlAnnotatedOrderByElement =
local (const joinAliasEntity) (unfurlAnnotatedOrderByElement annOrderByElementG)
Ir.AOCArrayAggregation Rql.RelInfo {riTarget = Rql.RelTargetNativeQuery _} _annBoolExp _annAggregateOrderBy ->
error "unfurlAnnotatedOrderByElement RelTargetNativeQuery"
Ir.AOCArrayAggregation Rql.RelInfo {riMapping = mapping, riTarget = Rql.RelTargetTable tableName} annBoolExp annAggregateOrderBy -> do
Ir.AOCArrayAggregation Rql.RelInfo {riMapping = Rql.RelMapping mapping, riTarget = Rql.RelTargetTable tableName} annBoolExp annAggregateOrderBy -> do
selectFrom <- lift (lift (fromQualifiedTable tableName))
let alias = aggFieldName
joinAlias <-
@ -835,7 +835,7 @@ fromAnnBoolExpFld =
error "fromAnnBoolExpFld RelTargetNativeQuery"
Ir.AVRemoteRelationship _ ->
error "fromAnnBoolExpFld RemoteRelationship"
Ir.AVRelationship Rql.RelInfo {riMapping = mapping, riTarget = Rql.RelTargetTable table} (Ir.RelationshipFilters tablePerms annBoolExp) -> do
Ir.AVRelationship Rql.RelInfo {riMapping = Rql.RelMapping mapping, riTarget = Rql.RelTargetTable table} (Ir.RelationshipFilters tablePerms annBoolExp) -> do
selectFrom <- lift (fromQualifiedTable table)
foreignKeyConditions <- fromMapping selectFrom mapping
whereExpression <-

View File

@ -28,6 +28,7 @@ instance Backend 'BigQuery where
type NullsOrderType 'BigQuery = BigQuery.NullsOrder
type CountType 'BigQuery = BigQuery.CountType
type Column 'BigQuery = BigQuery.ColumnName
type ColumnPath 'BigQuery = BigQuery.ColumnName
type ScalarValue 'BigQuery = BigQuery.Value
type ScalarType 'BigQuery = BigQuery.ScalarType
type SQLExpression 'BigQuery = BigQuery.Expression
@ -117,6 +118,10 @@ instance Backend 'BigQuery where
getColVals _ _ _ _ _ _ = throw500 "getColVals: not implemented for the BigQuery backend"
getColumnPathColumn = id
tryColumnPathToColumn = Just
instance HasSourceConfiguration 'BigQuery where
type SourceConfig 'BigQuery = BigQuery.BigQuerySourceConfig
type SourceConnConfiguration 'BigQuery = BigQuery.BigQueryConnSourceConfig

View File

@ -56,6 +56,7 @@ instance Backend 'DataConnector where
type NullsOrderType 'DataConnector = Unimplemented
type CountType 'DataConnector = DC.CountAggregate
type Column 'DataConnector = DC.ColumnName
type ColumnPath 'DataConnector = DC.ColumnPath
type ScalarValue 'DataConnector = J.Value
type ScalarType 'DataConnector = DC.ScalarType
@ -167,6 +168,15 @@ instance Backend 'DataConnector where
getColVals _ _ _ _ _ _ = throw500 "getColVals: not implemented for the Data Connector backend"
getColumnPathColumn = \case
DC.CPPath p -> NonEmpty.head p
DC.CPColumn c -> c
tryColumnPathToColumn = \case
DC.CPPath (column :| []) -> Just column
DC.CPColumn column -> Just column
_ -> Nothing
backendSupportsNestedObjects = pure ()
sourceSupportsSchemalessTables =

View File

@ -8,7 +8,6 @@ import Control.Monad.Trans.Control
import Data.Aeson qualified as J
import Data.Aeson.Key qualified as K
import Data.Aeson.KeyMap qualified as KM
import Data.Bifunctor (bimap)
import Data.Environment (Environment)
import Data.Has (Has (getter))
import Data.HashMap.Strict qualified as HashMap
@ -71,7 +70,7 @@ import Hasura.RQL.Types.Metadata (SourceMetadata (..))
import Hasura.RQL.Types.Metadata.Backend (BackendMetadata (..))
import Hasura.RQL.Types.Metadata.Object
import Hasura.RQL.Types.NamingCase (NamingCase)
import Hasura.RQL.Types.Relationships.Local (ArrRelDef, ObjRelDef, RelInfo ())
import Hasura.RQL.Types.Relationships.Local (ArrRelDef, ObjRelDef, RelInfo (), RelMapping (..))
import Hasura.RQL.Types.SchemaCache (CacheRM, askSourceConfig, askSourceInfo)
import Hasura.RQL.Types.SchemaCache.Build
import Hasura.RQL.Types.SchemaCacheTypes (DependencyReason (DRTable), SchemaDependency (SchemaDependency), SchemaObjId (SOSourceObj), SourceObjId (SOITable))
@ -474,7 +473,7 @@ buildForeignKeySet (API.ForeignKeys constraints) =
$ constraints
& HashMap.foldMapWithKey @[RQL.T.T.ForeignKeyMetadata 'DataConnector]
\constraintName API.Constraint {..} -> maybeToList do
let columnMapAssocList = HashMap.foldrWithKey' (\(API.ColumnName k) (API.ColumnName v) acc -> (DC.ColumnName k, DC.ColumnName v) : acc) [] _cColumnMapping
let columnMapAssocList = HashMap.foldrWithKey' (\k v acc -> (Witch.from k, Witch.from v) : acc) [] $ API.unColumnPathMapping _cColumnMapping
columnMapping <- NEHashMap.fromList columnMapAssocList
let foreignKey =
RQL.T.T.ForeignKey
@ -786,7 +785,7 @@ convertTableMetadataToTableInfo tableName logicalModelCache RQL.T.T.DBTableMetad
constraint =
SourceConstraint
{ _scForeignTable = Witch.from _fkForeignTable,
_scColumnMapping = HashMap.fromList $ bimap Witch.from Witch.from <$> NEHashMap.toList _fkColumnMapping
_scColumnMapping = RelMapping $ NEHashMap.toHashMap _fkColumnMapping
}
in (constraintName, constraint)
)

View File

@ -23,6 +23,7 @@ module Hasura.Backends.DataConnector.Adapter.Types
TableName (..),
ConstraintName (..),
ColumnName (..),
ColumnPath (..),
FunctionName (..),
FunctionReturnType (..),
CountAggregate (..),
@ -414,6 +415,41 @@ instance ToTxt ColumnName where
instance ToErrorValue ColumnName where
toErrorValue = ErrorValue.squote . unColumnName
instance Witch.From ColumnName ColumnPath where
from = CPColumn
--------------------------------------------------------------------------------
data ColumnPath
= CPPath (NonEmpty ColumnName)
| CPColumn (ColumnName)
deriving stock (Eq, Ord, Show, Generic)
deriving (FromJSON, ToJSON, ToSchema) via AC.Autodocodec ColumnPath
deriving anyclass (Hashable, NFData)
instance HasCodec ColumnPath where
codec = AC.disjointMatchChoiceCodec pathCodec columnCodec chooser
where
pathCodec = AC.dimapCodec CPPath id (codec @(NonEmpty ColumnName))
columnCodec = AC.dimapCodec CPColumn id (codec @ColumnName)
chooser = \case
CPPath p -> Left p
CPColumn c -> Right c
instance ToJSONKey ColumnPath
instance FromJSONKey ColumnPath
instance Witch.From API.ColumnSelector ColumnPath where
from = \case
API.ColumnSelectorPath p -> CPPath $ Witch.from <$> p
API.ColumnSelectorColumn c -> CPColumn $ Witch.from c
instance Witch.From ColumnPath API.ColumnSelector where
from = \case
CPPath p -> API.ColumnSelectorPath $ Witch.from <$> p
CPColumn c -> API.ColumnSelectorColumn $ Witch.from c
--------------------------------------------------------------------------------
newtype FunctionName = FunctionName {unFunctionName :: NonEmpty Text}

View File

@ -68,7 +68,7 @@ import Hasura.RQL.Types.Backend (Backend, SessionVarType, getColVals)
import Hasura.RQL.Types.BackendType
import Hasura.RQL.Types.Column
import Hasura.RQL.Types.Common
import Hasura.RQL.Types.Relationships.Local (RelInfo (..), RelTarget (..))
import Hasura.RQL.Types.Relationships.Local (RelInfo (..), RelMapping (..), RelTarget (..))
import Hasura.SQL.AnyBackend qualified as AB
import Hasura.SQL.Types (CollectableType (..))
import Hasura.Session
@ -151,7 +151,7 @@ recordTableRelationshipFromRelInfo sourceTableName RelInfo {..} = do
API.Relationship
{ _rTarget = API.TTable (API.TargetTable (Witch.from targetTableName)),
_rRelationshipType = relationshipType,
_rColumnMapping = HashMap.fromList $ bimap Witch.from Witch.from <$> HashMap.toList riMapping
_rColumnMapping = API.ColumnPathMapping $ HashMap.fromList $ bimap Witch.from Witch.from <$> HashMap.toList (unRelMapping riMapping)
}
recordRelationship
sourceTableName
@ -346,8 +346,10 @@ pushColumn :: ColumnStack -> ColumnName -> ColumnStack
pushColumn (ColumnStack stack) columnName = ColumnStack $ columnName : stack
toColumnSelector :: ColumnStack -> ColumnName -> API.ColumnSelector
toColumnSelector (ColumnStack []) columnName =
API.ColumnSelectorColumn $ Witch.from columnName
toColumnSelector (ColumnStack stack) columnName =
API.ColumnSelector $ NonEmpty.reverse $ Witch.from columnName :| fmap Witch.from stack
API.ColumnSelectorPath $ NonEmpty.reverse $ Witch.from columnName :| fmap Witch.from stack
--------------------------------------------------------------------------------

View File

@ -214,7 +214,7 @@ fromNativeQueryArray arrRel translateFieldsAndAggregates sourceTargetName native
API.Relationship
{ _rTarget = TInterpolated (API.TargetInterpolatedQuery nqid),
_rRelationshipType = API.ArrayRelationship,
_rColumnMapping = HashMap.fromList $ bimap Witch.from Witch.from <$> HashMap.toList (_aarColumnMapping arrRel)
_rColumnMapping = API.ColumnPathMapping $ HashMap.fromList $ bimap Witch.from Witch.from <$> HashMap.toList (_aarColumnMapping arrRel)
}
pure
@ -252,7 +252,7 @@ fromNativeQueryObject objRel sourceTargetName nativeQuery = do
API.Relationship
{ _rTarget = TInterpolated (API.TargetInterpolatedQuery nqid),
_rRelationshipType = API.ObjectRelationship,
_rColumnMapping = HashMap.fromList $ bimap Witch.from Witch.from <$> HashMap.toList (_aarColumnMapping objRel)
_rColumnMapping = API.ColumnPathMapping $ HashMap.fromList $ bimap Witch.from Witch.from <$> HashMap.toList (_aarColumnMapping objRel)
}
pure
@ -526,7 +526,7 @@ translateAnnField targetName = \case
API.Relationship
{ _rTarget = API.TTable (API.TargetTable targetTable),
_rRelationshipType = API.ObjectRelationship,
_rColumnMapping = HashMap.fromList $ bimap Witch.from Witch.from <$> HashMap.toList (_aarColumnMapping objRel)
_rColumnMapping = API.ColumnPathMapping $ HashMap.fromList $ bimap Witch.from Witch.from <$> HashMap.toList (_aarColumnMapping objRel)
}
pure
@ -586,7 +586,7 @@ translateArrayRelationSelect targetName translateFieldsAndAggregates arrRel = do
API.Relationship
{ _rTarget = API.TTable (API.TargetTable (Witch.into targetTable)),
_rRelationshipType = API.ArrayRelationship,
_rColumnMapping = HashMap.fromList $ bimap Witch.from Witch.from <$> HashMap.toList (_aarColumnMapping arrRel)
_rColumnMapping = API.ColumnPathMapping $ HashMap.fromList $ bimap Witch.from Witch.from <$> HashMap.toList (_aarColumnMapping arrRel)
}
pure

View File

@ -86,7 +86,7 @@ fromAnnBoolExpFld =
expressions <- traverse (fromOpExpG columnInfo) opExpGs
potentiallyRedacted redactionExp (AndExpression expressions)
IR.AVRemoteRelationship _ -> error "fromAnnBoolExpFld RemoteRelationship"
IR.AVRelationship IR.RelInfo {riMapping = mapping, riTarget = target} (IR.RelationshipFilters tablePerm annBoolExp) -> do
IR.AVRelationship IR.RelInfo {riMapping = IR.RelMapping mapping, riTarget = target} (IR.RelationshipFilters tablePerm annBoolExp) -> do
case target of
IR.RelTargetNativeQuery _ -> error "fromAnnBoolExpFld RelTargetNativeQuery"
IR.RelTargetTable table -> do

View File

@ -991,20 +991,20 @@ unfurlAnnotatedOrderByElement =
-- text/ntext/image. See ToQuery for more explanation.
_ -> Nothing
)
IR.AOCObjectRelation IR.RelInfo {riMapping = mapping, riTarget = IR.RelTargetNativeQuery nativeQueryName} annBoolExp annOrderByElementG -> do
IR.AOCObjectRelation IR.RelInfo {riMapping = IR.RelMapping mapping, riTarget = IR.RelTargetNativeQuery nativeQueryName} annBoolExp annOrderByElementG -> do
let name = T.toTxt (getNativeQueryName nativeQueryName)
selectFrom = TSQL.FromIdentifier name
joinAliasEntity <-
lift (lift (generateAlias (ForOrderAlias name)))
genObjectRelation mapping annBoolExp annOrderByElementG joinAliasEntity selectFrom (Left nativeQueryName)
IR.AOCObjectRelation IR.RelInfo {riMapping = mapping, riTarget = IR.RelTargetTable table} annBoolExp annOrderByElementG -> do
IR.AOCObjectRelation IR.RelInfo {riMapping = IR.RelMapping mapping, riTarget = IR.RelTargetTable table} annBoolExp annOrderByElementG -> do
selectFrom <- lift (lift (fromQualifiedTable table))
joinAliasEntity <-
lift (lift (generateAlias (ForOrderAlias (tableNameText table))))
genObjectRelation mapping annBoolExp annOrderByElementG joinAliasEntity selectFrom (Right table)
IR.AOCArrayAggregation IR.RelInfo {riTarget = IR.RelTargetNativeQuery _} _annBoolExp _annAggregateOrderBy ->
error "unfurlAnnotatedOrderByElement RelTargetNativeQuery"
IR.AOCArrayAggregation IR.RelInfo {riMapping = mapping, riTarget = IR.RelTargetTable tableName} annBoolExp annAggregateOrderBy -> do
IR.AOCArrayAggregation IR.RelInfo {riMapping = IR.RelMapping mapping, riTarget = IR.RelTargetTable tableName} annBoolExp annAggregateOrderBy -> do
selectFrom <- lift (lift (fromQualifiedTable tableName))
let alias = aggFieldName
joinAliasEntity <-

View File

@ -40,6 +40,7 @@ instance Backend 'MSSQL where
type NullsOrderType 'MSSQL = MSSQL.NullsOrder
type CountType 'MSSQL = MSSQL.CountType
type Column 'MSSQL = MSSQL.ColumnName
type ColumnPath 'MSSQL = MSSQL.ColumnName
type ScalarValue 'MSSQL = MSSQL.Value
type ScalarType 'MSSQL = MSSQL.ScalarType
type BooleanOperators 'MSSQL = MSSQL.BooleanOperators
@ -123,6 +124,10 @@ instance Backend 'MSSQL where
getColVals _ _ _ _ _ _ = throw500 "getColVals: not implemented for the MSSQL backend"
getColumnPathColumn = id
tryColumnPathToColumn = Just
instance HasSourceConfiguration 'MSSQL where
type SourceConfig 'MSSQL = MSSQL.MSSQLSourceConfig
type SourceConnConfiguration 'MSSQL = MSSQL.MSSQLConnConfiguration

View File

@ -195,7 +195,7 @@ insertObject singleObjIns additionalColumns userInfo planVars stringifyNum tCase
afterInsertDepCols :: [ColumnInfo ('Postgres pgKind)]
afterInsertDepCols =
flip (getColInfos @('Postgres pgKind)) allColumns
$ concatMap (HashMap.keys . riMapping . IR._riRelationInfo) allAfterInsertRels
$ concatMap (HashMap.keys . unRelMapping . riMapping . IR._riRelationInfo) allAfterInsertRels
withArrRels ::
Maybe (ColumnValues ('Postgres pgKind) TxtEncodedVal) ->
@ -258,7 +258,7 @@ insertObjRel planVars userInfo stringifyNum tCase objRelIns =
table = case riTarget relInfo of
RelTargetNativeQuery _ -> error "insertObjRel RelTargetNativeQuery"
RelTargetTable tn -> tn
mapCols = riMapping relInfo
mapCols = unRelMapping $ riMapping relInfo
allCols = IR._aiTableColumns singleObjIns
rCols = HashMap.elems mapCols
rColInfos = getColInfos rCols allCols
@ -298,7 +298,7 @@ insertArrRel resCols userInfo planVars stringifyNum tCase arrRelIns =
$ throw500 "affected_rows not returned in array rel insert"
where
IR.RelationInsert multiObjIns relInfo = arrRelIns
mapping = riMapping relInfo
mapping = unRelMapping $ riMapping relInfo
mutOutput = IR.MOutMultirowFields [("affected_rows", IR.MCount)]
-- | Validate an insert object based on insert columns,
@ -325,7 +325,7 @@ validateInsert insCols objRels addCols = do
<> " columns as their values are already being determined by parent insert"
forM_ objRels $ \relInfo -> do
let lCols = HashMap.keys $ riMapping relInfo
let lCols = HashMap.keys $ unRelMapping $ riMapping relInfo
relName = riName relInfo
relNameTxt = relNameToTxt relName
lColConflicts = lCols `intersect` (addCols <> insCols)

View File

@ -323,7 +323,7 @@ instance
let mappings :: HashMap Postgres.PGCol Postgres.PGCol
mappings = NEHashMap.toHashMap _fkColumnMapping
pure (_cName _fkConstraint, SourceConstraint _fkForeignTable mappings)
pure (_cName _fkConstraint, SourceConstraint _fkForeignTable $ RelMapping mappings)
pure
SourceTableInfo

View File

@ -103,6 +103,7 @@ instance
type NullsOrderType ('Postgres pgKind) = Postgres.NullsOrder
type CountType ('Postgres pgKind) = Postgres.CountAggregate pgKind
type Column ('Postgres pgKind) = Postgres.PGCol
type ColumnPath ('Postgres pgKind) = Postgres.PGCol
type ScalarValue ('Postgres pgKind) = Postgres.PGScalarValue
type ScalarType ('Postgres pgKind) = Postgres.PGScalarType
type BooleanOperators ('Postgres pgKind) = Postgres.BooleanOperators
@ -177,6 +178,10 @@ instance
getColVals = Postgres.getPGColValues
getColumnPathColumn = id
tryColumnPathToColumn = Just
instance
( HasTag ('Postgres pgKind)
) =>

View File

@ -375,12 +375,12 @@ translateAggPredArguments predArgs relTableNameIdentifier userInfo =
)
cols
translateTableRelationship :: (Monad m) => HashMap PGCol PGCol -> TableIdentifier -> BoolExpM m S.BoolExp
translateTableRelationship :: (Monad m) => RelMapping ('Postgres pgKind) -> TableIdentifier -> BoolExpM m S.BoolExp
translateTableRelationship colMapping relTableNameIdentifier = do
BoolExpCtx {currTableReference} <- ask
pure
$ sqlAnd
$ flip map (HashMap.toList colMapping)
$ flip map (HashMap.toList $ unRelMapping colMapping)
$ \(lCol, rCol) ->
S.BECompare
S.SEQ

View File

@ -132,7 +132,7 @@ processOrderByItems userInfo sourcePrefix' selectSourceQual fieldAlias' similarA
$ S.mkQIdenExp baseTableIdentifier
$ ciColumn pgColInfo
AOCObjectRelation relInfo relFilter rest -> withWriteObjectRelation $ do
let RelInfo {riName = relName, riMapping = colMapping, riTarget = relTarget} = relInfo
let RelInfo {riName = relName, riMapping = RelMapping colMapping, riTarget = relTarget} = relInfo
relSourcePrefix = mkObjectRelationTableAlias sourcePrefix relName
fieldName = mkOrderByFieldName relName
case relTarget of
@ -153,7 +153,7 @@ processOrderByItems userInfo sourcePrefix' selectSourceQual fieldAlias' similarA
S.mkQIdenExp relSourcePrefix relOrderByAlias
)
AOCArrayAggregation relInfo relFilter aggOrderBy -> withWriteArrayRelation $ do
let RelInfo {riName = relName, riMapping = colMapping, riTarget = relTarget} = relInfo
let RelInfo {riName = relName, riMapping = RelMapping colMapping, riTarget = relTarget} = relInfo
case relTarget of
RelTargetNativeQuery _ -> error "processAnnotatedOrderByElement RelTargetNativeQuery (AOCArrayAggregation)"
RelTargetTable relTable -> do

View File

@ -187,7 +187,7 @@ convertRemoteSourceRelationship ::
forall b.
(Backend b) =>
-- | Join columns for the relationship
HashMap (Column b) (Column b) ->
HashMap (ColumnPath b) (ColumnPath b) ->
-- | The LHS of the join, this is the expression which selects from json
-- objects
SelectFromG b (UnpreparedValue b) ->

View File

@ -1560,7 +1560,7 @@ relationshipField table ri@RelInfo {riTarget = RelTargetTable otherTableName} =
RelTargetTable tn -> Just tn
_ -> Nothing
in if (remoteTableName == Just table)
&& (riMapping remoteRI `HashMap.isInverseOf` riMapping ri)
&& (unRelMapping (riMapping remoteRI) `HashMap.isInverseOf` unRelMapping (riMapping ri))
&& (thisTablePerm == rfFilter)
then BoolAnd []
else x
@ -1610,7 +1610,7 @@ relationshipField table ri@RelInfo {riTarget = RelTargetTable otherTableName} =
nullable <- case (riIsManual ri, riInsertOrder ri) of
-- Automatically generated forward relationship
(False, BeforeParent) -> do
let columns = HashMap.keys $ riMapping ri
let columns = fmap (getColumnPathColumn @b) $ HashMap.keys $ unRelMapping $ riMapping ri
fieldInfoMap = _tciFieldInfoMap $ _tiCoreInfo tableInfo
findColumn col = HashMap.lookup (fromCol @b col) fieldInfoMap ^? _Just . _FIColumn . _SCIScalarColumn
-- Fetch information about the referencing columns of the foreign key
@ -1627,7 +1627,7 @@ relationshipField table ri@RelInfo {riTarget = RelTargetTable otherTableName} =
$ P.subselection_ relFieldName desc selectionSetParser
<&> \fields ->
IR.AFObjectRelation
$ IR.AnnRelationSelectG (riName ri) (riMapping ri) Nullable
$ IR.AnnRelationSelectG (riName ri) (unRelMapping $ riMapping ri) Nullable
$ IR.AnnObjectSelectG fields (IR.FromTable otherTableName)
$ deduplicatePermissions
$ IR._tpFilter
@ -1639,7 +1639,7 @@ relationshipField table ri@RelInfo {riTarget = RelTargetTable otherTableName} =
otherTableParser <&> \selectExp ->
IR.AFArrayRelation
$ IR.ASSimple
$ IR.AnnRelationSelectG (riName ri) (riMapping ri) Nullable
$ IR.AnnRelationSelectG (riName ri) (unRelMapping $ riMapping ri) Nullable
$ deduplicatePermissions' selectExp
relAggFieldName = applyFieldNameCaseCust tCase $ relFieldName <> Name.__aggregate
relAggDesc = Just $ G.Description "An aggregate relationship"
@ -1658,8 +1658,8 @@ relationshipField table ri@RelInfo {riTarget = RelTargetTable otherTableName} =
pure
$ catMaybes
[ Just arrayRelField,
fmap (IR.AFArrayRelation . IR.ASAggregate . IR.AnnRelationSelectG (riName ri) (riMapping ri) Nullable) <$> remoteAggField,
fmap (IR.AFArrayRelation . IR.ASConnection . IR.AnnRelationSelectG (riName ri) (riMapping ri) Nullable) <$> remoteConnectionField
fmap (IR.AFArrayRelation . IR.ASAggregate . IR.AnnRelationSelectG (riName ri) (unRelMapping $ riMapping ri) Nullable) <$> remoteAggField,
fmap (IR.AFArrayRelation . IR.ASConnection . IR.AnnRelationSelectG (riName ri) (unRelMapping $ riMapping ri) Nullable) <$> remoteConnectionField
]
relationshipField _table ri@RelInfo {riTarget = RelTargetNativeQuery nativeQueryName} = runMaybeT do
relFieldName <- lift $ textToName $ relNameToTxt $ riName ri
@ -1680,7 +1680,7 @@ relationshipField _table ri@RelInfo {riTarget = RelTargetNativeQuery nativeQuery
$ pure
$ nativeQueryParser
<&> \selectExp ->
IR.AFObjectRelation (IR.AnnRelationSelectG (riName ri) (riMapping ri) nullability selectExp)
IR.AFObjectRelation (IR.AnnRelationSelectG (riName ri) (unRelMapping $ riMapping ri) nullability selectExp)
ArrRel -> do
nativeQueryInfo <- askNativeQueryInfo nativeQueryName
@ -1697,4 +1697,4 @@ relationshipField _table ri@RelInfo {riTarget = RelTargetNativeQuery nativeQuery
<&> \selectExp ->
IR.AFArrayRelation
$ IR.ASSimple
$ IR.AnnRelationSelectG (riName ri) (riMapping ri) innerNullability selectExp
$ IR.AnnRelationSelectG (riName ri) (unRelMapping $ riMapping ri) innerNullability selectExp

View File

@ -48,7 +48,7 @@ import Hasura.RQL.IR.Value (Provenance (FreshVar), UnpreparedValue (UVParameter)
import Hasura.RQL.Types.Column qualified as Column
import Hasura.RQL.Types.Common (RelType (..), relNameToTxt)
import Hasura.RQL.Types.Metadata.Object qualified as MO
import Hasura.RQL.Types.Relationships.Local (Nullable (..), RelInfo (..), RelTarget (..))
import Hasura.RQL.Types.Relationships.Local (Nullable (..), RelInfo (..), RelMapping (..), RelTarget (..))
import Hasura.RQL.Types.Schema.Options qualified as Options
import Hasura.RQL.Types.Source
( SourceInfo (_siCustomization, _siName),
@ -328,7 +328,7 @@ nativeQueryRelationshipField ri | riType ri == ObjRel = runMaybeT do
pure
$ nativeQueryParser
<&> \selectExp ->
IR.AFObjectRelation (IR.AnnRelationSelectG (riName ri) (riMapping ri) nullability selectExp)
IR.AFObjectRelation (IR.AnnRelationSelectG (riName ri) (unRelMapping $ riMapping ri) nullability selectExp)
RelTargetTable otherTableName -> do
let desc = Just $ G.Description "An object relationship"
roleName <- retrieve scRole
@ -339,7 +339,7 @@ nativeQueryRelationshipField ri | riType ri == ObjRel = runMaybeT do
$ P.subselection_ relFieldName desc selectionSetParser
<&> \fields ->
IR.AFObjectRelation
$ IR.AnnRelationSelectG (riName ri) (riMapping ri) Nullable
$ IR.AnnRelationSelectG (riName ri) (unRelMapping $ riMapping ri) Nullable
$ IR.AnnObjectSelectG fields (IR.FromTable otherTableName)
$ IR._tpFilter
$ tablePermissionsInfo remotePerms
@ -361,7 +361,7 @@ nativeQueryRelationshipField ri = do
<&> \selectExp ->
IR.AFArrayRelation
$ IR.ASSimple
$ IR.AnnRelationSelectG (riName ri) (riMapping ri) innerNullability selectExp
$ IR.AnnRelationSelectG (riName ri) (unRelMapping $ riMapping ri) innerNullability selectExp
RelTargetTable otherTableName -> runMaybeT $ do
let arrayRelDesc = Just $ G.Description "An array relationship"
@ -371,6 +371,6 @@ nativeQueryRelationshipField ri = do
otherTableParser <&> \selectExp ->
IR.AFArrayRelation
$ IR.ASSimple
$ IR.AnnRelationSelectG (riName ri) (riMapping ri) Nullable
$ IR.AnnRelationSelectG (riName ri) (unRelMapping $ riMapping ri) Nullable
$ selectExp
pure arrayRelField

View File

@ -135,14 +135,15 @@ defaultBuildObjectRelationshipInfo ::
m (RelInfo b, Seq SchemaDependency)
defaultBuildObjectRelationshipInfo source foreignKeys qt (RelDef rn ru _) = case ru of
RUManual (RelManualNativeQueryConfig (RelManualNativeQueryConfigC {rmnNativeQueryName = refqt, rmnCommon = common})) -> do
let (lCols, rCols) = unzip $ HashMap.toList $ rmColumns common
let (lCols, rCols) = unzip $ HashMap.toList $ unRelMapping $ rmColumns common
io = fromMaybe BeforeParent $ rmInsertOrder common
mkNativeQueryDependency nativeQueryName reason col =
SchemaDependency
( SOSourceObj source
$ AB.mkAnyBackend
$ SOINativeQueryObj @b nativeQueryName
$ NQOCol @b col
$ NQOCol @b
$ getColumnPathColumn @b col
)
reason
mkDependency tableName reason col =
@ -150,7 +151,8 @@ defaultBuildObjectRelationshipInfo source foreignKeys qt (RelDef rn ru _) = case
( SOSourceObj source
$ AB.mkAnyBackend
$ SOITableObj @b tableName
$ TOCol @b col
$ TOCol @b
$ getColumnPathColumn @b col
)
reason
dependencies =
@ -158,14 +160,15 @@ defaultBuildObjectRelationshipInfo source foreignKeys qt (RelDef rn ru _) = case
<> (mkNativeQueryDependency refqt DRRightColumn <$> Seq.fromList rCols)
pure (RelInfo rn ObjRel (rmColumns common) (RelTargetNativeQuery refqt) True io, dependencies)
RUManual (RelManualTableConfig (RelManualTableConfigC {rmtTable = refqt, rmtCommon = common})) -> do
let (lCols, rCols) = unzip $ HashMap.toList $ rmColumns common
let (lCols, rCols) = unzip $ HashMap.toList $ unRelMapping $ rmColumns common
io = fromMaybe BeforeParent $ rmInsertOrder common
mkDependency tableName reason col =
SchemaDependency
( SOSourceObj source
$ AB.mkAnyBackend
$ SOITableObj @b tableName
$ TOCol @b col
$ TOCol @b
$ getColumnPathColumn @b col
)
reason
dependencies =
@ -195,8 +198,8 @@ defaultBuildObjectRelationshipInfo source foreignKeys qt (RelDef rn ru _) = case
)
DRRemoteTable
]
<> (drUsingColumnDep @b source qt <$> Seq.fromList (toList columns))
pure (RelInfo rn ObjRel (NEHashMap.toHashMap colMap) (RelTargetTable foreignTable) False BeforeParent, dependencies)
<> (drUsingColumnDep @b source qt <$> Seq.fromList (toList $ getColumnPathColumn @b <$> columns))
pure (RelInfo rn ObjRel (RelMapping $ NEHashMap.toHashMap colMap) (RelTargetTable foreignTable) False BeforeParent, dependencies)
RUFKeyOn (RemoteTable remoteTable remoteCols) ->
mkFkeyRel ObjRel AfterParent source rn qt remoteTable remoteCols foreignKeys
@ -219,7 +222,8 @@ nativeQueryRelationshipSetup sourceName nativeQueryName relType (RelDef relName
( SOSourceObj sourceName
$ AB.mkAnyBackend
$ SOINativeQueryObj @b refqt
$ NQOCol @b c
$ NQOCol @b
$ getColumnPathColumn @b c
)
DRRightColumn
)
@ -231,12 +235,13 @@ nativeQueryRelationshipSetup sourceName nativeQueryName relType (RelDef relName
( SOSourceObj sourceName
$ AB.mkAnyBackend
$ SOITableObj @b refqt
$ TOCol @b c
$ TOCol @b
$ getColumnPathColumn @b c
)
DRRightColumn
)
let (lCols, rCols) = unzip $ HashMap.toList $ rmColumns common
let (lCols, rCols) = unzip $ HashMap.toList $ unRelMapping $ rmColumns common
io = case relType of
ObjRel -> fromMaybe BeforeParent $ rmInsertOrder common
ArrRel -> AfterParent
@ -247,7 +252,8 @@ nativeQueryRelationshipSetup sourceName nativeQueryName relType (RelDef relName
( SOSourceObj sourceName
$ AB.mkAnyBackend
$ SOINativeQueryObj @b nativeQueryName
$ NQOCol @b c
$ NQOCol @b
$ getColumnPathColumn @b c
)
DRLeftColumn
)
@ -266,7 +272,7 @@ defaultBuildArrayRelationshipInfo ::
m (RelInfo b, Seq SchemaDependency)
defaultBuildArrayRelationshipInfo source foreignKeys qt (RelDef rn ru _) = case ru of
RUManual (RelManualNativeQueryConfig (RelManualNativeQueryConfigC {rmnNativeQueryName = refqt, rmnCommon = common})) -> do
let (lCols, rCols) = unzip $ HashMap.toList $ rmColumns common
let (lCols, rCols) = unzip $ HashMap.toList $ unRelMapping $ rmColumns common
deps =
( fmap
( \c ->
@ -274,7 +280,8 @@ defaultBuildArrayRelationshipInfo source foreignKeys qt (RelDef rn ru _) = case
( SOSourceObj source
$ AB.mkAnyBackend
$ SOITableObj @b qt
$ TOCol @b c
$ TOCol @b
$ getColumnPathColumn @b c
)
DRLeftColumn
)
@ -286,14 +293,15 @@ defaultBuildArrayRelationshipInfo source foreignKeys qt (RelDef rn ru _) = case
( SOSourceObj source
$ AB.mkAnyBackend
$ SOINativeQueryObj @b refqt
$ NQOCol @b c
$ NQOCol @b
$ getColumnPathColumn @b c
)
DRRightColumn
)
(Seq.fromList rCols)
pure (RelInfo rn ArrRel (rmColumns common) (RelTargetNativeQuery refqt) True AfterParent, deps)
RUManual (RelManualTableConfig (RelManualTableConfigC {rmtTable = refqt, rmtCommon = common})) -> do
let (lCols, rCols) = unzip $ HashMap.toList $ rmColumns common
let (lCols, rCols) = unzip $ HashMap.toList $ unRelMapping $ rmColumns common
deps =
( fmap
( \c ->
@ -301,7 +309,8 @@ defaultBuildArrayRelationshipInfo source foreignKeys qt (RelDef rn ru _) = case
( SOSourceObj source
$ AB.mkAnyBackend
$ SOITableObj @b qt
$ TOCol @b c
$ TOCol @b
$ getColumnPathColumn @b c
)
DRLeftColumn
)
@ -313,7 +322,8 @@ defaultBuildArrayRelationshipInfo source foreignKeys qt (RelDef rn ru _) = case
( SOSourceObj source
$ AB.mkAnyBackend
$ SOITableObj @b refqt
$ TOCol @b c
$ TOCol @b
$ getColumnPathColumn @b c
)
DRRightColumn
)
@ -332,7 +342,7 @@ mkFkeyRel ::
RelName ->
TableName b ->
TableName b ->
NonEmpty (Column b) ->
NonEmpty (ColumnPath b) ->
HashMap (TableName b) (HashSet (ForeignKey b)) ->
m (RelInfo b, Seq SchemaDependency)
mkFkeyRel relType io source rn sourceTable remoteTable remoteColumns foreignKeys = do
@ -358,17 +368,18 @@ mkFkeyRel relType io source rn sourceTable remoteTable remoteColumns foreignKeys
DRRemoteTable
]
<> ( drUsingColumnDep @b source remoteTable
<$> Seq.fromList (toList remoteColumns)
<$> Seq.fromList (toList $ getColumnPathColumn @b <$> remoteColumns)
)
pure (RelInfo rn relType (reverseMap (NEHashMap.toHashMap colMap)) (RelTargetTable remoteTable) False io, dependencies)
pure (RelInfo rn relType (RelMapping $ reverseMap $ NEHashMap.toHashMap colMap) (RelTargetTable remoteTable) False io, dependencies)
where
reverseMap :: (Hashable y) => HashMap x y -> HashMap y x
reverseMap = HashMap.fromList . fmap swap . HashMap.toList
-- | Try to find a foreign key constraint, identifying a constraint by its set of columns
getRequiredFkey ::
forall m b.
(QErrM m, Backend b) =>
NonEmpty (Column b) ->
NonEmpty (ColumnPath b) ->
[ForeignKey b] ->
m (ForeignKey b)
getRequiredFkey cols fkeys =

View File

@ -36,10 +36,11 @@ import Hasura.Prelude
import Hasura.RQL.Types.Backend
import Hasura.RQL.Types.Common
import Hasura.RQL.Types.Metadata.Backend
import Hasura.RQL.Types.Relationships.Local (RelInfo (riMapping, riTarget), RelTarget (..))
import Hasura.RQL.Types.Relationships.Local (RelInfo (riMapping, riTarget), RelMapping (..), RelTarget (..))
import Hasura.RQL.Types.SchemaCache
import Hasura.RQL.Types.SchemaCache.Build
import Hasura.Table.Cache (ForeignKey, UniqueConstraint, _cName, _fkColumnMapping, _fkConstraint, _fkForeignTable, _ucColumns)
import Witch qualified
-- | Datatype used by Metadata API to represent Request for Suggested Relationships
data SuggestRels b = SuggestRels
@ -102,7 +103,7 @@ instance (Backend b) => HasCodec (Relationship b) where
data Mapping b = Mapping
{ mTable :: TableName b,
mColumns :: [Column b],
mColumns :: [ColumnPath b],
mConstraintName :: Maybe J.Value
}
deriving (Generic)
@ -133,7 +134,7 @@ suggestRelsFK ::
HashMap (TableName b) (TableCoreInfo b) ->
TableName b ->
HashSet (UniqueConstraint b) ->
H.HashSet (TableName b, HashMap (Column b) (Column b)) ->
H.HashSet (TableName b, HashMap (ColumnPath b) (ColumnPath b)) ->
(TableName b -> Bool) ->
ForeignKey b ->
[Relationship b]
@ -145,6 +146,7 @@ suggestRelsFK omitTracked tables name uniqueConstraints tracked predicate foreig
where
toTracked = H.member (relatedTableName, columnRelationships) tracked
fromTracked = H.member (name, invert columnRelationships) trackedBack
toRelationship, fromRelationship :: Relationship b
toRelationship =
Relationship
{ rType = ObjRel,
@ -157,10 +159,10 @@ suggestRelsFK omitTracked tables name uniqueConstraints tracked predicate foreig
rTo = Mapping {mTable = name, mColumns = localColumns, mConstraintName = Just constraintName},
rFrom = Mapping {mTable = relatedTableName, mColumns = relatedColumns, mConstraintName = Nothing}
}
columnRelationships = MapNE.toHashMap (_fkColumnMapping foreignKey)
columnRelationships = MapNE.toHashMap $ _fkColumnMapping foreignKey
localColumns = HashMap.keys columnRelationships
relatedColumns = HashMap.elems columnRelationships
uniqueConstraintColumns = H.map _ucColumns uniqueConstraints
uniqueConstraintColumns = H.map (H.map Witch.from . _ucColumns) uniqueConstraints
relatedTableName = _fkForeignTable foreignKey
relatedTable = HashMap.lookup relatedTableName tables
constraintName = J.toJSON (_cName (_fkConstraint foreignKey))
@ -174,10 +176,10 @@ suggestRelsFK omitTracked tables name uniqueConstraints tracked predicate foreig
-- we're only interested in suggesting table-based relationships for now
getRelationshipsInputs ::
RelInfo b ->
Maybe (TableName b, HashMap (Column b) (Column b))
Maybe (TableName b, HashMap (ColumnPath b) (ColumnPath b))
getRelationshipsInputs ri =
case riTarget ri of
RelTargetTable tn -> Just (tn, riMapping ri)
RelTargetTable tn -> Just (tn, unRelMapping $ riMapping ri)
_ -> Nothing
suggestRelsTable ::

View File

@ -289,7 +289,8 @@ processTablesDiff ::
( MonadError QErr m,
CacheRM m,
MonadWriter MetadataModifier m,
BackendMetadata b
BackendMetadata b,
Column b ~ ColumnPath b
) =>
SourceName ->
TableCache b ->
@ -313,7 +314,8 @@ alterTableInMetadata ::
( MonadError QErr m,
CacheRM m,
MonadWriter MetadataModifier m,
BackendMetadata b
BackendMetadata b,
Column b ~ ColumnPath b
) =>
SourceName ->
TableCoreInfo b ->
@ -387,7 +389,8 @@ alterColumnsInMetadata ::
( MonadError QErr m,
CacheRM m,
MonadWriter MetadataModifier m,
BackendMetadata b
BackendMetadata b,
Column b ~ ColumnPath b
) =>
SourceName ->
[(RawColumnInfo b, RawColumnInfo b)] ->

View File

@ -40,7 +40,9 @@ resolveEnumReferences enumTables =
where
resolveEnumReference :: ForeignKey b -> Maybe (Column b, EnumReference b)
resolveEnumReference foreignKey = do
[(localColumn, foreignColumn)] <- pure $ NEHashMap.toList (_fkColumnMapping @b foreignKey)
[(localColumnPath, foreignColumnPath)] <- pure $ NEHashMap.toList (_fkColumnMapping @b foreignKey)
localColumn <- tryColumnPathToColumn @b localColumnPath
foreignColumn <- tryColumnPathToColumn @b foreignColumnPath
let foreignKeyTableName = _fkForeignTable foreignKey
(primaryKey, tConfig, enumValues) <- HashMap.lookup foreignKeyTableName enumTables
let tableCustomName = _tcCustomName tConfig

View File

@ -933,4 +933,4 @@ recreateSystemMetadata = do
$ RelManualTableConfig
$ RelManualTableConfigC
(QualifiedObject schemaName tableName)
(RelManualCommon (HashMap.fromList columns) Nothing)
(RelManualCommon (RelMapping $ HashMap.fromList columns) Nothing)

View File

@ -162,7 +162,8 @@ renameColumnInMetadata ::
( MonadError QErr m,
CacheRM m,
MonadWriter MetadataModifier m,
BackendMetadata b
BackendMetadata b,
Column b ~ ColumnPath b
) =>
Column b ->
Column b ->
@ -532,7 +533,7 @@ updateColExp qt rf (ColExp fld val) =
-- rename columns in relationship definitions
updateColInRel ::
forall b m.
(CacheRM m, MonadWriter MetadataModifier m, BackendMetadata b) =>
(CacheRM m, MonadWriter MetadataModifier m, BackendMetadata b, Column b ~ ColumnPath b) =>
SourceName ->
TableName b ->
RelName ->
@ -681,7 +682,7 @@ updateTableInRemoteRelationshipRHS source tableName remoteRelationshipName (_, n
.~ toJSON newTableName
updateColInObjRel ::
(Backend b) =>
(Backend b, Column b ~ ColumnPath b) =>
TableName b ->
TableName b ->
RenameCol b ->
@ -694,7 +695,7 @@ updateColInObjRel fromQT toQT rnCol = \case
RUManual $ updateRelManualConfig fromQT toQT rnCol manConfig
updateRelChoice ::
(Backend b) =>
(Backend b, Column b ~ ColumnPath b) =>
TableName b ->
TableName b ->
RenameCol b ->
@ -706,7 +707,7 @@ updateRelChoice fromQT toQT rnCol =
RemoteTable t c -> RemoteTable t (getNewCol rnCol toQT c)
updateColInArrRel ::
(Backend b) =>
(Backend b, Column b ~ ColumnPath b) =>
TableName b ->
TableName b ->
RenameCol b ->
@ -718,8 +719,6 @@ updateColInArrRel fromQT toQT rnCol = \case
in RUFKeyOn $ ArrRelUsingFKeyOn t updCol
RUManual manConfig -> RUManual $ updateRelManualConfig fromQT toQT rnCol manConfig
type ColMap b = HashMap (Column b) (Column b)
getNewCol ::
forall b f.
(Backend b) =>
@ -741,7 +740,7 @@ getNewCol rnCol qt cols =
updateRelManualConfig ::
forall b.
(Backend b) =>
(Backend b, Column b ~ ColumnPath b) =>
TableName b ->
TableName b ->
RenameCol b ->
@ -754,14 +753,14 @@ updateRelManualConfig fromQT toQT rnCol (RelManualNativeQueryConfig (RelManualNa
updateColMap ::
forall b.
(Backend b) =>
(Backend b, Column b ~ ColumnPath b) =>
TableName b ->
TableName b ->
RenameCol b ->
ColMap b ->
ColMap b
RelMapping b ->
RelMapping b
updateColMap fromQT toQT rnCol =
HashMap.fromList . map (modCol fromQT *** modCol toQT) . HashMap.toList
RelMapping . HashMap.fromList . map (modCol fromQT *** modCol toQT) . HashMap.toList . unRelMapping
where
RenameItem qt oCol nCol = rnCol
modCol colQt col = if colQt == qt && col == oCol then nCol else col

View File

@ -286,7 +286,7 @@ convExtRel sqlGen fieldInfoMap relName mAlias selQ sessVarBldr prepValBldr = do
relInfo <-
withPathK "name"
$ askRelType fieldInfoMap relName pgWhenRelErr
let (RelInfo {riType = relTy, riMapping = colMapping, riTarget = relTarget}) = relInfo
let (RelInfo {riType = relTy, riMapping = RelMapping colMapping, riTarget = relTarget}) = relInfo
relTableName <- case relTarget of
RelTargetNativeQuery _ -> error "convExtRel RelTargetNativeQuery"
RelTargetTable tn -> pure tn

View File

@ -18,7 +18,7 @@ import Hasura.RQL.Types.Relationships.Local (Nullable)
data AnnRelationSelectG (b :: BackendType) a = AnnRelationSelectG
{ _aarRelationshipName :: RelName, -- Relationship name
_aarColumnMapping :: HashMap (Column b) (Column b), -- Column of left table to join with
_aarColumnMapping :: HashMap (ColumnPath b) (ColumnPath b), -- Column of left table to join with
_aarNullable :: Nullable, -- is the target object allowed to be missing?
_aarAnnSelect :: a -- Current table. Almost ~ to SQL Select
}

View File

@ -40,6 +40,7 @@ import Hasura.RQL.Types.Session (SessionVariables)
import Hasura.RQL.Types.SourceConfiguration
import Hasura.SQL.Types
import Language.GraphQL.Draft.Syntax qualified as G
import Witch (From)
type SessionVarType b = CollectableType (ScalarType b)
@ -81,6 +82,7 @@ class
( HasSourceConfiguration b,
Representable (BasicOrderType b),
Representable (Column b),
Representable (ColumnPath b),
Representable (ComputedFieldDefinition b),
Representable (ComputedFieldImplicitArguments b),
Representable (ComputedFieldReturn b),
@ -104,14 +106,18 @@ class
Ord (FunctionName b),
Ord (ScalarType b),
Ord (Column b),
Ord (ColumnPath b),
Ord (ComputedFieldReturn b),
Ord (ComputedFieldImplicitArguments b),
Ord (ConstraintName b),
Ord (FunctionArgument b),
Ord (XComputedField b),
Data (TableName b),
From (Column b) (ColumnPath b),
FromJSON (BackendConfig b),
FromJSON (Column b),
FromJSON (ColumnPath b),
FromJSON (ColumnPath b),
FromJSON (ComputedFieldDefinition b),
FromJSON (ConnectionTemplateRequestContext b),
FromJSON (ConstraintName b),
@ -123,17 +129,22 @@ class
FromJSON (ScalarType b),
FromJSON (TableName b),
FromJSONKey (Column b),
FromJSONKey (ColumnPath b),
FromJSONKey (ConstraintName b),
HasCodec (BackendConfig b),
HasCodec (BackendSourceKind b),
HasCodec (Column b),
HasCodec (ColumnPath b),
HasCodec (ComputedFieldDefinition b),
HasCodec (FunctionName b),
HasCodec (FunctionReturnType b),
HasCodec (ScalarType b),
HasCodec (TableName b),
Hashable (Column b),
Hashable (ColumnPath b),
ToJSON (BackendConfig b),
ToJSON (Column b),
ToJSON (ColumnPath b),
ToJSON (ConstraintName b),
ToJSON (ExecutionStatistics b),
ToJSON (FunctionArgument b),
@ -150,6 +161,7 @@ class
ToJSON (HealthCheckTest b),
ToJSON (ResolvedConnectionTemplate b),
ToJSONKey (Column b),
ToJSONKey (ColumnPath b),
ToJSONKey (ConstraintName b),
ToJSONKey (ScalarType b),
ToTxt (Column b),
@ -160,6 +172,7 @@ class
ToErrorValue (Column b),
ToErrorValue (TableName b),
Typeable (Column b),
Typeable (ColumnPath b),
Typeable b,
HasTag b,
Traversable (CountType b),
@ -232,6 +245,9 @@ class
-- Name of a 'column'
type Column b :: Type
-- Path to a column
type ColumnPath b :: Type
type ScalarValue b :: Type
type ScalarType b :: Type
@ -443,6 +459,14 @@ class
(Column b, [RemoteRelSupportedOp RemoteRelSessionVariableORLiteralValue]) ->
m [Text]
-- | Get the top-level column from a ColumnPath
-- For backends that don't support nested objects (i.e. where ColumnPath b = Column b) this will be `id`.
getColumnPathColumn :: ColumnPath b -> Column b
-- | Convert a singleton ColumnPath to a Column
-- Should return Nothing for paths to nested fields
tryColumnPathToColumn :: ColumnPath b -> Maybe (Column b)
backendSupportsNestedObjects :: Either QErr (XNestedObjects b)
default backendSupportsNestedObjects :: (XNestedObjects b ~ XDisable) => Either QErr (XNestedObjects b)
backendSupportsNestedObjects = throw400 InvalidConfiguration "Nested objects not supported"

View File

@ -10,6 +10,7 @@ module Hasura.RQL.Types.Relationships.Local
ObjRelUsingChoice (..),
RelDef (..),
RelTarget (..),
RelMapping (..),
RelInfo (..),
RelManualConfig (..),
RelManualTableConfig (..),
@ -31,6 +32,8 @@ import Autodocodec.Extended (optionalFieldOrIncludedNull', typeableName)
import Control.Lens (makeLenses)
import Data.Aeson.KeyMap qualified as KM
import Data.Aeson.Types
import Data.Bitraversable
import Data.HashMap.Strict qualified as HashMap
import Data.Text qualified as T
import Data.Typeable (Typeable)
import Hasura.NativeQuery.Types (NativeQueryName)
@ -39,6 +42,7 @@ import Hasura.RQL.Types.Backend
import Hasura.RQL.Types.BackendTag (backendPrefix)
import Hasura.RQL.Types.BackendType
import Hasura.RQL.Types.Common
import Witch qualified
data RelDef a = RelDef
{ _rdName :: RelName,
@ -112,7 +116,7 @@ deriving instance (Backend b) => Eq (RelManualNativeQueryConfig b)
deriving instance (Backend b) => Show (RelManualNativeQueryConfig b)
data RelManualCommon (b :: BackendType) = RelManualCommon
{ rmColumns :: HashMap (Column b) (Column b),
{ rmColumns :: RelMapping b,
rmInsertOrder :: Maybe InsertOrder
}
deriving (Generic)
@ -188,7 +192,7 @@ instance (FromJSON a, Backend b) => FromJSON (RelUsing b a) where
data ArrRelUsingFKeyOn (b :: BackendType) = ArrRelUsingFKeyOn
{ arufTable :: TableName b,
arufColumns :: NonEmpty (Column b)
arufColumns :: NonEmpty (ColumnPath b)
}
deriving (Generic)
@ -224,8 +228,8 @@ instance (ToAesonPairs a, Backend b) => ToJSON (WithTable b a) where
object $ ("source" .= sourceName) : ("table" .= tn) : toAesonPairs rel
data ObjRelUsingChoice b
= SameTable (NonEmpty (Column b))
| RemoteTable (TableName b) (NonEmpty (Column b))
= SameTable (NonEmpty (ColumnPath b))
| RemoteTable (TableName b) (NonEmpty (ColumnPath b))
deriving (Generic)
deriving instance (Backend b) => Eq (ObjRelUsingChoice b)
@ -235,10 +239,10 @@ deriving instance (Backend b) => Show (ObjRelUsingChoice b)
instance (Backend b) => HasCodec (ObjRelUsingChoice b) where
codec = dimapCodec dec enc $ disjointEitherCodec sameTableCodec remoteTableCodec
where
sameTableCodec :: AC.JSONCodec (Either (Column b) (NonEmpty (Column b)))
sameTableCodec :: AC.JSONCodec (Either (ColumnPath b) (NonEmpty (ColumnPath b)))
sameTableCodec = disjointEitherCodec codec codec
remoteTableCodec :: AC.JSONCodec (Either (TableName b, Column b) (TableName b, NonEmpty (Column b)))
remoteTableCodec :: AC.JSONCodec (Either (TableName b, ColumnPath b) (TableName b, NonEmpty (ColumnPath b)))
remoteTableCodec =
singleOrMultipleRelColumnsCodec @b
$ backendPrefix @b
@ -262,8 +266,8 @@ singleOrMultipleRelColumnsCodec ::
Text ->
AC.JSONCodec
( Either
(TableName b, Column b)
(TableName b, NonEmpty (Column b))
(TableName b, ColumnPath b)
(TableName b, NonEmpty (ColumnPath b))
)
singleOrMultipleRelColumnsCodec codecName =
disjointEitherCodec
@ -310,7 +314,7 @@ instance (Backend b) => FromJSON (ObjRelUsingChoice b) where
pure $ RemoteTable table cols
val -> SameTable <$> parseColumns val
where
parseColumns :: Value -> Parser (NonEmpty (Column b))
parseColumns :: Value -> Parser (NonEmpty (ColumnPath b))
parseColumns = \case
v@(String _) -> pure <$> parseJSON v
v@(Array _) -> parseJSON v
@ -321,12 +325,12 @@ instance (Backend b) => HasCodec (ArrRelUsingFKeyOn b) where
dimapCodec dec enc
$ singleOrMultipleRelColumnsCodec @b (backendPrefix @b <> "ArrRelUsingFKeyOn")
where
dec :: (Either (TableName b, Column b) (TableName b, NonEmpty (Column b))) -> ArrRelUsingFKeyOn b
dec :: (Either (TableName b, ColumnPath b) (TableName b, NonEmpty (ColumnPath b))) -> ArrRelUsingFKeyOn b
dec = \case
Left (qt, col) -> ArrRelUsingFKeyOn qt (pure col)
Right (qt, cols) -> ArrRelUsingFKeyOn qt cols
enc :: ArrRelUsingFKeyOn b -> (Either (TableName b, Column b) (TableName b, NonEmpty (Column b)))
enc :: ArrRelUsingFKeyOn b -> (Either (TableName b, ColumnPath b) (TableName b, NonEmpty (ColumnPath b)))
enc = \case
ArrRelUsingFKeyOn qt (col :| []) -> Left (qt, col)
ArrRelUsingFKeyOn qt cols -> Right (qt, cols)
@ -352,7 +356,7 @@ instance (Backend b) => FromJSON (ArrRelUsingFKeyOn b) where
pure $ ArrRelUsingFKeyOn table cols
_ -> fail "Expecting object { table, columns }."
where
parseColumns :: Value -> Parser (NonEmpty (Column b))
parseColumns :: Value -> Parser (NonEmpty (ColumnPath b))
parseColumns = \case
v@(String _) -> pure <$> parseJSON v
v@(Array _) -> parseJSON v
@ -391,10 +395,48 @@ instance (Backend b) => ToJSON (RelTarget b) where
---
newtype RelMapping (b :: BackendType) = RelMapping {unRelMapping :: HashMap (ColumnPath b) (ColumnPath b)}
deriving (Generic)
deriving instance (Backend b) => Show (RelMapping b)
deriving instance (Backend b) => Eq (RelMapping b)
deriving instance (Backend b) => Ord (RelMapping b)
deriving via AC.Autodocodec (RelMapping b) instance (Backend b) => FromJSON (RelMapping b)
deriving via AC.Autodocodec (RelMapping b) instance (Backend b) => ToJSON (RelMapping b)
instance (Backend b) => NFData (RelMapping b)
instance (Backend b) => Hashable (RelMapping b)
-- If all keys in the RelMapping have a singleton ColumnPath then we want to
-- want to represent the mapping as a JSON object with the source columns as properties
-- (using `codec @(HashMap (Column b) (ColumnPath b))`).
-- This is required for metadata and API backwards compatibilty.
-- If some of the keys are not singletons then we can't use a JSON object so we use
-- an array of pairs instead, as provided by `codec @(HashMap (ColumnPath b) (ColumnPath b))`
instance (Backend b) => HasCodec (RelMapping b) where
codec =
AC.matchChoiceCodec
(AC.dimapCodec RelMapping unRelMapping $ codec @(HashMap (ColumnPath b) (ColumnPath b)))
(AC.dimapCodec toRelMapping id $ codec @(HashMap (Column b) (ColumnPath b)))
\m -> maybeToEither m (tryFromRelMapping m)
where
toRelMapping :: HashMap (Column b) (ColumnPath b) -> RelMapping b
toRelMapping = RelMapping . HashMap.mapKeys Witch.from
tryFromRelMapping :: RelMapping b -> Maybe (HashMap (Column b) (ColumnPath b))
tryFromRelMapping = fmap HashMap.fromList . traverse (bitraverse (tryColumnPathToColumn @b) pure) . HashMap.toList . unRelMapping
---
data RelInfo (b :: BackendType) = RelInfo
{ riName :: RelName,
riType :: RelType,
riMapping :: HashMap (Column b) (Column b),
riMapping :: RelMapping b,
riTarget :: RelTarget b,
riIsManual :: Bool,
riInsertOrder :: InsertOrder

View File

@ -38,6 +38,7 @@ import Data.Text (Text)
import GHC.Generics (Generic)
import Hasura.LogicalModel.Metadata
import Hasura.RQL.Types.Backend (Backend (..), ConstraintName)
import Hasura.RQL.Types.Relationships.Local (RelMapping (..))
import Hasura.RQL.Types.Source.Column (SourceColumnInfo)
import Hasura.RQL.Types.Source.TableType
import Prelude
@ -102,7 +103,7 @@ instance (Backend b) => HasCodec (SourceForeignKeys b) where
data SourceConstraint b = SourceConstraint
{ _scForeignTable :: TableName b,
_scColumnMapping :: HashMap (Column b) (Column b)
_scColumnMapping :: RelMapping b
}
deriving stock (Generic)
deriving anyclass (Hashable)

View File

@ -984,7 +984,7 @@ instance (Backend b) => FromJSON (UniqueConstraint b) where
data ForeignKey (b :: BackendType) = ForeignKey
{ _fkConstraint :: Constraint b,
_fkForeignTable :: TableName b,
_fkColumnMapping :: NEHashMap (Column b) (Column b)
_fkColumnMapping :: NEHashMap (ColumnPath b) (ColumnPath b)
}
deriving (Generic)

View File

@ -1,7 +1,7 @@
{-# LANGUAGE OverloadedLists #-}
{-# LANGUAGE QuasiQuotes #-}
module Hasura.Backends.DataConnector.API.V0.ColumnSpec (spec, genColumnName, genColumnType, genColumnInfo, genColumnValueGenerationStrategy) where
module Hasura.Backends.DataConnector.API.V0.ColumnSpec (spec, genColumnName, genColumnSelector, genColumnType, genColumnInfo, genColumnValueGenerationStrategy) where
import Data.Aeson.QQ.Simple (aesonQQ)
import Hasura.Backends.DataConnector.API.V0
@ -19,6 +19,12 @@ spec = do
describe "ColumnName" $ do
testToFromJSONToSchema (ColumnName "my_column_name") [aesonQQ|"my_column_name"|]
jsonOpenApiProperties genColumnName
describe "ColumnSelector" $ do
describe "single column selector"
$ testToFromJSONToSchema (ColumnSelectorColumn $ ColumnName "foo") [aesonQQ|"foo"|]
describe "nested path selector"
$ testToFromJSONToSchema (ColumnSelectorPath [ColumnName "foo", ColumnName "bar"]) [aesonQQ|["foo","bar"]|]
jsonOpenApiProperties genColumnSelector
describe "ColumnInfo" $ do
describe "minimal"
$ testFromJSON
@ -56,6 +62,13 @@ spec = do
genColumnName :: (MonadGen m) => m ColumnName
genColumnName = ColumnName <$> genArbitraryAlphaNumText defaultRange
genColumnSelector :: (MonadGen m) => m ColumnSelector
genColumnSelector =
Gen.choice
[ ColumnSelectorPath <$> Gen.nonEmpty defaultRange genColumnName,
ColumnSelectorColumn <$> genColumnName
]
genColumnType :: Gen ColumnType
genColumnType =
Gen.choice

View File

@ -10,14 +10,13 @@ module Hasura.Backends.DataConnector.API.V0.ExpressionSpec
genExpression,
genRedactionExpressionName,
genTargetRedactionExpressions,
genColumnSelector,
)
where
import Data.Aeson
import Data.Aeson.QQ.Simple (aesonQQ)
import Hasura.Backends.DataConnector.API.V0
import Hasura.Backends.DataConnector.API.V0.ColumnSpec (genColumnName)
import Hasura.Backends.DataConnector.API.V0.ColumnSpec (genColumnSelector)
import Hasura.Backends.DataConnector.API.V0.RelationshipsSpec (genRelationshipName)
import Hasura.Backends.DataConnector.API.V0.ScalarSpec (genScalarType, genScalarValue)
import Hasura.Backends.DataConnector.API.V0.TableSpec (genTableName)
@ -84,13 +83,6 @@ spec = do
$ testToFromJSONToSchema CurrentTable [aesonQQ|[]|]
jsonOpenApiProperties genColumnPath
describe "ColumnSelector" $ do
describe "single column selector"
$ testToFromJSONToSchema (ColumnSelector [ColumnName "foo"]) [aesonQQ|"foo"|]
describe "nested path selector"
$ testToFromJSONToSchema (ColumnSelector [ColumnName "foo", ColumnName "bar"]) [aesonQQ|["foo","bar"]|]
jsonOpenApiProperties genColumnSelector
describe "ComparisonValue" $ do
describe "AnotherColumnComparison"
$ testToFromJSONToSchema
@ -290,10 +282,6 @@ genColumnPath :: (MonadGen m) => m ColumnPath
genColumnPath =
Gen.element [CurrentTable, QueryTable]
genColumnSelector :: (MonadGen m) => m ColumnSelector
genColumnSelector =
ColumnSelector <$> Gen.nonEmpty defaultRange genColumnName
genComparisonValue :: (MonadGen m, GenBase m ~ Identity) => m ComparisonValue
genComparisonValue =
Gen.choice

View File

@ -12,7 +12,8 @@ import Data.Aeson.QQ.Simple (aesonQQ)
import Data.HashMap.Strict qualified as HashMap
import Hasura.Backends.DataConnector.API.V0
import Hasura.Backends.DataConnector.API.V0.AggregateSpec (genSingleColumnAggregate)
import Hasura.Backends.DataConnector.API.V0.ExpressionSpec (genColumnSelector, genExpression, genRedactionExpressionName)
import Hasura.Backends.DataConnector.API.V0.ColumnSpec (genColumnSelector)
import Hasura.Backends.DataConnector.API.V0.ExpressionSpec (genExpression, genRedactionExpressionName)
import Hasura.Backends.DataConnector.API.V0.RelationshipsSpec (genRelationshipName)
import Hasura.Generator.Common (defaultRange)
import Hasura.Prelude

View File

@ -12,7 +12,7 @@ where
import Data.Aeson.QQ.Simple (aesonQQ)
import Data.HashMap.Strict qualified as HashMap
import Hasura.Backends.DataConnector.API.V0
import Hasura.Backends.DataConnector.API.V0.ColumnSpec (genColumnName)
import Hasura.Backends.DataConnector.API.V0.ColumnSpec (genColumnSelector)
import Hasura.Backends.DataConnector.API.V0.TableSpec (genTableName, genTableTarget)
import Hasura.Generator.Common (defaultRange, genArbitraryAlphaNumText)
import Hasura.Prelude
@ -38,7 +38,7 @@ spec = do
Relationship
{ _rTarget = TTable (TargetTable (TableName ["target_table_name"])),
_rRelationshipType = ObjectRelationship,
_rColumnMapping = [(ColumnName "outer_column", ColumnName "inner_column")]
_rColumnMapping = ColumnPathMapping [(mkColumnSelector $ ColumnName "outer_column", mkColumnSelector $ ColumnName "inner_column")]
}
testToFromJSONToSchema
relationship
@ -51,18 +51,20 @@ spec = do
}
|]
jsonOpenApiProperties genRelationship
describe "ColumnPathMapping"
$ jsonOpenApiProperties genColumnPathMapping
describe "TableRelationships" $ do
let relationshipA =
Relationship
{ _rTarget = TTable (TargetTable (TableName ["target_table_name_a"])),
_rRelationshipType = ObjectRelationship,
_rColumnMapping = [(ColumnName "outer_column_a", ColumnName "inner_column_a")]
_rColumnMapping = ColumnPathMapping [(mkColumnSelector $ ColumnName "outer_column_a", mkColumnSelector $ ColumnName "inner_column_a")]
}
let relationshipB =
Relationship
{ _rTarget = TTable (TargetTable (TableName ["target_table_name_b"])),
_rRelationshipType = ArrayRelationship,
_rColumnMapping = [(ColumnName "outer_column_b", ColumnName "inner_column_b")]
_rColumnMapping = ColumnPathMapping [(mkColumnSelector $ ColumnName "outer_column_b", mkColumnSelector $ ColumnName "inner_column_b")]
}
let tableRelationships =
TableRelationships
@ -109,7 +111,7 @@ genRelationship =
Relationship
<$> genTableTarget
<*> genRelationshipType
<*> (HashMap.fromList <$> Gen.list defaultRange ((,) <$> genColumnName <*> genColumnName))
<*> genColumnPathMapping
genRelationships :: Gen Relationships
genRelationships = (RTable <$> genTableRelationships) <|> (RFunction <$> genFunctionRelationships)
@ -128,3 +130,6 @@ genFunctionRelationships =
genFunctionName :: (MonadGen m) => m FunctionName
genFunctionName = FunctionName <$> Gen.nonEmpty (linear 1 3) (genArbitraryAlphaNumText defaultRange)
genColumnPathMapping :: (MonadGen m) => m ColumnPathMapping
genColumnPathMapping = ColumnPathMapping . HashMap.fromList <$> Gen.list defaultRange ((,) <$> genColumnSelector <*> genColumnSelector)

View File

@ -6,7 +6,7 @@ module Hasura.Backends.DataConnector.API.V0.TableSpec (spec, genTableName, genTa
import Data.Aeson.QQ.Simple (aesonQQ)
import Data.HashMap.Strict qualified as HashMap
import Hasura.Backends.DataConnector.API.V0
import Hasura.Backends.DataConnector.API.V0.ColumnSpec (genColumnInfo, genColumnName)
import Hasura.Backends.DataConnector.API.V0.ColumnSpec (genColumnInfo, genColumnName, genColumnSelector)
import Hasura.Generator.Common
import Hasura.Prelude
import Hedgehog
@ -60,7 +60,14 @@ spec = do
Table
[ColumnInfo (ColumnName "id") (ColumnTypeScalar $ ScalarType "string") False Nothing False False Nothing]
(Just $ ColumnName "id" :| [])
(ForeignKeys $ HashMap.singleton (ConstraintName "Artist") (Constraint (TableName ["artist_table"]) (HashMap.singleton (ColumnName "ArtistId") (ColumnName "ArtistId"))))
( ForeignKeys
$ HashMap.singleton
(ConstraintName "Artist")
( Constraint
(TableName ["artist_table"])
(ColumnPathMapping $ HashMap.singleton (mkColumnSelector $ ColumnName "ArtistId") (mkColumnSelector $ ColumnName "ArtistId"))
)
)
(Just "my description")
False
False
@ -101,7 +108,7 @@ genConstraintName = ConstraintName <$> genArbitraryAlphaNumText defaultRange
genConstraint :: (MonadGen m) => m Constraint
genConstraint =
let mapping = genHashMap genColumnName genColumnName defaultRange
let mapping = ColumnPathMapping <$> genHashMap genColumnSelector genColumnSelector defaultRange
in Constraint <$> genTableName <*> mapping
genTableType :: (MonadGen m) => m TableType

View File

@ -47,6 +47,7 @@ genSelectArgsG genA = do
Gen.maybe
$ genAnnBoolExp
( genAnnBoolExpFld
genColumn
genColumn
genTableName
genScalarType
@ -66,6 +67,7 @@ genSelectArgsG genA = do
genBasicOrderType
genNullsOrderType
( genAnnotatedOrderByElement @_ @('Postgres 'Vanilla)
genColumn
genColumn
genTableName
genScalarType
@ -89,6 +91,7 @@ genSelectArgsG genA = do
$ AnnDistinctColumn
<$> genColumn
<*> genAnnRedactionExp
genColumn
genColumn
genTableName
genScalarType

View File

@ -24,7 +24,7 @@ import Hedgehog.Gen qualified as Gen
genTablePermG :: (MonadGen m) => m a -> m (TablePermG ('Postgres 'Vanilla) a)
genTablePermG genA = do
let genV = genAnnBoolExpFld @_ @('Postgres 'Vanilla) genColumn genTableName genScalarType genFunctionName genXComputedField (genBooleanOperators genA) (genFunctionArgumentExp genA) genA
let genV = genAnnBoolExpFld @_ @('Postgres 'Vanilla) genColumn genColumn genTableName genScalarType genFunctionName genXComputedField (genBooleanOperators genA) (genFunctionArgumentExp genA) genA
gBoolExp <- genAnnBoolExp @_ @_ @('Postgres 'Vanilla) genV genTableName
limit <- Gen.maybe (Gen.integral defaultRange)
pure $ TablePerm gBoolExp limit

View File

@ -29,7 +29,7 @@ import Hasura.RQL.Types.BackendType (BackendSourceKind (PostgresVanillaKind), Ba
import Hasura.RQL.Types.Column (ColumnType (ColumnScalar), ColumnValue (..))
import Hasura.RQL.Types.Common (InsertOrder (..), RelName (..), RelType (..), SourceName (..))
import Hasura.RQL.Types.NamingCase (NamingCase (..))
import Hasura.RQL.Types.Relationships.Local (RelInfo (..), RelTarget (..))
import Hasura.RQL.Types.Relationships.Local (RelInfo (..), RelMapping (..), RelTarget (..))
import Hasura.RQL.Types.Schema.Options qualified as Options
import Hasura.RQL.Types.Source (DBObjectsIntrospection (..), SourceInfo (..))
import Hasura.RQL.Types.SourceCustomization (ResolvedSourceCustomization (..))
@ -307,7 +307,7 @@ spec = do
RelInfo
{ riName = RelName [nonEmptyTextQQ|tracks|],
riType = ArrRel,
riMapping = HashMap.fromList [("id", "album_id")],
riMapping = RelMapping $ HashMap.fromList [("id", "album_id")],
riTarget = RelTargetTable (mkTable "track"),
riIsManual = False,
riInsertOrder = AfterParent

View File

@ -62,7 +62,9 @@ genAnnRedactionExp ::
(MonadGen m) =>
(Hashable (ScalarType b)) =>
(Hashable (Column b)) =>
(Hashable (ColumnPath b)) =>
m (Column b) ->
m (ColumnPath b) ->
m (TableName b) ->
m (ScalarType b) ->
m (FunctionName b) ->
@ -73,6 +75,7 @@ genAnnRedactionExp ::
m (AnnRedactionExp b a)
genAnnRedactionExp
genColumn
genColumnPath
genTableName
genScalarType
genFunctionName
@ -87,6 +90,7 @@ genAnnRedactionExp
<$> genAnnBoolExp
( genAnnBoolExpFld
genColumn
genColumnPath
genTableName
genScalarType
genFunctionName
@ -129,7 +133,9 @@ genAnnBoolExpFld ::
(MonadGen m) =>
(Hashable (ScalarType b)) =>
(Hashable (Column b)) =>
(Hashable (ColumnPath b)) =>
m (Column b) ->
m (ColumnPath b) ->
m (TableName b) ->
m (ScalarType b) ->
m (FunctionName b) ->
@ -140,6 +146,7 @@ genAnnBoolExpFld ::
m (AnnBoolExpFld b a)
genAnnBoolExpFld
genColumn
genColumnPath
genTableName
genScalarType
genFunctionName
@ -157,6 +164,7 @@ genAnnBoolExpFld
genScalarType
<*> genAnnRedactionExp
genColumn
genColumnPath
genTableName
genScalarType
genFunctionName
@ -175,11 +183,12 @@ genAnnBoolExpFld
)
relationship =
AVRelationship
<$> genRelInfo genTableName genColumn
<$> genRelInfo genTableName genColumnPath
<*> ( RelationshipFilters
<$> genAnnBoolExp
( genAnnBoolExpFld
genColumn
genColumnPath
genTableName
genScalarType
genFunctionName
@ -192,6 +201,7 @@ genAnnBoolExpFld
<*> genAnnBoolExp
( genAnnBoolExpFld
genColumn
genColumnPath
genTableName
genScalarType
genFunctionName
@ -207,6 +217,7 @@ genAnnBoolExpFld
<$> genAnnComputedFieldBolExp
genTableName
genColumn
genColumnPath
genScalarType
genBooleanOperators
genXComputedField
@ -216,15 +227,15 @@ genAnnBoolExpFld
genRelInfo ::
(MonadGen m) =>
(Hashable (Column b)) =>
(Hashable (ColumnPath b)) =>
m (TableName b) ->
m (Column b) ->
m (ColumnPath b) ->
m (RelInfo b)
genRelInfo genTableName genColumn =
RelInfo
<$> genRelName
<*> genRelType
<*> genHashMap genColumn genColumn defaultRange
<*> (RelMapping <$> genHashMap genColumn genColumn defaultRange)
<*> genRelTarget genTableName
<*> bool_
<*> genInsertOrder
@ -252,8 +263,10 @@ genAnnComputedFieldBolExp ::
(MonadGen m) =>
(Hashable (ScalarType b)) =>
(Hashable (Column b)) =>
(Hashable (ColumnPath b)) =>
m (TableName b) ->
m (Column b) ->
m (ColumnPath b) ->
m (ScalarType b) ->
m (BooleanOperators b a) ->
m (XComputedField b) ->
@ -264,6 +277,7 @@ genAnnComputedFieldBolExp ::
genAnnComputedFieldBolExp
genTableName
genColumn
genColumnPath
genScalarType
genBooleanOperators
genXComputedField
@ -278,6 +292,7 @@ genAnnComputedFieldBolExp
<*> genComputedFieldBoolExp
genTableName
genColumn
genColumnPath
genScalarType
genFunctionName
genXComputedField
@ -289,8 +304,10 @@ genComputedFieldBoolExp ::
(MonadGen m) =>
(Hashable (ScalarType b)) =>
(Hashable (Column b)) =>
(Hashable (ColumnPath b)) =>
m (TableName b) ->
m (Column b) ->
m (ColumnPath b) ->
m (ScalarType b) ->
m (FunctionName b) ->
m (XComputedField b) ->
@ -301,6 +318,7 @@ genComputedFieldBoolExp ::
genComputedFieldBoolExp
genTableName
genColumn
genColumnPath
genScalarType
genFunctionName
genXComputedField
@ -311,6 +329,7 @@ genComputedFieldBoolExp
[ CFBEScalar
<$> genAnnRedactionExp
genColumn
genColumnPath
genTableName
genScalarType
genFunctionName
@ -332,6 +351,7 @@ genComputedFieldBoolExp
<*> genAnnBoolExp
( genAnnBoolExpFld
genColumn
genColumnPath
genTableName
genScalarType
genFunctionName
@ -492,7 +512,9 @@ genAnnotatedOrderByElement ::
(MonadGen m) =>
(Hashable (ScalarType b)) =>
(Hashable (Column b)) =>
(Hashable (ColumnPath b)) =>
m (Column b) ->
m (ColumnPath b) ->
m (TableName b) ->
m (ScalarType b) ->
m (FunctionName b) ->
@ -503,6 +525,7 @@ genAnnotatedOrderByElement ::
m (AnnotatedOrderByElement b a)
genAnnotatedOrderByElement
genColumn
genColumnPath
genTableName
genScalarType
genFunctionName
@ -525,6 +548,7 @@ genAnnotatedOrderByElement
genScalarType
<*> genAnnRedactionExp
genColumn
genColumnPath
genTableName
genScalarType
genFunctionName
@ -534,10 +558,11 @@ genAnnotatedOrderByElement
genA
objectRelation =
AOCObjectRelation
<$> genRelInfo genTableName genColumn
<$> genRelInfo genTableName genColumnPath
<*> genAnnBoolExp
( genAnnBoolExpFld
genColumn
genColumnPath
genTableName
genScalarType
genFunctionName
@ -549,6 +574,7 @@ genAnnotatedOrderByElement
genTableName
<*> genAnnotatedOrderByElement
genColumn
genColumnPath
genTableName
genScalarType
genFunctionName
@ -558,10 +584,11 @@ genAnnotatedOrderByElement
genA
arrayAggregation =
AOCArrayAggregation
<$> genRelInfo genTableName genColumn
<$> genRelInfo genTableName genColumnPath
<*> genAnnBoolExp
( genAnnBoolExpFld
genColumn
genColumnPath
genTableName
genScalarType
genFunctionName
@ -573,6 +600,7 @@ genAnnotatedOrderByElement
genTableName
<*> genAnnotatedAggregateOrderBy
genColumn
genColumnPath
genTableName
genScalarType
genFunctionName
@ -584,6 +612,7 @@ genAnnotatedOrderByElement
AOCComputedField
<$> genComputedFieldOrderBy
genColumn
genColumnPath
genScalarType
genTableName
genFunctionName
@ -596,7 +625,9 @@ genAnnotatedAggregateOrderBy ::
(MonadGen m) =>
(Hashable (ScalarType b)) =>
(Hashable (Column b)) =>
(Hashable (ColumnPath b)) =>
m (Column b) ->
m (ColumnPath b) ->
m (TableName b) ->
m (ScalarType b) ->
m (FunctionName b) ->
@ -607,6 +638,7 @@ genAnnotatedAggregateOrderBy ::
m (AnnotatedAggregateOrderBy b a)
genAnnotatedAggregateOrderBy
genColumn
genColumnPath
genTableName
genScalarType
genFunctionName
@ -626,6 +658,7 @@ genAnnotatedAggregateOrderBy
genScalarType
<*> genAnnRedactionExp
genColumn
genColumnPath
genTableName
genScalarType
genFunctionName
@ -640,7 +673,9 @@ genComputedFieldOrderBy ::
(MonadGen m) =>
(Hashable (ScalarType b)) =>
(Hashable (Column b)) =>
(Hashable (ColumnPath b)) =>
m (Column b) ->
m (ColumnPath b) ->
m (ScalarType b) ->
m (TableName b) ->
m (FunctionName b) ->
@ -651,6 +686,7 @@ genComputedFieldOrderBy ::
m (ComputedFieldOrderBy b a)
genComputedFieldOrderBy
genColumn
genColumnPath
genScalarType
genTableName
genFunctionName
@ -665,6 +701,7 @@ genComputedFieldOrderBy
<*> genFunctionArgsExpG genFunctionArgumentExp
<*> genComputedFieldOrderByElement
genColumn
genColumnPath
genScalarType
genTableName
genFunctionName
@ -677,7 +714,9 @@ genComputedFieldOrderByElement ::
(MonadGen m) =>
(Hashable (ScalarType b)) =>
(Hashable (Column b)) =>
(Hashable (ColumnPath b)) =>
m (Column b) ->
m (ColumnPath b) ->
m (ScalarType b) ->
m (TableName b) ->
m (FunctionName b) ->
@ -688,6 +727,7 @@ genComputedFieldOrderByElement ::
m (ComputedFieldOrderByElement b a)
genComputedFieldOrderByElement
genColumn
genColumnPath
genScalarType
genTableName
genFunctionName
@ -700,6 +740,7 @@ genComputedFieldOrderByElement
<$> genScalarType
<*> genAnnRedactionExp
genColumn
genColumnPath
genTableName
genScalarType
genFunctionName
@ -712,6 +753,7 @@ genComputedFieldOrderByElement
<*> genAnnBoolExp
( genAnnBoolExpFld
genColumn
genColumnPath
genTableName
genScalarType
genFunctionName
@ -723,6 +765,7 @@ genComputedFieldOrderByElement
genTableName
<*> genAnnotatedAggregateOrderBy
genColumn
genColumnPath
genTableName
genScalarType
genFunctionName