mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-15 09:22:43 +03:00
Generate TypeScript types for the Data Connector reference agent from the OpenAPI schema
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/4855 GitOrigin-RevId: 4cc09d6706e67c69fbbedef72ff816365b9f7b4e
This commit is contained in:
parent
4b2ca2ea63
commit
59ffce9ac1
@ -32,8 +32,8 @@ constraints: any.Cabal ==3.2.1.0,
|
||||
any.attoparsec-iso8601 ==1.0.2.1,
|
||||
any.authenticate-oauth ==1.7,
|
||||
any.auto-update ==0.1.6,
|
||||
any.autodocodec ==0.1.0.0,
|
||||
any.autodocodec-openapi3 ==0.2.0.0,
|
||||
any.autodocodec ==0.1.0.1,
|
||||
any.autodocodec-openapi3 ==0.2.1.0,
|
||||
any.barbies ==2.0.3.1,
|
||||
any.base ==4.14.3.0,
|
||||
any.base-compat ==0.11.2,
|
||||
@ -352,4 +352,4 @@ constraints: any.Cabal ==3.2.1.0,
|
||||
any.xml-types ==0.3.8,
|
||||
any.yaml ==0.11.7.0,
|
||||
any.zlib ==0.6.2.3,
|
||||
index-state: hackage.haskell.org 2022-06-13T15:16:34Z
|
||||
index-state: hackage.haskell.org 2022-06-20T06:51:52Z
|
||||
|
@ -210,7 +210,7 @@ Notice that the names of tables and columns are used in the metadata document to
|
||||
|
||||
#### Type definitions
|
||||
|
||||
The `SchemaResponse` TypeScript type from [the reference implementation](./reference/src/types/schema.ts) describes the valid response body for the `GET /schema` endpoint.
|
||||
The `SchemaResponse` TypeScript type from [the reference implementation](./reference/src/types/index.ts) describes the valid response body for the `GET /schema` endpoint.
|
||||
|
||||
### Responding to queries
|
||||
|
||||
@ -672,4 +672,4 @@ The key point of interest here is in the `where` field where we are comparing be
|
||||
|
||||
#### Type Definitions
|
||||
|
||||
The `QueryRequest` TypeScript type in the [reference implementation](./reference/src/types/query.ts) describes the valid request body payloads which may be passed to the `POST /query` endpoint. The response body structure is captured by the `QueryResponse` type.
|
||||
The `QueryRequest` TypeScript type in the [reference implementation](./reference/src/types/index.ts) describes the valid request body payloads which may be passed to the `POST /query` endpoint. The response body structure is captured by the `QueryResponse` type.
|
||||
|
1018
dc-agents/reference/package-lock.json
generated
1018
dc-agents/reference/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -18,12 +18,12 @@
|
||||
"typecheck": "tsc --noEmit",
|
||||
"start": "ts-node ./src/index.ts",
|
||||
"start-no-typecheck": "ts-node --transpileOnly ./src/index.ts",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"generate-types": "./scripts/generate-types.sh"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fastify/cors": "^7.0.0",
|
||||
"fastify": "^3.29.0",
|
||||
"openapi3-ts": "^2.0.2",
|
||||
"pino-pretty": "^8.0.0",
|
||||
"xml2js": "^0.4.23"
|
||||
},
|
||||
@ -31,6 +31,7 @@
|
||||
"@tsconfig/node16": "^1.0.2",
|
||||
"@types/node": "^16.11.38",
|
||||
"@types/xml2js": "^0.4.11",
|
||||
"openapi-typescript-codegen": "^0.23.0",
|
||||
"ts-node": "^10.8.1",
|
||||
"typescript": "^4.7.3"
|
||||
}
|
||||
|
21
dc-agents/reference/scripts/generate-types.sh
Executable file
21
dc-agents/reference/scripts/generate-types.sh
Executable file
@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
PROJECT_ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." >/dev/null 2>&1 && pwd )" # ... https://stackoverflow.com/a/246128/176841
|
||||
cd "$PROJECT_ROOT"
|
||||
|
||||
TYPES_DIR="./src/types"
|
||||
SCHEMA_FILE="$TYPES_DIR/agent.openapi.json"
|
||||
|
||||
mkdir -p $TYPES_DIR
|
||||
|
||||
if [ ! -f $SCHEMA_FILE ] ; then
|
||||
echo "$SCHEMA_FILE does not exist, re-generating it using the agent test suite"
|
||||
cabal run test:tests-dc-api -- export-openapi-spec | tail -n 1 | jq > $SCHEMA_FILE
|
||||
fi
|
||||
|
||||
echo "Deleting existing generated model..."
|
||||
rm -rf "$TYPES_DIR/models"
|
||||
rm -f "$TYPES_DIR/index.ts"
|
||||
echo "Generating model from $SCHEMA_FILE..."
|
||||
openapi --useUnionTypes --input $SCHEMA_FILE --output $TYPES_DIR --exportServices false --exportCore false --indent 2
|
@ -1,17 +1,7 @@
|
||||
import { ConfigSchemaResponse, configSchema } from "./config"
|
||||
|
||||
export type Relationships = {}
|
||||
|
||||
export type Capabilities = {
|
||||
relationships: Relationships
|
||||
}
|
||||
|
||||
export type CapabilitiesResponse = {
|
||||
capabilities: Capabilities,
|
||||
configSchemas: ConfigSchemaResponse,
|
||||
}
|
||||
import { configSchema } from "./config"
|
||||
import { CapabilitiesResponse } from "./types"
|
||||
|
||||
export const capabilitiesResponse: CapabilitiesResponse = {
|
||||
capabilities: { relationships: {}},
|
||||
capabilities: { relationships: {} },
|
||||
configSchemas: configSchema
|
||||
}
|
||||
|
@ -1,15 +1,10 @@
|
||||
import { FastifyRequest } from "fastify"
|
||||
import { SchemaObject } from "openapi3-ts"
|
||||
import { ConfigSchemaResponse } from "./types"
|
||||
|
||||
export type Config = {
|
||||
tables: String[] | null
|
||||
}
|
||||
|
||||
export type ConfigSchemaResponse = {
|
||||
configSchema: SchemaObject,
|
||||
otherSchemas: { [schemaName: string]: SchemaObject },
|
||||
}
|
||||
|
||||
export const getConfig = (request: FastifyRequest): Config => {
|
||||
const configHeader = request.headers["x-hasura-dataconnector-config"];
|
||||
const rawConfigJson = Array.isArray(configHeader) ? configHeader[0] : configHeader ?? "{}";
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { SchemaResponse, ScalarType } from "../types/schema"
|
||||
import { SchemaResponse } from "../types"
|
||||
import { Config } from "../config";
|
||||
import xml2js from "xml2js"
|
||||
import fs from "fs"
|
||||
@ -43,13 +43,13 @@ const schema: SchemaResponse = {
|
||||
columns: [
|
||||
{
|
||||
name: "ArtistId",
|
||||
type: ScalarType.Number,
|
||||
type: "number",
|
||||
nullable: false,
|
||||
description: "Artist primary key identifier"
|
||||
},
|
||||
{
|
||||
name: "Name",
|
||||
type: ScalarType.String,
|
||||
type: "string",
|
||||
nullable: true,
|
||||
description: "The name of the artist"
|
||||
}
|
||||
@ -62,19 +62,19 @@ const schema: SchemaResponse = {
|
||||
columns: [
|
||||
{
|
||||
name: "AlbumId",
|
||||
type: ScalarType.Number,
|
||||
type: "number",
|
||||
nullable: false,
|
||||
description: "Album primary key identifier"
|
||||
},
|
||||
{
|
||||
name: "Title",
|
||||
type: ScalarType.String,
|
||||
type: "string",
|
||||
nullable: false,
|
||||
description: "The title of the album"
|
||||
},
|
||||
{
|
||||
name: "ArtistId",
|
||||
type: ScalarType.Number,
|
||||
type: "number",
|
||||
nullable: false,
|
||||
description: "The ID of the artist that created this album"
|
||||
}
|
||||
@ -87,79 +87,79 @@ const schema: SchemaResponse = {
|
||||
columns: [
|
||||
{
|
||||
name: "CustomerId",
|
||||
type: ScalarType.Number,
|
||||
type: "number",
|
||||
nullable: false,
|
||||
description: "Customer primary key identifier"
|
||||
},
|
||||
{
|
||||
name: "FirstName",
|
||||
type: ScalarType.String,
|
||||
type: "string",
|
||||
nullable: false,
|
||||
description: "The customer's first name"
|
||||
},
|
||||
{
|
||||
name: "LastName",
|
||||
type: ScalarType.String,
|
||||
type: "string",
|
||||
nullable: false,
|
||||
description: "The customer's last name"
|
||||
},
|
||||
{
|
||||
name: "Company",
|
||||
type: ScalarType.String,
|
||||
type: "string",
|
||||
nullable: true,
|
||||
description: "The customer's company name"
|
||||
},
|
||||
{
|
||||
name: "Address",
|
||||
type: ScalarType.String,
|
||||
type: "string",
|
||||
nullable: true,
|
||||
description: "The customer's address line (street number, street)"
|
||||
},
|
||||
{
|
||||
name: "City",
|
||||
type: ScalarType.String,
|
||||
type: "string",
|
||||
nullable: true,
|
||||
description: "The customer's address city"
|
||||
},
|
||||
{
|
||||
name: "State",
|
||||
type: ScalarType.String,
|
||||
type: "string",
|
||||
nullable: true,
|
||||
description: "The customer's address state"
|
||||
},
|
||||
{
|
||||
name: "Country",
|
||||
type: ScalarType.String,
|
||||
type: "string",
|
||||
nullable: true,
|
||||
description: "The customer's address country"
|
||||
},
|
||||
{
|
||||
name: "PostalCode",
|
||||
type: ScalarType.String,
|
||||
type: "string",
|
||||
nullable: true,
|
||||
description: "The customer's address postal code"
|
||||
},
|
||||
{
|
||||
name: "Phone",
|
||||
type: ScalarType.String,
|
||||
type: "string",
|
||||
nullable: true,
|
||||
description: "The customer's phone number"
|
||||
},
|
||||
{
|
||||
name: "Fax",
|
||||
type: ScalarType.String,
|
||||
type: "string",
|
||||
nullable: true,
|
||||
description: "The customer's fax number"
|
||||
},
|
||||
{
|
||||
name: "Email",
|
||||
type: ScalarType.String,
|
||||
type: "string",
|
||||
nullable: false,
|
||||
description: "The customer's email address"
|
||||
},
|
||||
{
|
||||
name: "SupportRepId",
|
||||
type: ScalarType.Number,
|
||||
type: "number",
|
||||
nullable: true,
|
||||
description: "The ID of the Employee who is this customer's support representative"
|
||||
}
|
||||
@ -172,85 +172,85 @@ const schema: SchemaResponse = {
|
||||
columns: [
|
||||
{
|
||||
name: "EmployeeId",
|
||||
type: ScalarType.Number,
|
||||
type: "number",
|
||||
nullable: false,
|
||||
description: "Employee primary key identifier"
|
||||
},
|
||||
{
|
||||
name: "FirstName",
|
||||
type: ScalarType.String,
|
||||
type: "string",
|
||||
nullable: false,
|
||||
description: "The employee's first name"
|
||||
},
|
||||
{
|
||||
name: "LastName",
|
||||
type: ScalarType.String,
|
||||
type: "string",
|
||||
nullable: false,
|
||||
description: "The employee's last name"
|
||||
},
|
||||
{
|
||||
name: "Title",
|
||||
type: ScalarType.String,
|
||||
type: "string",
|
||||
nullable: true,
|
||||
description: "The employee's job title"
|
||||
},
|
||||
{
|
||||
name: "BirthDate",
|
||||
type: ScalarType.String, // Ought to be DateTime but we don't have a type for this yet
|
||||
type: "string", // Ought to be DateTime but we don't have a type for this yet
|
||||
nullable: true,
|
||||
description: "The employee's birth date"
|
||||
},
|
||||
{
|
||||
name: "HireDate",
|
||||
type: ScalarType.String, // Ought to be DateTime but we don't have a type for this yet
|
||||
type: "string", // Ought to be DateTime but we don't have a type for this yet
|
||||
nullable: true,
|
||||
description: "The employee's birth date"
|
||||
},
|
||||
{
|
||||
name: "Address",
|
||||
type: ScalarType.String,
|
||||
type: "string",
|
||||
nullable: true,
|
||||
description: "The employee's address line (street number, street)"
|
||||
},
|
||||
{
|
||||
name: "City",
|
||||
type: ScalarType.String,
|
||||
type: "string",
|
||||
nullable: true,
|
||||
description: "The employee's address city"
|
||||
},
|
||||
{
|
||||
name: "State",
|
||||
type: ScalarType.String,
|
||||
type: "string",
|
||||
nullable: true,
|
||||
description: "The employee's address state"
|
||||
},
|
||||
{
|
||||
name: "Country",
|
||||
type: ScalarType.String,
|
||||
type: "string",
|
||||
nullable: true,
|
||||
description: "The employee's address country"
|
||||
},
|
||||
{
|
||||
name: "PostalCode",
|
||||
type: ScalarType.String,
|
||||
type: "string",
|
||||
nullable: true,
|
||||
description: "The employee's address postal code"
|
||||
},
|
||||
{
|
||||
name: "Phone",
|
||||
type: ScalarType.String,
|
||||
type: "string",
|
||||
nullable: true,
|
||||
description: "The employee's phone number"
|
||||
},
|
||||
{
|
||||
name: "Fax",
|
||||
type: ScalarType.String,
|
||||
type: "string",
|
||||
nullable: true,
|
||||
description: "The employee's fax number"
|
||||
},
|
||||
{
|
||||
name: "Email",
|
||||
type: ScalarType.String,
|
||||
type: "string",
|
||||
nullable: false,
|
||||
description: "The employee's email address"
|
||||
},
|
||||
@ -263,13 +263,13 @@ const schema: SchemaResponse = {
|
||||
columns: [
|
||||
{
|
||||
name: "GenreId",
|
||||
type: ScalarType.Number,
|
||||
type: "number",
|
||||
nullable: false,
|
||||
description: "Genre primary key identifier"
|
||||
},
|
||||
{
|
||||
name: "Name",
|
||||
type: ScalarType.String,
|
||||
type: "string",
|
||||
nullable: true,
|
||||
description: "The name of the genre"
|
||||
}
|
||||
@ -282,55 +282,55 @@ const schema: SchemaResponse = {
|
||||
columns: [
|
||||
{
|
||||
name: "InvoiceId",
|
||||
type: ScalarType.Number,
|
||||
type: "number",
|
||||
nullable: false,
|
||||
description: "Invoice primary key identifier"
|
||||
},
|
||||
{
|
||||
name: "CustomerId",
|
||||
type: ScalarType.Number,
|
||||
type: "number",
|
||||
nullable: false,
|
||||
description: "ID of the customer who bought the music"
|
||||
},
|
||||
{
|
||||
name: "InvoiceDate",
|
||||
type: ScalarType.String, // Ought to be DateTime but we don't have a type for this yet
|
||||
type: "string", // Ought to be DateTime but we don't have a type for this yet
|
||||
nullable: false,
|
||||
description: "Date of the invoice"
|
||||
},
|
||||
{
|
||||
name: "BillingAddress",
|
||||
type: ScalarType.String,
|
||||
type: "string",
|
||||
nullable: true,
|
||||
description: "The invoice's billing address line (street number, street)"
|
||||
},
|
||||
{
|
||||
name: "BillingCity",
|
||||
type: ScalarType.String,
|
||||
type: "string",
|
||||
nullable: true,
|
||||
description: "The invoice's billing address city"
|
||||
},
|
||||
{
|
||||
name: "BillingState",
|
||||
type: ScalarType.String,
|
||||
type: "string",
|
||||
nullable: true,
|
||||
description: "The invoice's billing address state"
|
||||
},
|
||||
{
|
||||
name: "BillingCountry",
|
||||
type: ScalarType.String,
|
||||
type: "string",
|
||||
nullable: true,
|
||||
description: "The invoice's billing address country"
|
||||
},
|
||||
{
|
||||
name: "BillingPostalCode",
|
||||
type: ScalarType.String,
|
||||
type: "string",
|
||||
nullable: true,
|
||||
description: "The invoice's billing address postal code"
|
||||
},
|
||||
{
|
||||
name: "Total",
|
||||
type: ScalarType.Number,
|
||||
type: "number",
|
||||
nullable: false,
|
||||
description: "The total amount due on the invoice"
|
||||
},
|
||||
@ -343,31 +343,31 @@ const schema: SchemaResponse = {
|
||||
columns: [
|
||||
{
|
||||
name: "InvoiceLineId",
|
||||
type: ScalarType.Number,
|
||||
type: "number",
|
||||
nullable: false,
|
||||
description: "Invoice Line primary key identifier"
|
||||
},
|
||||
{
|
||||
name: "InvoiceId",
|
||||
type: ScalarType.Number,
|
||||
type: "number",
|
||||
nullable: false,
|
||||
description: "ID of the invoice the line belongs to"
|
||||
},
|
||||
{
|
||||
name: "TrackId",
|
||||
type: ScalarType.Number,
|
||||
type: "number",
|
||||
nullable: false,
|
||||
description: "ID of the music track being purchased"
|
||||
},
|
||||
{
|
||||
name: "UnitPrice",
|
||||
type: ScalarType.Number,
|
||||
type: "number",
|
||||
nullable: false,
|
||||
description: "Price of each individual track unit"
|
||||
},
|
||||
{
|
||||
name: "Quantity",
|
||||
type: ScalarType.Number,
|
||||
type: "number",
|
||||
nullable: false,
|
||||
description: "Quantity of the track purchased"
|
||||
},
|
||||
@ -380,13 +380,13 @@ const schema: SchemaResponse = {
|
||||
columns: [
|
||||
{
|
||||
name: "MediaTypeId",
|
||||
type: ScalarType.Number,
|
||||
type: "number",
|
||||
nullable: false,
|
||||
description: "Media Type primary key identifier"
|
||||
},
|
||||
{
|
||||
name: "Name",
|
||||
type: ScalarType.Number,
|
||||
type: "number",
|
||||
nullable: true,
|
||||
description: "The name of the media type format"
|
||||
},
|
||||
@ -399,13 +399,13 @@ const schema: SchemaResponse = {
|
||||
columns: [
|
||||
{
|
||||
name: "PlaylistId",
|
||||
type: ScalarType.Number,
|
||||
type: "number",
|
||||
nullable: false,
|
||||
description: "Playlist primary key identifier"
|
||||
},
|
||||
{
|
||||
name: "Name",
|
||||
type: ScalarType.Number,
|
||||
type: "number",
|
||||
nullable: true,
|
||||
description: "The name of the playlist"
|
||||
},
|
||||
@ -419,13 +419,13 @@ const schema: SchemaResponse = {
|
||||
// columns: [
|
||||
// {
|
||||
// name: "PlaylistId",
|
||||
// type: ScalarType.Number,
|
||||
// type: "number",
|
||||
// nullable: false,
|
||||
// description: "The ID of the playlist"
|
||||
// },
|
||||
// {
|
||||
// name: "TrackId",
|
||||
// type: ScalarType.Number,
|
||||
// type: "number",
|
||||
// nullable: true,
|
||||
// description: "The ID of the track"
|
||||
// },
|
||||
@ -438,55 +438,55 @@ const schema: SchemaResponse = {
|
||||
columns: [
|
||||
{
|
||||
name: "TrackId",
|
||||
type: ScalarType.Number,
|
||||
type: "number",
|
||||
nullable: false,
|
||||
description: "The ID of the track"
|
||||
},
|
||||
{
|
||||
name: "Name",
|
||||
type: ScalarType.String,
|
||||
type: "string",
|
||||
nullable: false,
|
||||
description: "The name of the track"
|
||||
},
|
||||
{
|
||||
name: "AlbumId",
|
||||
type: ScalarType.Number,
|
||||
type: "number",
|
||||
nullable: true,
|
||||
description: "The ID of the album the track belongs to"
|
||||
},
|
||||
{
|
||||
name: "MediaTypeId",
|
||||
type: ScalarType.Number,
|
||||
type: "number",
|
||||
nullable: true,
|
||||
description: "The ID of the media type the track is encoded with"
|
||||
},
|
||||
{
|
||||
name: "GenreId",
|
||||
type: ScalarType.Number,
|
||||
type: "number",
|
||||
nullable: true,
|
||||
description: "The ID of the genre of the track"
|
||||
},
|
||||
{
|
||||
name: "Composer",
|
||||
type: ScalarType.String,
|
||||
type: "string",
|
||||
nullable: true,
|
||||
description: "The name of the composer of the track"
|
||||
},
|
||||
{
|
||||
name: "Milliseconds",
|
||||
type: ScalarType.Number,
|
||||
type: "number",
|
||||
nullable: false,
|
||||
description: "The length of the track in milliseconds"
|
||||
},
|
||||
{
|
||||
name: "Bytes",
|
||||
type: ScalarType.Number,
|
||||
type: "number",
|
||||
nullable: true,
|
||||
description: "The size of the track in bytes"
|
||||
},
|
||||
{
|
||||
name: "UnitPrice",
|
||||
type: ScalarType.Number,
|
||||
type: "number",
|
||||
nullable: false,
|
||||
description: "The price of the track"
|
||||
},
|
||||
|
@ -1,11 +1,10 @@
|
||||
import Fastify from 'fastify';
|
||||
import Fastify from 'fastify';
|
||||
import FastifyCors from '@fastify/cors';
|
||||
import { SchemaResponse } from './types/schema';
|
||||
import { ProjectedRow, QueryRequest } from './types/query';
|
||||
import { filterAvailableTables, getSchema, loadStaticData } from './data';
|
||||
import { queryData } from './query';
|
||||
import { getConfig } from './config';
|
||||
import { CapabilitiesResponse, capabilitiesResponse} from './capabilities';
|
||||
import { capabilitiesResponse } from './capabilities';
|
||||
import { CapabilitiesResponse, SchemaResponse, QueryRequest, QueryResponse } from './types';
|
||||
|
||||
const port = Number(process.env.PORT) || 8100;
|
||||
const server = Fastify({ logger: { prettyPrint: true } });
|
||||
@ -31,7 +30,7 @@ server.get<{ Reply: SchemaResponse }>("/schema", async (request, _response) => {
|
||||
return getSchema(config);
|
||||
});
|
||||
|
||||
server.post<{ Body: QueryRequest, Reply: ProjectedRow[] }>("/query", async (request, _response) => {
|
||||
server.post<{ Body: QueryRequest, Reply: QueryResponse }>("/query", async (request, _response) => {
|
||||
server.log.info({ headers: request.headers, query: request.body, }, "query.request");
|
||||
const config = getConfig(request);
|
||||
const data = filterAvailableTables(staticData, config);
|
||||
|
@ -1,49 +1,56 @@
|
||||
import { Expression, Fields, BinaryComparisonOperator, OrderBy, OrderType, ProjectedRow, Query, QueryResponse, RelationshipType, ScalarValue, UnaryComparisonOperator, ComparisonValue, BinaryArrayComparisonOperator, QueryRequest, TableName, ComparisonColumn, TableRelationships, Relationship, RelationshipName } from "./types/query";
|
||||
import { QueryRequest, TableRelationships, Relationship, Query, Field, OrderBy, Expression, BinaryComparisonOperator, UnaryComparisonOperator, BinaryArrayComparisonOperator, ComparisonColumn, ComparisonValue, ScalarValue, QueryResponse } from "./types";
|
||||
import { coerceUndefinedToNull, crossProduct, unreachable, zip } from "./util";
|
||||
|
||||
type StaticData = {
|
||||
[tableName: string]: Record<string, ScalarValue>[]
|
||||
}
|
||||
|
||||
type TableName = string
|
||||
type RelationshipName = string
|
||||
|
||||
type ProjectedRow = {
|
||||
[fieldName: string]: ScalarValue | ProjectedRow[] | ProjectedRow
|
||||
}
|
||||
|
||||
const prettyPrintBinaryComparisonOperator = (operator: BinaryComparisonOperator): string => {
|
||||
switch (operator) {
|
||||
case BinaryComparisonOperator.GreaterThan: return ">";
|
||||
case BinaryComparisonOperator.GreaterThanOrEqual: return ">=";
|
||||
case BinaryComparisonOperator.LessThan: return "<";
|
||||
case BinaryComparisonOperator.LessThanOrEqual: return "<=";
|
||||
case BinaryComparisonOperator.Equal: return "==";
|
||||
case "greater_than": return ">";
|
||||
case "greater_than_or_equal": return ">=";
|
||||
case "less_than": return "<";
|
||||
case "less_than_or_equal": return "<=";
|
||||
case "equal": return "==";
|
||||
default: return unreachable(operator);
|
||||
};
|
||||
};
|
||||
|
||||
const prettyPrintBinaryArrayComparisonOperator = (operator: BinaryArrayComparisonOperator): string => {
|
||||
switch (operator) {
|
||||
case BinaryArrayComparisonOperator.In: return "IN";
|
||||
case "in": return "IN";
|
||||
default: return unreachable(operator);
|
||||
};
|
||||
};
|
||||
|
||||
const prettyPrintUnaryComparisonOperator = (operator: UnaryComparisonOperator): string => {
|
||||
switch (operator) {
|
||||
case UnaryComparisonOperator.IsNull: return "IS NULL";
|
||||
case "is_null": return "IS NULL";
|
||||
default: return unreachable(operator);
|
||||
};
|
||||
};
|
||||
|
||||
const getBinaryComparisonOperatorEvaluator = (operator: BinaryComparisonOperator): ((left: ScalarValue, right: ScalarValue) => boolean) => {
|
||||
switch (operator) {
|
||||
case BinaryComparisonOperator.GreaterThan: return (a, b) => a !== null && b !== null && a > b;
|
||||
case BinaryComparisonOperator.GreaterThanOrEqual: return (a, b) => a !== null && b !== null && a >= b;
|
||||
case BinaryComparisonOperator.LessThan: return (a, b) => a !== null && b !== null && a < b;
|
||||
case BinaryComparisonOperator.LessThanOrEqual: return (a, b) => a !== null && b !== null && a <= b;
|
||||
case BinaryComparisonOperator.Equal: return (a, b) => a !== null && b !== null && a === b;
|
||||
case "greater_than": return (a, b) => a !== null && b !== null && a > b;
|
||||
case "greater_than_or_equal": return (a, b) => a !== null && b !== null && a >= b;
|
||||
case "less_than": return (a, b) => a !== null && b !== null && a < b;
|
||||
case "less_than_or_equal": return (a, b) => a !== null && b !== null && a <= b;
|
||||
case "equal": return (a, b) => a !== null && b !== null && a === b;
|
||||
default: return unreachable(operator);
|
||||
};
|
||||
};
|
||||
|
||||
const getBinaryArrayComparisonOperatorEvaluator = (operator: BinaryArrayComparisonOperator): ((left: ScalarValue, right: ScalarValue[]) => boolean) => {
|
||||
switch (operator) {
|
||||
case BinaryArrayComparisonOperator.In: return (a, bs) => a !== null && bs.includes(a);
|
||||
case "in": return (a, bs) => a !== null && bs.includes(a);
|
||||
default: return unreachable(operator);
|
||||
};
|
||||
};
|
||||
@ -51,7 +58,7 @@ const getBinaryArrayComparisonOperatorEvaluator = (operator: BinaryArrayComparis
|
||||
|
||||
const getUnaryComparisonOperatorEvaluator = (operator: UnaryComparisonOperator): ((value: ScalarValue) => boolean) => {
|
||||
switch (operator) {
|
||||
case UnaryComparisonOperator.IsNull: return (v) => v === null;
|
||||
case "is_null": return (v) => v === null;
|
||||
default: return unreachable(operator);
|
||||
};
|
||||
};
|
||||
@ -162,7 +169,7 @@ const sortRows = (rows: Record<string, ScalarValue>[], orderBy: OrderBy[]): Reco
|
||||
? -1
|
||||
: 1;
|
||||
|
||||
return ordering === OrderType.Descending ? -compared : compared;
|
||||
return ordering === "desc" ? -compared : compared;
|
||||
}, 0)
|
||||
);
|
||||
|
||||
@ -191,7 +198,7 @@ const createFilterExpressionForRelationshipJoin = (row: Record<string, ScalarVal
|
||||
.map(([outerValue, innerColumnName]) => {
|
||||
return {
|
||||
type: "binary_op",
|
||||
operator: BinaryComparisonOperator.Equal,
|
||||
operator: "equal",
|
||||
column: {
|
||||
path: [],
|
||||
name: innerColumnName,
|
||||
@ -222,7 +229,7 @@ const addRelationshipFilterToQuery = (row: Record<string, ScalarValue>, relation
|
||||
}
|
||||
};
|
||||
|
||||
const buildFieldsForPathedComparisonColumn = (comparisonColumn: ComparisonColumn): Fields => {
|
||||
const buildFieldsForPathedComparisonColumn = (comparisonColumn: ComparisonColumn): Record<string, Field> => {
|
||||
const [relationshipName, ...remainingPath] = comparisonColumn.path;
|
||||
if (relationshipName === undefined) {
|
||||
return {
|
||||
@ -276,7 +283,7 @@ const makeGetComparisonColumnValues = (findRelationship: (relationshipName: Rela
|
||||
}
|
||||
};
|
||||
|
||||
const projectRow = (fields: Fields, findRelationship: (relationshipName: RelationshipName) => Relationship, performQuery: (tableName: TableName, query: Query) => ProjectedRow[]) => (row: Record<string, ScalarValue>): ProjectedRow => {
|
||||
const projectRow = (fields: Record<string, Field>, findRelationship: (relationshipName: RelationshipName) => Relationship, performQuery: (tableName: TableName, query: Query) => ProjectedRow[]) => (row: Record<string, ScalarValue>): ProjectedRow => {
|
||||
const projectedRow: ProjectedRow = {};
|
||||
for (const [fieldName, field] of Object.entries(fields)) {
|
||||
|
||||
@ -289,11 +296,11 @@ const projectRow = (fields: Fields, findRelationship: (relationshipName: Relatio
|
||||
const relationship = findRelationship(field.relationship);
|
||||
const subquery = addRelationshipFilterToQuery(row, relationship, field.query);
|
||||
switch (relationship.relationship_type) {
|
||||
case RelationshipType.Object:
|
||||
case "object":
|
||||
projectedRow[fieldName] = subquery ? coerceUndefinedToNull(performQuery(relationship.target_table, subquery)[0]) : null;
|
||||
break;
|
||||
|
||||
case RelationshipType.Array:
|
||||
case "array":
|
||||
projectedRow[fieldName] = subquery ? performQuery(relationship.target_table, subquery) : [];
|
||||
break;
|
||||
|
||||
|
1022
dc-agents/reference/src/types/agent.openapi.json
Normal file
1022
dc-agents/reference/src/types/agent.openapi.json
Normal file
File diff suppressed because it is too large
Load Diff
49
dc-agents/reference/src/types/index.ts
Normal file
49
dc-agents/reference/src/types/index.ts
Normal file
@ -0,0 +1,49 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
export type { AndExpression } from './models/AndExpression';
|
||||
export type { AnotherColumnComparison } from './models/AnotherColumnComparison';
|
||||
export type { ApplyBinaryArrayComparisonExpression } from './models/ApplyBinaryArrayComparisonExpression';
|
||||
export type { ApplyBinaryComparisonOperator } from './models/ApplyBinaryComparisonOperator';
|
||||
export type { ApplyUnaryComparisonOperator } from './models/ApplyUnaryComparisonOperator';
|
||||
export type { BinaryArrayComparisonOperator } from './models/BinaryArrayComparisonOperator';
|
||||
export type { BinaryComparisonOperator } from './models/BinaryComparisonOperator';
|
||||
export type { BooleanOperators } from './models/BooleanOperators';
|
||||
export type { Capabilities } from './models/Capabilities';
|
||||
export type { CapabilitiesResponse } from './models/CapabilitiesResponse';
|
||||
export type { ColumnField } from './models/ColumnField';
|
||||
export type { ColumnInfo } from './models/ColumnInfo';
|
||||
export type { ComparisonColumn } from './models/ComparisonColumn';
|
||||
export type { ComparisonOperators } from './models/ComparisonOperators';
|
||||
export type { ComparisonValue } from './models/ComparisonValue';
|
||||
export type { ConfigSchemaResponse } from './models/ConfigSchemaResponse';
|
||||
export type { Expression } from './models/Expression';
|
||||
export type { Field } from './models/Field';
|
||||
export type { FilteringCapabilities } from './models/FilteringCapabilities';
|
||||
export type { MutationCapabilities } from './models/MutationCapabilities';
|
||||
export type { NotExpression } from './models/NotExpression';
|
||||
export type { OpenApiDiscriminator } from './models/OpenApiDiscriminator';
|
||||
export type { OpenApiExternalDocumentation } from './models/OpenApiExternalDocumentation';
|
||||
export type { OpenApiReference } from './models/OpenApiReference';
|
||||
export type { OpenApiSchema } from './models/OpenApiSchema';
|
||||
export type { OpenApiXml } from './models/OpenApiXml';
|
||||
export type { OrderBy } from './models/OrderBy';
|
||||
export type { OrderType } from './models/OrderType';
|
||||
export type { OrExpression } from './models/OrExpression';
|
||||
export type { Query } from './models/Query';
|
||||
export type { QueryCapabilities } from './models/QueryCapabilities';
|
||||
export type { QueryRequest } from './models/QueryRequest';
|
||||
export type { QueryResponse } from './models/QueryResponse';
|
||||
export type { Relationship } from './models/Relationship';
|
||||
export type { RelationshipCapabilities } from './models/RelationshipCapabilities';
|
||||
export type { RelationshipField } from './models/RelationshipField';
|
||||
export type { RelationshipType } from './models/RelationshipType';
|
||||
export type { ScalarType } from './models/ScalarType';
|
||||
export type { ScalarValue } from './models/ScalarValue';
|
||||
export type { ScalarValueComparison } from './models/ScalarValueComparison';
|
||||
export type { SchemaResponse } from './models/SchemaResponse';
|
||||
export type { SubscriptionCapabilities } from './models/SubscriptionCapabilities';
|
||||
export type { TableInfo } from './models/TableInfo';
|
||||
export type { TableRelationships } from './models/TableRelationships';
|
||||
export type { UnaryComparisonOperator } from './models/UnaryComparisonOperator';
|
11
dc-agents/reference/src/types/models/AndExpression.ts
Normal file
11
dc-agents/reference/src/types/models/AndExpression.ts
Normal file
@ -0,0 +1,11 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
import type { Expression } from './Expression';
|
||||
|
||||
export type AndExpression = {
|
||||
expressions: Array<Expression>;
|
||||
type: 'and';
|
||||
};
|
||||
|
@ -0,0 +1,11 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
import type { ComparisonColumn } from './ComparisonColumn';
|
||||
|
||||
export type AnotherColumnComparison = {
|
||||
column: ComparisonColumn;
|
||||
type: 'column';
|
||||
};
|
||||
|
@ -0,0 +1,15 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
import type { BinaryArrayComparisonOperator } from './BinaryArrayComparisonOperator';
|
||||
import type { ComparisonColumn } from './ComparisonColumn';
|
||||
import type { ScalarValue } from './ScalarValue';
|
||||
|
||||
export type ApplyBinaryArrayComparisonExpression = {
|
||||
column: ComparisonColumn;
|
||||
operator: BinaryArrayComparisonOperator;
|
||||
type: 'binary_arr_op';
|
||||
values: Array<ScalarValue>;
|
||||
};
|
||||
|
@ -0,0 +1,15 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
import type { BinaryComparisonOperator } from './BinaryComparisonOperator';
|
||||
import type { ComparisonColumn } from './ComparisonColumn';
|
||||
import type { ComparisonValue } from './ComparisonValue';
|
||||
|
||||
export type ApplyBinaryComparisonOperator = {
|
||||
column: ComparisonColumn;
|
||||
operator: BinaryComparisonOperator;
|
||||
type: 'binary_op';
|
||||
value: ComparisonValue;
|
||||
};
|
||||
|
@ -0,0 +1,13 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
import type { ComparisonColumn } from './ComparisonColumn';
|
||||
import type { UnaryComparisonOperator } from './UnaryComparisonOperator';
|
||||
|
||||
export type ApplyUnaryComparisonOperator = {
|
||||
column: ComparisonColumn;
|
||||
operator: UnaryComparisonOperator;
|
||||
type: 'unary_op';
|
||||
};
|
||||
|
@ -0,0 +1,5 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
export type BinaryArrayComparisonOperator = 'in';
|
@ -0,0 +1,5 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
export type BinaryComparisonOperator = 'less_than' | 'less_than_or_equal' | 'greater_than' | 'greater_than_or_equal' | 'equal';
|
7
dc-agents/reference/src/types/models/BooleanOperators.ts
Normal file
7
dc-agents/reference/src/types/models/BooleanOperators.ts
Normal file
@ -0,0 +1,7 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
export type BooleanOperators = {
|
||||
};
|
||||
|
18
dc-agents/reference/src/types/models/Capabilities.ts
Normal file
18
dc-agents/reference/src/types/models/Capabilities.ts
Normal file
@ -0,0 +1,18 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
import type { FilteringCapabilities } from './FilteringCapabilities';
|
||||
import type { MutationCapabilities } from './MutationCapabilities';
|
||||
import type { QueryCapabilities } from './QueryCapabilities';
|
||||
import type { RelationshipCapabilities } from './RelationshipCapabilities';
|
||||
import type { SubscriptionCapabilities } from './SubscriptionCapabilities';
|
||||
|
||||
export type Capabilities = {
|
||||
filtering?: FilteringCapabilities;
|
||||
mutations?: MutationCapabilities;
|
||||
queries?: QueryCapabilities;
|
||||
relationships?: RelationshipCapabilities;
|
||||
subscriptions?: SubscriptionCapabilities;
|
||||
};
|
||||
|
12
dc-agents/reference/src/types/models/CapabilitiesResponse.ts
Normal file
12
dc-agents/reference/src/types/models/CapabilitiesResponse.ts
Normal file
@ -0,0 +1,12 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
import type { Capabilities } from './Capabilities';
|
||||
import type { ConfigSchemaResponse } from './ConfigSchemaResponse';
|
||||
|
||||
export type CapabilitiesResponse = {
|
||||
capabilities: Capabilities;
|
||||
configSchemas: ConfigSchemaResponse;
|
||||
};
|
||||
|
9
dc-agents/reference/src/types/models/ColumnField.ts
Normal file
9
dc-agents/reference/src/types/models/ColumnField.ts
Normal file
@ -0,0 +1,9 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
export type ColumnField = {
|
||||
column: string;
|
||||
type: 'column';
|
||||
};
|
||||
|
22
dc-agents/reference/src/types/models/ColumnInfo.ts
Normal file
22
dc-agents/reference/src/types/models/ColumnInfo.ts
Normal file
@ -0,0 +1,22 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
import type { ScalarType } from './ScalarType';
|
||||
|
||||
export type ColumnInfo = {
|
||||
/**
|
||||
* Column description
|
||||
*/
|
||||
description?: string | null;
|
||||
/**
|
||||
* Column name
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* Is column nullable
|
||||
*/
|
||||
nullable: boolean;
|
||||
type: ScalarType;
|
||||
};
|
||||
|
15
dc-agents/reference/src/types/models/ComparisonColumn.ts
Normal file
15
dc-agents/reference/src/types/models/ComparisonColumn.ts
Normal file
@ -0,0 +1,15 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
export type ComparisonColumn = {
|
||||
/**
|
||||
* The name of the column
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* The relationship path from the current query table to the table that contains the specified column. Empty array means the current query table.
|
||||
*/
|
||||
path: Array<string>;
|
||||
};
|
||||
|
@ -0,0 +1,7 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
export type ComparisonOperators = {
|
||||
};
|
||||
|
9
dc-agents/reference/src/types/models/ComparisonValue.ts
Normal file
9
dc-agents/reference/src/types/models/ComparisonValue.ts
Normal file
@ -0,0 +1,9 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
import type { AnotherColumnComparison } from './AnotherColumnComparison';
|
||||
import type { ScalarValueComparison } from './ScalarValueComparison';
|
||||
|
||||
export type ComparisonValue = (AnotherColumnComparison | ScalarValueComparison);
|
||||
|
11
dc-agents/reference/src/types/models/ConfigSchemaResponse.ts
Normal file
11
dc-agents/reference/src/types/models/ConfigSchemaResponse.ts
Normal file
@ -0,0 +1,11 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
import type { OpenApiSchema } from './OpenApiSchema';
|
||||
|
||||
export type ConfigSchemaResponse = {
|
||||
configSchema: OpenApiSchema;
|
||||
otherSchemas: Record<string, OpenApiSchema>;
|
||||
};
|
||||
|
13
dc-agents/reference/src/types/models/Expression.ts
Normal file
13
dc-agents/reference/src/types/models/Expression.ts
Normal file
@ -0,0 +1,13 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
import type { AndExpression } from './AndExpression';
|
||||
import type { ApplyBinaryArrayComparisonExpression } from './ApplyBinaryArrayComparisonExpression';
|
||||
import type { ApplyBinaryComparisonOperator } from './ApplyBinaryComparisonOperator';
|
||||
import type { ApplyUnaryComparisonOperator } from './ApplyUnaryComparisonOperator';
|
||||
import type { NotExpression } from './NotExpression';
|
||||
import type { OrExpression } from './OrExpression';
|
||||
|
||||
export type Expression = (AndExpression | OrExpression | NotExpression | ApplyBinaryComparisonOperator | ApplyBinaryArrayComparisonExpression | ApplyUnaryComparisonOperator);
|
||||
|
9
dc-agents/reference/src/types/models/Field.ts
Normal file
9
dc-agents/reference/src/types/models/Field.ts
Normal file
@ -0,0 +1,9 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
import type { ColumnField } from './ColumnField';
|
||||
import type { RelationshipField } from './RelationshipField';
|
||||
|
||||
export type Field = (ColumnField | RelationshipField);
|
||||
|
@ -0,0 +1,12 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
import type { BooleanOperators } from './BooleanOperators';
|
||||
import type { ComparisonOperators } from './ComparisonOperators';
|
||||
|
||||
export type FilteringCapabilities = {
|
||||
booleanOperators: BooleanOperators;
|
||||
comparisonOperators: ComparisonOperators;
|
||||
};
|
||||
|
@ -0,0 +1,7 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
export type MutationCapabilities = {
|
||||
};
|
||||
|
11
dc-agents/reference/src/types/models/NotExpression.ts
Normal file
11
dc-agents/reference/src/types/models/NotExpression.ts
Normal file
@ -0,0 +1,11 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
import type { Expression } from './Expression';
|
||||
|
||||
export type NotExpression = {
|
||||
expression: Expression;
|
||||
type: 'not';
|
||||
};
|
||||
|
@ -0,0 +1,9 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
export type OpenApiDiscriminator = {
|
||||
mapping?: Record<string, string>;
|
||||
propertyName: string;
|
||||
};
|
||||
|
@ -0,0 +1,9 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
export type OpenApiExternalDocumentation = {
|
||||
description?: string;
|
||||
url: string;
|
||||
};
|
||||
|
8
dc-agents/reference/src/types/models/OpenApiReference.ts
Normal file
8
dc-agents/reference/src/types/models/OpenApiReference.ts
Normal file
@ -0,0 +1,8 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
export type OpenApiReference = {
|
||||
$ref: string;
|
||||
};
|
||||
|
47
dc-agents/reference/src/types/models/OpenApiSchema.ts
Normal file
47
dc-agents/reference/src/types/models/OpenApiSchema.ts
Normal file
@ -0,0 +1,47 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
import type { OpenApiDiscriminator } from './OpenApiDiscriminator';
|
||||
import type { OpenApiExternalDocumentation } from './OpenApiExternalDocumentation';
|
||||
import type { OpenApiReference } from './OpenApiReference';
|
||||
import type { OpenApiXml } from './OpenApiXml';
|
||||
|
||||
export type OpenApiSchema = {
|
||||
additionalProperties?: any;
|
||||
allOf?: Array<(OpenApiSchema | OpenApiReference)>;
|
||||
anyOf?: Array<(OpenApiSchema | OpenApiReference)>;
|
||||
default?: any;
|
||||
deprecated?: boolean;
|
||||
description?: string;
|
||||
discriminator?: OpenApiDiscriminator;
|
||||
enum?: Array<any>;
|
||||
example?: any;
|
||||
exclusiveMaximum?: boolean;
|
||||
exclusiveMinimum?: boolean;
|
||||
externalDocs?: OpenApiExternalDocumentation;
|
||||
format?: string;
|
||||
items?: (OpenApiSchema | OpenApiReference);
|
||||
maxItems?: number;
|
||||
maxLength?: number;
|
||||
maxProperties?: number;
|
||||
maximum?: number;
|
||||
minItems?: number;
|
||||
minLength?: number;
|
||||
minProperties?: number;
|
||||
minimum?: number;
|
||||
multipleOf?: number;
|
||||
not?: (OpenApiSchema | OpenApiReference);
|
||||
nullable?: boolean;
|
||||
oneOf?: Array<(OpenApiSchema | OpenApiReference)>;
|
||||
pattern?: string;
|
||||
properties?: Record<string, (OpenApiSchema | OpenApiReference)>;
|
||||
readOnly?: boolean;
|
||||
required?: Array<string>;
|
||||
title?: string;
|
||||
type?: 'array' | 'boolean' | 'integer' | 'number' | 'object' | 'string';
|
||||
uniqueItems?: boolean;
|
||||
writeOnly?: boolean;
|
||||
xml?: OpenApiXml;
|
||||
};
|
||||
|
12
dc-agents/reference/src/types/models/OpenApiXml.ts
Normal file
12
dc-agents/reference/src/types/models/OpenApiXml.ts
Normal file
@ -0,0 +1,12 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
export type OpenApiXml = {
|
||||
attribute?: boolean;
|
||||
name?: string;
|
||||
namespace?: string;
|
||||
prefix?: string;
|
||||
wrapped?: boolean;
|
||||
};
|
||||
|
11
dc-agents/reference/src/types/models/OrExpression.ts
Normal file
11
dc-agents/reference/src/types/models/OrExpression.ts
Normal file
@ -0,0 +1,11 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
import type { Expression } from './Expression';
|
||||
|
||||
export type OrExpression = {
|
||||
expressions: Array<Expression>;
|
||||
type: 'or';
|
||||
};
|
||||
|
14
dc-agents/reference/src/types/models/OrderBy.ts
Normal file
14
dc-agents/reference/src/types/models/OrderBy.ts
Normal file
@ -0,0 +1,14 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
import type { OrderType } from './OrderType';
|
||||
|
||||
export type OrderBy = {
|
||||
/**
|
||||
* Column to order by
|
||||
*/
|
||||
column: string;
|
||||
ordering: OrderType;
|
||||
};
|
||||
|
5
dc-agents/reference/src/types/models/OrderType.ts
Normal file
5
dc-agents/reference/src/types/models/OrderType.ts
Normal file
@ -0,0 +1,5 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
export type OrderType = 'asc' | 'desc';
|
28
dc-agents/reference/src/types/models/Query.ts
Normal file
28
dc-agents/reference/src/types/models/Query.ts
Normal file
@ -0,0 +1,28 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
import type { Expression } from './Expression';
|
||||
import type { Field } from './Field';
|
||||
import type { OrderBy } from './OrderBy';
|
||||
|
||||
export type Query = {
|
||||
/**
|
||||
* Fields of the query
|
||||
*/
|
||||
fields: Record<string, Field>;
|
||||
/**
|
||||
* Optionally limit to N results
|
||||
*/
|
||||
limit?: number | null;
|
||||
/**
|
||||
* Optionally offset from the Nth result
|
||||
*/
|
||||
offset?: number | null;
|
||||
/**
|
||||
* Optionally order the results by the value of one or more fields
|
||||
*/
|
||||
order_by?: Array<OrderBy> | null;
|
||||
where?: Expression;
|
||||
};
|
||||
|
11
dc-agents/reference/src/types/models/QueryCapabilities.ts
Normal file
11
dc-agents/reference/src/types/models/QueryCapabilities.ts
Normal file
@ -0,0 +1,11 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
export type QueryCapabilities = {
|
||||
/**
|
||||
* Does the agent support querying a table by primary key?
|
||||
*/
|
||||
supportsPrimaryKeys: boolean;
|
||||
};
|
||||
|
19
dc-agents/reference/src/types/models/QueryRequest.ts
Normal file
19
dc-agents/reference/src/types/models/QueryRequest.ts
Normal file
@ -0,0 +1,19 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
import type { Query } from './Query';
|
||||
import type { TableRelationships } from './TableRelationships';
|
||||
|
||||
export type QueryRequest = {
|
||||
query: Query;
|
||||
/**
|
||||
* The name of the table to query
|
||||
*/
|
||||
table: string;
|
||||
/**
|
||||
* The relationships between tables involved in the entire query request
|
||||
*/
|
||||
table_relationships: Array<TableRelationships>;
|
||||
};
|
||||
|
5
dc-agents/reference/src/types/models/QueryResponse.ts
Normal file
5
dc-agents/reference/src/types/models/QueryResponse.ts
Normal file
@ -0,0 +1,5 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
export type QueryResponse = Array<Record<string, any>>;
|
18
dc-agents/reference/src/types/models/Relationship.ts
Normal file
18
dc-agents/reference/src/types/models/Relationship.ts
Normal file
@ -0,0 +1,18 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
import type { RelationshipType } from './RelationshipType';
|
||||
|
||||
export type Relationship = {
|
||||
/**
|
||||
* A mapping between columns on the source table to columns on the target table
|
||||
*/
|
||||
column_mapping: Record<string, string>;
|
||||
relationship_type: RelationshipType;
|
||||
/**
|
||||
* The name of the target table in the relationship
|
||||
*/
|
||||
target_table: string;
|
||||
};
|
||||
|
@ -0,0 +1,7 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
export type RelationshipCapabilities = {
|
||||
};
|
||||
|
15
dc-agents/reference/src/types/models/RelationshipField.ts
Normal file
15
dc-agents/reference/src/types/models/RelationshipField.ts
Normal file
@ -0,0 +1,15 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
import type { Query } from './Query';
|
||||
|
||||
export type RelationshipField = {
|
||||
query: Query;
|
||||
/**
|
||||
* The name of the relationship to follow for the subquery
|
||||
*/
|
||||
relationship: string;
|
||||
type: 'relationship';
|
||||
};
|
||||
|
5
dc-agents/reference/src/types/models/RelationshipType.ts
Normal file
5
dc-agents/reference/src/types/models/RelationshipType.ts
Normal file
@ -0,0 +1,5 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
export type RelationshipType = 'object' | 'array';
|
5
dc-agents/reference/src/types/models/ScalarType.ts
Normal file
5
dc-agents/reference/src/types/models/ScalarType.ts
Normal file
@ -0,0 +1,5 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
export type ScalarType = 'string' | 'number' | 'bool';
|
6
dc-agents/reference/src/types/models/ScalarValue.ts
Normal file
6
dc-agents/reference/src/types/models/ScalarValue.ts
Normal file
@ -0,0 +1,6 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
export type ScalarValue = (string | number | boolean | null);
|
||||
|
@ -0,0 +1,11 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
import type { ScalarValue } from './ScalarValue';
|
||||
|
||||
export type ScalarValueComparison = {
|
||||
type: 'scalar';
|
||||
value: ScalarValue;
|
||||
};
|
||||
|
13
dc-agents/reference/src/types/models/SchemaResponse.ts
Normal file
13
dc-agents/reference/src/types/models/SchemaResponse.ts
Normal file
@ -0,0 +1,13 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
import type { TableInfo } from './TableInfo';
|
||||
|
||||
export type SchemaResponse = {
|
||||
/**
|
||||
* Available tables
|
||||
*/
|
||||
tables: Array<TableInfo>;
|
||||
};
|
||||
|
@ -0,0 +1,7 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
export type SubscriptionCapabilities = {
|
||||
};
|
||||
|
25
dc-agents/reference/src/types/models/TableInfo.ts
Normal file
25
dc-agents/reference/src/types/models/TableInfo.ts
Normal file
@ -0,0 +1,25 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
import type { ColumnInfo } from './ColumnInfo';
|
||||
|
||||
export type TableInfo = {
|
||||
/**
|
||||
* The columns of the table
|
||||
*/
|
||||
columns: Array<ColumnInfo>;
|
||||
/**
|
||||
* Description of the table
|
||||
*/
|
||||
description?: string | null;
|
||||
/**
|
||||
* The name of the table
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* The primary key of the table
|
||||
*/
|
||||
primary_key?: string | null;
|
||||
};
|
||||
|
17
dc-agents/reference/src/types/models/TableRelationships.ts
Normal file
17
dc-agents/reference/src/types/models/TableRelationships.ts
Normal file
@ -0,0 +1,17 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
import type { Relationship } from './Relationship';
|
||||
|
||||
export type TableRelationships = {
|
||||
/**
|
||||
* A map of relationships from the source table to target tables. The key of the map is the relationship name
|
||||
*/
|
||||
relationships: Record<string, Relationship>;
|
||||
/**
|
||||
* The name of the source table in the relationship
|
||||
*/
|
||||
source_table: string;
|
||||
};
|
||||
|
@ -0,0 +1,5 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
export type UnaryComparisonOperator = 'is_null';
|
@ -1,148 +0,0 @@
|
||||
export type QueryRequest = {
|
||||
table: TableName,
|
||||
table_relationships: TableRelationships[],
|
||||
query: Query,
|
||||
}
|
||||
|
||||
export type TableName = string
|
||||
|
||||
export type TableRelationships = {
|
||||
source_table: TableName,
|
||||
relationships: { [relationshipName: RelationshipName]: Relationship }
|
||||
}
|
||||
|
||||
export type Relationship = {
|
||||
target_table: TableName,
|
||||
relationship_type: RelationshipType,
|
||||
column_mapping: { [source: SourceColumnName]: TargetColumnName },
|
||||
}
|
||||
|
||||
export type SourceColumnName = ColumnName
|
||||
export type TargetColumnName = ColumnName
|
||||
|
||||
export type RelationshipName = string
|
||||
|
||||
export enum RelationshipType {
|
||||
Object = "object",
|
||||
Array = "array"
|
||||
}
|
||||
|
||||
export type Query = {
|
||||
fields: Fields,
|
||||
limit?: number | null,
|
||||
offset?: number | null,
|
||||
where?: Expression | null,
|
||||
order_by?: OrderBy[],
|
||||
}
|
||||
|
||||
export type Fields = { [fieldName: string]: Field }
|
||||
|
||||
export type Field = ColumnField | RelationshipField
|
||||
|
||||
export type ColumnName = string
|
||||
export type ColumnField = {
|
||||
type: "column",
|
||||
column: ColumnName,
|
||||
}
|
||||
|
||||
export type RelationshipField = {
|
||||
type: "relationship",
|
||||
relationship: RelationshipName
|
||||
query: Query,
|
||||
}
|
||||
|
||||
export type ScalarValue = string | number | boolean | null
|
||||
|
||||
export type ComparisonColumn = {
|
||||
path: RelationshipName[],
|
||||
name: ColumnName,
|
||||
}
|
||||
|
||||
export type ComparisonValue =
|
||||
| AnotherColumnComparisonValue
|
||||
| ScalarComparisonValue
|
||||
|
||||
export type AnotherColumnComparisonValue = {
|
||||
type: "column",
|
||||
column: ComparisonColumn,
|
||||
}
|
||||
|
||||
export type ScalarComparisonValue = {
|
||||
type: "scalar",
|
||||
value: ScalarValue,
|
||||
}
|
||||
|
||||
export type Expression =
|
||||
| AndExpression
|
||||
| OrExpression
|
||||
| NotExpression
|
||||
| ApplyBinaryComparisonOperatorExpression
|
||||
| ApplyBinaryArrayComparisonOperatorExpression
|
||||
| ApplyUnaryComparisonOperatorExpression
|
||||
|
||||
export type AndExpression = {
|
||||
type: "and",
|
||||
expressions: Expression[],
|
||||
}
|
||||
|
||||
export type OrExpression = {
|
||||
type: "or",
|
||||
expressions: Expression[],
|
||||
}
|
||||
|
||||
export type NotExpression = {
|
||||
type: "not",
|
||||
expression: Expression,
|
||||
}
|
||||
|
||||
export type ApplyBinaryComparisonOperatorExpression = {
|
||||
type: "binary_op",
|
||||
operator: BinaryComparisonOperator,
|
||||
column: ComparisonColumn,
|
||||
value: ComparisonValue,
|
||||
}
|
||||
|
||||
export type ApplyBinaryArrayComparisonOperatorExpression = {
|
||||
type: "binary_arr_op",
|
||||
operator: BinaryArrayComparisonOperator,
|
||||
column: ComparisonColumn,
|
||||
values: ScalarValue[],
|
||||
}
|
||||
|
||||
export type ApplyUnaryComparisonOperatorExpression = {
|
||||
type: "unary_op",
|
||||
operator: UnaryComparisonOperator,
|
||||
column: ComparisonColumn,
|
||||
}
|
||||
|
||||
export enum BinaryComparisonOperator {
|
||||
LessThan = "less_than",
|
||||
LessThanOrEqual = "less_than_or_equal",
|
||||
GreaterThan = "greater_than",
|
||||
GreaterThanOrEqual = "greater_than_or_equal",
|
||||
Equal = "equal",
|
||||
}
|
||||
|
||||
export enum BinaryArrayComparisonOperator {
|
||||
In = "in",
|
||||
}
|
||||
|
||||
export enum UnaryComparisonOperator {
|
||||
IsNull = "is_null",
|
||||
}
|
||||
|
||||
export type OrderBy = {
|
||||
column: ColumnName,
|
||||
ordering: OrderType,
|
||||
}
|
||||
|
||||
export enum OrderType {
|
||||
Ascending = "asc",
|
||||
Descending = "desc",
|
||||
}
|
||||
|
||||
export type QueryResponse = ProjectedRow[]
|
||||
|
||||
export type ProjectedRow = {
|
||||
[fieldName: string]: ScalarValue | ProjectedRow[] | ProjectedRow
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
export type SchemaResponse = {
|
||||
tables: Table[],
|
||||
}
|
||||
|
||||
export type Table = {
|
||||
name: string,
|
||||
columns: ColumnInfo[],
|
||||
primary_key?: string | null,
|
||||
description?: string | null
|
||||
}
|
||||
|
||||
export type ColumnInfo = {
|
||||
name: string,
|
||||
type: ScalarType,
|
||||
nullable: boolean,
|
||||
description?: string | null
|
||||
}
|
||||
|
||||
export enum ScalarType {
|
||||
String = "string",
|
||||
Number = "number",
|
||||
Boolean = "bool"
|
||||
}
|
@ -1,9 +1,8 @@
|
||||
export const coerceUndefinedToNull = <T>(v: T | undefined): T | null => v === undefined ? null : v;
|
||||
|
||||
export const unreachable = (x: never): never => { throw new Error(`Unreachable code reached! The types lied! 😭 Unexpected value: ${x}`) };
|
||||
;
|
||||
|
||||
export const zip = <T, U>(arr1: T[], arr2: U[]): [T,U][] => {
|
||||
export const zip = <T, U>(arr1: T[], arr2: U[]): [T, U][] => {
|
||||
const length = Math.min(arr1.length, arr2.length);
|
||||
const newArray = Array(length);
|
||||
for (let i = 0; i < length; i++) {
|
||||
@ -12,6 +11,6 @@ export const zip = <T, U>(arr1: T[], arr2: U[]): [T,U][] => {
|
||||
return newArray;
|
||||
};
|
||||
|
||||
export const crossProduct = <T, U>(arr1: T[], arr2: U[]): [T,U][] => {
|
||||
return arr1.flatMap(a1 => arr2.map(a2 => [a1, a2]) as [T,U][]);
|
||||
export const crossProduct = <T, U>(arr1: T[], arr2: U[]): [T, U][] => {
|
||||
return arr1.flatMap(a1 => arr2.map(a2 => [a1, a2]) as [T, U][]);
|
||||
};
|
||||
|
@ -7,13 +7,12 @@ module Hasura.Backends.DataConnector.API
|
||||
ConfigHeader,
|
||||
SourceNameHeader,
|
||||
SourceName,
|
||||
openApiSchemaJson,
|
||||
openApiSchema,
|
||||
Routes (..),
|
||||
apiClient,
|
||||
)
|
||||
where
|
||||
|
||||
import Data.Aeson qualified as J
|
||||
import Data.Data (Proxy (..))
|
||||
import Data.OpenApi (OpenApi)
|
||||
import Data.Text (Text)
|
||||
@ -22,7 +21,6 @@ import Servant.API
|
||||
import Servant.API.Generic
|
||||
import Servant.Client (Client, ClientM, client)
|
||||
import Servant.OpenApi
|
||||
import Prelude
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Servant Routes
|
||||
@ -68,13 +66,6 @@ type Api = CapabilitiesApi :<|> SchemaApi :<|> QueryApi
|
||||
openApiSchema :: OpenApi
|
||||
openApiSchema = toOpenApi (Proxy @Api)
|
||||
|
||||
-- | The OpenAPI 3.0 schema for the API
|
||||
--
|
||||
-- This is not exposed as the 'OpenApi' type because we need to do some hackery in
|
||||
-- the serialized JSON to work around some limitations in the openapi3 library
|
||||
openApiSchemaJson :: J.Value
|
||||
openApiSchemaJson = V0.fixExternalSchemaRefsInComponentSchemas $ J.toJSON openApiSchema
|
||||
|
||||
apiClient :: Client ClientM (NamedRoutes Routes)
|
||||
apiClient =
|
||||
client (Proxy @(NamedRoutes Routes))
|
||||
|
@ -22,7 +22,7 @@ import Data.Aeson (FromJSON, ToJSON)
|
||||
import Data.Data (Data, Proxy (..))
|
||||
import Data.HashMap.Strict.InsOrd qualified as InsOrdHashMap
|
||||
import Data.Hashable (Hashable)
|
||||
import Data.OpenApi (NamedSchema (..), OpenApiType (OpenApiObject), Referenced (..), Schema (..), ToSchema (..))
|
||||
import Data.OpenApi (NamedSchema (..), OpenApiType (OpenApiObject), Schema (..), ToSchema (..), declareSchemaRef)
|
||||
import GHC.Generics (Generic)
|
||||
import Hasura.Backends.DataConnector.API.V0.ConfigSchema (ConfigSchemaResponse)
|
||||
import Prelude
|
||||
@ -137,8 +137,8 @@ instance HasCodec CapabilitiesResponse where
|
||||
|
||||
instance ToSchema CapabilitiesResponse where
|
||||
declareNamedSchema _ = do
|
||||
capabilitiesSchema <- declareNamedSchema (Proxy @Capabilities)
|
||||
configSchemasSchema <- declareNamedSchema (Proxy @ConfigSchemaResponse)
|
||||
capabilitiesSchemaRef <- declareSchemaRef (Proxy @Capabilities)
|
||||
configSchemasSchemaRef <- declareSchemaRef (Proxy @ConfigSchemaResponse)
|
||||
let schema =
|
||||
mempty
|
||||
{ _schemaType = Just OpenApiObject,
|
||||
@ -146,8 +146,8 @@ instance ToSchema CapabilitiesResponse where
|
||||
_schemaRequired = ["capabilities", "configSchemas"],
|
||||
_schemaProperties =
|
||||
InsOrdHashMap.fromList
|
||||
[ ("capabilities", Inline $ _namedSchemaSchema capabilitiesSchema),
|
||||
("configSchemas", Inline $ _namedSchemaSchema configSchemasSchema)
|
||||
[ ("capabilities", capabilitiesSchemaRef),
|
||||
("configSchemas", configSchemasSchemaRef)
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -4,8 +4,6 @@ module Hasura.Backends.DataConnector.API.V0.ConfigSchema
|
||||
( Config (..),
|
||||
ConfigSchemaResponse (..),
|
||||
validateConfigAgainstConfigSchema,
|
||||
fixExternalSchemaRefsInComponentSchemas,
|
||||
fixExternalSchemaRefsInSchema,
|
||||
)
|
||||
where
|
||||
|
||||
@ -20,8 +18,9 @@ import Data.ByteString.Lazy qualified as BSL
|
||||
import Data.HashMap.Strict.InsOrd qualified as InsOrdHashMap
|
||||
import Data.Hashable (Hashable)
|
||||
import Data.Maybe (fromMaybe)
|
||||
import Data.OpenApi (AdditionalProperties (..), Definitions, NamedSchema (..), OpenApiType (..), Reference (..), Referenced (..), Schema (..), ToParamSchema (..), ToSchema (..), ValidationError)
|
||||
import Data.OpenApi (AdditionalProperties (..), Definitions, NamedSchema (..), OpenApiItems (..), OpenApiType (..), Reference (..), Referenced (..), Schema (..), ToParamSchema (..), ToSchema (..), ValidationError)
|
||||
import Data.OpenApi qualified as OpenApi
|
||||
import Data.OpenApi.Declare (Declare, MonadDeclare (..))
|
||||
import Data.Text (Text)
|
||||
import Data.Text qualified as Text
|
||||
import Data.Text.Encoding qualified as Text
|
||||
@ -75,33 +74,184 @@ instance Autodocodec.HasCodec ConfigSchemaResponse where
|
||||
codec = Autodocodec.codecViaAeson "Configuration schemas"
|
||||
|
||||
instance ToSchema ConfigSchemaResponse where
|
||||
declareNamedSchema _ =
|
||||
declareNamedSchema _ = do
|
||||
openApiSchemaRef <- declareOpenApiSchema
|
||||
let otherSchemasSchema =
|
||||
mempty
|
||||
{ _schemaType = Just OpenApiObject,
|
||||
_schemaNullable = Just False,
|
||||
_schemaAdditionalProperties = Just $ AdditionalPropertiesSchema openApiSchemaRef
|
||||
}
|
||||
let schema =
|
||||
mempty
|
||||
{ _schemaType = Just OpenApiObject,
|
||||
_schemaNullable = Just False,
|
||||
_schemaRequired = ["configSchema", "otherSchemas"],
|
||||
_schemaProperties =
|
||||
InsOrdHashMap.fromList
|
||||
[ ("configSchema", openApiSchemaRef),
|
||||
("otherSchemas", Inline otherSchemasSchema)
|
||||
]
|
||||
}
|
||||
pure $ NamedSchema (Just "ConfigSchemaResponse") schema
|
||||
where
|
||||
schema :: Schema
|
||||
schema =
|
||||
|
||||
-- | Declares the schema for the OpenAPI Schema type (and its dependent types) and
|
||||
-- returns a reference that can be used to refer to it from other schemas.
|
||||
--
|
||||
-- This is a transcription of the schemas defined here:
|
||||
-- https://raw.githubusercontent.com/OAI/OpenAPI-Specification/80c781e479f85ac67001ceb3e7e410e25d2a561b/schemas/v3.0/schema.json#/definitions/Schema
|
||||
--
|
||||
-- Unfortunately using external references to the above schema tends to make many
|
||||
-- OpenAPI type generators choke, so importing the relevant schemas into our spec
|
||||
-- is a pragmatic workaround.
|
||||
declareOpenApiSchema :: Declare (Definitions Schema) (Referenced Schema)
|
||||
declareOpenApiSchema = do
|
||||
declare $
|
||||
InsOrdHashMap.fromList
|
||||
[ openApiSchema,
|
||||
openApiReference,
|
||||
openApiDiscriminator,
|
||||
openApiExternalDocumentation,
|
||||
openApiXml
|
||||
]
|
||||
pure . Ref $ Reference "OpenApiSchema"
|
||||
where
|
||||
openApiSchema :: (Text, Schema)
|
||||
openApiSchema =
|
||||
("OpenApiSchema",)
|
||||
mempty
|
||||
{ _schemaType = Just OpenApiObject,
|
||||
_schemaNullable = Just False,
|
||||
_schemaRequired = ["configSchema", "otherSchemas"],
|
||||
_schemaProperties =
|
||||
InsOrdHashMap.fromList
|
||||
[ ("configSchema", openApiSchemaSchema),
|
||||
("otherSchemas", Inline otherSchemasSchema)
|
||||
[ ("title", Inline mempty {_schemaType = Just OpenApiString}),
|
||||
("multipleOf", Inline mempty {_schemaType = Just OpenApiNumber, _schemaMinimum = Just 0, _schemaExclusiveMinimum = Just True}),
|
||||
("maximum", Inline mempty {_schemaType = Just OpenApiNumber}),
|
||||
("exclusiveMaximum", Inline mempty {_schemaType = Just OpenApiBoolean, _schemaDefault = Just $ Bool False}),
|
||||
("minimum", Inline mempty {_schemaType = Just OpenApiNumber}),
|
||||
("exclusiveMinimum", Inline mempty {_schemaType = Just OpenApiBoolean, _schemaDefault = Just $ Bool False}),
|
||||
("maxLength", Inline mempty {_schemaType = Just OpenApiInteger, _schemaMinimum = Just 0}),
|
||||
("minLength", Inline mempty {_schemaType = Just OpenApiInteger, _schemaMinimum = Just 0, _schemaDefault = Just $ Number 0}),
|
||||
("pattern", Inline mempty {_schemaType = Just OpenApiString, _schemaFormat = Just "regex"}),
|
||||
("maxItems", Inline mempty {_schemaType = Just OpenApiInteger, _schemaMinimum = Just 0}),
|
||||
("minItems", Inline mempty {_schemaType = Just OpenApiInteger, _schemaMinimum = Just 0, _schemaDefault = Just $ Number 0}),
|
||||
("uniqueItems", Inline mempty {_schemaType = Just OpenApiBoolean, _schemaDefault = Just $ Bool False}),
|
||||
("maxProperties", Inline mempty {_schemaType = Just OpenApiInteger, _schemaMinimum = Just 0}),
|
||||
("minProperties", Inline mempty {_schemaType = Just OpenApiInteger, _schemaMinimum = Just 0, _schemaDefault = Just $ Number 0}),
|
||||
( "required",
|
||||
Inline
|
||||
mempty
|
||||
{ _schemaType = Just OpenApiArray,
|
||||
_schemaItems = Just . OpenApiItemsObject $ Inline mempty {_schemaType = Just OpenApiString},
|
||||
_schemaMinItems = Just 1,
|
||||
_schemaUniqueItems = Just True
|
||||
}
|
||||
),
|
||||
( "enum",
|
||||
Inline
|
||||
mempty
|
||||
{ _schemaType = Just OpenApiArray,
|
||||
_schemaItems = Just . OpenApiItemsObject $ Inline mempty,
|
||||
_schemaMinItems = Just 1,
|
||||
_schemaUniqueItems = Just False
|
||||
}
|
||||
),
|
||||
("type", Inline mempty {_schemaType = Just OpenApiString, _schemaEnum = Just ["array", "boolean", "integer", "number", "object", "string"]}),
|
||||
("not", Inline mempty {_schemaOneOf = Just schemaOrReference}),
|
||||
("allOf", Inline mempty {_schemaType = Just OpenApiArray, _schemaItems = Just . OpenApiItemsObject $ Inline mempty {_schemaOneOf = Just schemaOrReference}}),
|
||||
("oneOf", Inline mempty {_schemaType = Just OpenApiArray, _schemaItems = Just . OpenApiItemsObject $ Inline mempty {_schemaOneOf = Just schemaOrReference}}),
|
||||
("anyOf", Inline mempty {_schemaType = Just OpenApiArray, _schemaItems = Just . OpenApiItemsObject $ Inline mempty {_schemaOneOf = Just schemaOrReference}}),
|
||||
("items", Inline mempty {_schemaOneOf = Just schemaOrReference}),
|
||||
("properties", Inline mempty {_schemaType = Just OpenApiObject, _schemaAdditionalProperties = Just . AdditionalPropertiesSchema $ Inline mempty {_schemaOneOf = Just schemaOrReference}}),
|
||||
( "additionalProperties",
|
||||
Inline
|
||||
mempty
|
||||
{ _schemaAdditionalProperties = Just . AdditionalPropertiesSchema $ Inline mempty {_schemaOneOf = Just $ schemaOrReference <> [Inline mempty {_schemaType = Just OpenApiBoolean}]},
|
||||
_schemaDefault = Just $ Bool True
|
||||
}
|
||||
),
|
||||
("description", Inline mempty {_schemaType = Just OpenApiString}),
|
||||
("format", Inline mempty {_schemaType = Just OpenApiString}),
|
||||
("default", Inline mempty),
|
||||
("nullable", Inline mempty {_schemaType = Just OpenApiBoolean, _schemaDefault = Just $ Bool False}),
|
||||
("discriminator", Ref . Reference $ fst openApiDiscriminator),
|
||||
("readOnly", Inline mempty {_schemaType = Just OpenApiBoolean, _schemaDefault = Just $ Bool False}),
|
||||
("writeOnly", Inline mempty {_schemaType = Just OpenApiBoolean, _schemaDefault = Just $ Bool False}),
|
||||
("example", Inline mempty),
|
||||
("externalDocs", Ref . Reference $ fst openApiExternalDocumentation),
|
||||
("deprecated", Inline mempty {_schemaType = Just OpenApiBoolean, _schemaDefault = Just $ Bool False}),
|
||||
("xml", Ref . Reference $ fst openApiXml)
|
||||
],
|
||||
-- Note: Technically OpenAPI schemas should be able to define extension properties but since OpenAPI itself doesn't
|
||||
-- support defining patternProperties, I can't define them here. 😢
|
||||
-- "patternProperties": { "^x-": {} }
|
||||
-- _schemaPatternProperties =
|
||||
_schemaAdditionalProperties = Just $ AdditionalPropertiesAllowed False
|
||||
}
|
||||
|
||||
openApiReference :: (Text, Schema)
|
||||
openApiReference =
|
||||
("OpenApiReference",)
|
||||
mempty
|
||||
{ _schemaType = Just OpenApiObject,
|
||||
_schemaRequired = ["$ref"],
|
||||
-- Note: This is technically defined using "patternProperties" with the property name regex ^\$ref$
|
||||
-- but OpenAPI doesn't support patternProperties ironically, so this is close enough
|
||||
_schemaProperties = InsOrdHashMap.fromList [("$ref", Inline mempty {_schemaType = Just OpenApiString, _schemaFormat = Just "uri-reference"})]
|
||||
}
|
||||
|
||||
schemaOrReference :: [Referenced Schema]
|
||||
schemaOrReference = [Ref . Reference $ fst openApiSchema, Ref . Reference $ fst openApiReference]
|
||||
|
||||
openApiDiscriminator :: (Text, Schema)
|
||||
openApiDiscriminator =
|
||||
("OpenApiDiscriminator",)
|
||||
mempty
|
||||
{ _schemaType = Just OpenApiObject,
|
||||
_schemaRequired = ["propertyName"],
|
||||
_schemaProperties =
|
||||
InsOrdHashMap.fromList
|
||||
[ ("propertyName", Inline mempty {_schemaType = Just OpenApiString}),
|
||||
("mapping", Inline mempty {_schemaType = Just OpenApiObject, _schemaAdditionalProperties = Just . AdditionalPropertiesSchema $ Inline mempty {_schemaType = Just OpenApiString}})
|
||||
]
|
||||
}
|
||||
|
||||
otherSchemasSchema :: Schema
|
||||
otherSchemasSchema =
|
||||
openApiExternalDocumentation :: (Text, Schema)
|
||||
openApiExternalDocumentation =
|
||||
("OpenApiExternalDocumentation",)
|
||||
mempty
|
||||
{ _schemaType = Just OpenApiObject,
|
||||
_schemaNullable = Just False,
|
||||
_schemaAdditionalProperties = Just $ AdditionalPropertiesSchema openApiSchemaSchema
|
||||
_schemaRequired = ["url"],
|
||||
_schemaProperties =
|
||||
InsOrdHashMap.fromList
|
||||
[ ("description", Inline mempty {_schemaType = Just OpenApiString}),
|
||||
("url", Inline mempty {_schemaType = Just OpenApiString, _schemaFormat = Just "uri-reference"})
|
||||
],
|
||||
-- Note: Technically external docs should be able to define extension properties but since OpenAPI itself doesn't
|
||||
-- support defining patternProperties, I can't define them here. 😢
|
||||
-- "patternProperties": { "^x-": {} }
|
||||
-- _schemaPatternProperties =
|
||||
_schemaAdditionalProperties = Just $ AdditionalPropertiesAllowed False
|
||||
}
|
||||
|
||||
openApiSchemaSchema :: Referenced Schema
|
||||
openApiSchemaSchema =
|
||||
Ref (Reference "https://raw.githubusercontent.com/OAI/OpenAPI-Specification/80c781e479f85ac67001ceb3e7e410e25d2a561b/schemas/v3.0/schema.json#/definitions/Schema")
|
||||
openApiXml :: (Text, Schema)
|
||||
openApiXml =
|
||||
("OpenApiXml",)
|
||||
mempty
|
||||
{ _schemaType = Just OpenApiObject,
|
||||
_schemaProperties =
|
||||
InsOrdHashMap.fromList
|
||||
[ ("name", Inline mempty {_schemaType = Just OpenApiString}),
|
||||
("namespace", Inline mempty {_schemaType = Just OpenApiString, _schemaFormat = Just "uri"}),
|
||||
("prefix", Inline mempty {_schemaType = Just OpenApiString}),
|
||||
("attribute", Inline mempty {_schemaType = Just OpenApiBoolean, _schemaDefault = Just $ Bool False}),
|
||||
("wrapped", Inline mempty {_schemaType = Just OpenApiBoolean, _schemaDefault = Just $ Bool False})
|
||||
],
|
||||
-- Note: Technically XML should be able to define extension properties but since OpenAPI itself doesn't
|
||||
-- support defining patternProperties, I can't define them here. 😢
|
||||
-- "patternProperties": { "^x-": {} }
|
||||
-- _schemaPatternProperties =
|
||||
_schemaAdditionalProperties = Just $ AdditionalPropertiesAllowed False
|
||||
}
|
||||
|
||||
-- | Rewrites the config schema internal refs to the form that openapi3 expects when it deserialized them
|
||||
--
|
||||
@ -157,26 +307,3 @@ rewriteSchemaRefs rewriteRefText schemaObj =
|
||||
validateConfigAgainstConfigSchema :: ConfigSchemaResponse -> Config -> [ValidationError]
|
||||
validateConfigAgainstConfigSchema ConfigSchemaResponse {..} (Config config) =
|
||||
OpenApi.validateJSON _csrOtherSchemas _csrConfigSchema (Object config)
|
||||
|
||||
-- | Fixes any refs in schemas that are external refs to an http-based URL.
|
||||
-- Note that this is limited to schemas in the components/schemas section.
|
||||
-- This is used to specifically address the external refs defined by the
|
||||
-- OpenAPI schema spec of the 'ConfigSchemaResponse' type.
|
||||
--
|
||||
-- This works around a limitation in the openapi3 library where it does not
|
||||
-- understand the concept of external refs and will always assume any defined
|
||||
-- ref refers to a schema inside the top level OpenApi document itself.
|
||||
-- Practically, this means that #/components/schemas/ gets mashed onto the
|
||||
-- front of any external ref :(
|
||||
fixExternalSchemaRefsInComponentSchemas :: Value -> Value
|
||||
fixExternalSchemaRefsInComponentSchemas openApiObj =
|
||||
openApiObj
|
||||
& key "components" . key "schemas" . members %~ fixExternalSchemaRefsInSchema
|
||||
|
||||
fixExternalSchemaRefsInSchema :: Value -> Value
|
||||
fixExternalSchemaRefsInSchema = rewriteSchemaRefs fixExternalHttpSchemaRef
|
||||
|
||||
fixExternalHttpSchemaRef :: Text -> Text
|
||||
fixExternalHttpSchemaRef = \case
|
||||
(Text.stripPrefix "#/components/schemas/http" -> Just suffix) -> "http" <> suffix
|
||||
other -> other
|
||||
|
@ -113,7 +113,10 @@ deriving via Autodocodec Field instance ToSchema Field
|
||||
-- endpoint encoded as a list of JSON objects.
|
||||
newtype QueryResponse = QueryResponse {getQueryResponse :: [Object]}
|
||||
deriving newtype (Eq, Ord, Show, NFData)
|
||||
deriving (ToJSON, FromJSON, ToSchema) via Autodocodec [Object]
|
||||
deriving (ToJSON, FromJSON, ToSchema) via Autodocodec QueryResponse
|
||||
|
||||
instance HasCodec QueryResponse where
|
||||
codec = named "QueryResponse" $ dimapCodec QueryResponse getQueryResponse codec
|
||||
|
||||
$(makeLenses ''QueryRequest)
|
||||
$(makeLenses ''Query)
|
||||
|
@ -31,5 +31,5 @@ data Type
|
||||
|
||||
instance HasCodec Type where
|
||||
codec =
|
||||
named "Type" $
|
||||
named "ScalarType" $
|
||||
disjointStringConstCodec [(StringTy, "string"), (NumberTy, "number"), (BoolTy, "bool")]
|
||||
|
@ -42,7 +42,7 @@ import Data.Text.Extended
|
||||
import Data.Text.Lazy qualified as LT
|
||||
import Data.Text.Lazy.Encoding qualified as TL
|
||||
import GHC.Stats.Extended qualified as RTS
|
||||
import Hasura.Backends.DataConnector.API (openApiSchemaJson)
|
||||
import Hasura.Backends.DataConnector.API (openApiSchema)
|
||||
import Hasura.Backends.Postgres.Execute.Types
|
||||
import Hasura.Base.Error
|
||||
import Hasura.EncJSON
|
||||
@ -1078,7 +1078,7 @@ httpApp setupHook corsCfg serverCtx enableConsole consoleAssetsDir enableTelemet
|
||||
spockAction encodeQErr id $
|
||||
mkGetHandler $ do
|
||||
onlyAdmin
|
||||
return (emptyHttpLogMetadata @m, JSONResp $ HttpResponse (encJFromJValue openApiSchemaJson) [])
|
||||
return (emptyHttpLogMetadata @m, JSONResp $ HttpResponse (encJFromJValue openApiSchema) [])
|
||||
Spock.get "api/swagger/json" $
|
||||
spockAction encodeQErr id $
|
||||
mkGetHandler $ do
|
||||
|
@ -65,8 +65,8 @@ spec = do
|
||||
|]
|
||||
testToFromJSON val jsonVal
|
||||
|
||||
it "produces the correct OpenAPI Spec once external schema refs are fixed up" $
|
||||
fixExternalSchemaRefsInSchema (toJSON $ toSchema (Proxy @ConfigSchemaResponse))
|
||||
it "OpenAPI spec is as expected" $
|
||||
toJSON (toSchema (Proxy @ConfigSchemaResponse))
|
||||
`shouldBe` [aesonQQ|
|
||||
{
|
||||
"required": [
|
||||
@ -77,11 +77,11 @@ spec = do
|
||||
"nullable": false,
|
||||
"properties": {
|
||||
"configSchema": {
|
||||
"$ref": "https://raw.githubusercontent.com/OAI/OpenAPI-Specification/80c781e479f85ac67001ceb3e7e410e25d2a561b/schemas/v3.0/schema.json#/definitions/Schema"
|
||||
"$ref": "#/components/schemas/OpenApiSchema"
|
||||
},
|
||||
"otherSchemas": {
|
||||
"additionalProperties": {
|
||||
"$ref": "https://raw.githubusercontent.com/OAI/OpenAPI-Specification/80c781e479f85ac67001ceb3e7e410e25d2a561b/schemas/v3.0/schema.json#/definitions/Schema"
|
||||
"$ref": "#/components/schemas/OpenApiSchema"
|
||||
},
|
||||
"type": "object",
|
||||
"nullable": false
|
||||
|
@ -6,7 +6,7 @@ import Control.Monad ((>=>))
|
||||
import Data.Aeson.Text (encodeToLazyText)
|
||||
import Data.Proxy (Proxy (..))
|
||||
import Data.Text.Lazy.IO qualified as Text
|
||||
import Hasura.Backends.DataConnector.API (Routes (..), apiClient, openApiSchemaJson)
|
||||
import Hasura.Backends.DataConnector.API (Routes (..), apiClient, openApiSchema)
|
||||
import Hasura.Backends.DataConnector.API qualified as API
|
||||
import Network.HTTP.Client (defaultManagerSettings, newManager)
|
||||
import Servant.API (NamedRoutes)
|
||||
@ -38,7 +38,7 @@ main = do
|
||||
agentCapabilities <- getAgentCapabilities api _toAgentCapabilities
|
||||
runSpec (tests api testSourceName _toAgentConfig agentCapabilities) (applyTestConfig defaultConfig testOptions) >>= evaluateSummary
|
||||
ExportOpenAPISpec ->
|
||||
Text.putStrLn $ encodeToLazyText openApiSchemaJson
|
||||
Text.putStrLn $ encodeToLazyText openApiSchema
|
||||
|
||||
pure ()
|
||||
|
||||
|
@ -27,6 +27,7 @@ import Data.Aeson qualified as Aeson
|
||||
import Data.IORef qualified as I
|
||||
import Harness.Backend.DataConnector.MockAgent
|
||||
import Harness.GraphqlEngine qualified as GraphqlEngine
|
||||
import Harness.Http (healthCheck)
|
||||
import Harness.Quoter.Yaml (shouldReturnYaml, yaml)
|
||||
import Harness.Test.Context (BackendType (DataConnector), Options, defaultBackendTypeString)
|
||||
import Harness.TestEnvironment (TestEnvironment)
|
||||
@ -48,10 +49,11 @@ dataconnector:
|
||||
mockBackendConfig :: Aeson.Value
|
||||
mockBackendConfig =
|
||||
let backendType = defaultBackendTypeString $ DataConnector
|
||||
agentUri = "http://127.0.0.1:" <> show mockAgentPort <> "/"
|
||||
in [yaml|
|
||||
dataconnector:
|
||||
*backendType:
|
||||
uri: "http://127.0.0.1:65006/"
|
||||
uri: *agentUri
|
||||
|]
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
@ -114,6 +116,7 @@ mkLocalTestEnvironmentMock _ = do
|
||||
maeConfig <- I.newIORef chinookMock
|
||||
maeQuery <- I.newIORef Nothing
|
||||
maeThreadId <- forkIO $ runMockServer maeConfig maeQuery
|
||||
healthCheck $ "http://127.0.0.1:" <> show mockAgentPort <> "/healthz"
|
||||
pure $ MockAgentEnvironment {..}
|
||||
|
||||
-- | Load the agent schema into HGE.
|
||||
|
@ -1,6 +1,7 @@
|
||||
module Harness.Backend.DataConnector.MockAgent
|
||||
( MockConfig (..),
|
||||
chinookMock,
|
||||
mockAgentPort,
|
||||
runMockServer,
|
||||
)
|
||||
where
|
||||
@ -220,12 +221,22 @@ mockQueryHandler :: I.IORef MockConfig -> I.IORef (Maybe API.QueryRequest) -> AP
|
||||
mockQueryHandler mcfg mquery _sourceName _cfg query = liftIO $ do
|
||||
handler <- fmap _queryResponse $ I.readIORef mcfg
|
||||
I.writeIORef mquery (Just query)
|
||||
pure $ handler (error "WTF DUDE")
|
||||
pure $ handler query
|
||||
|
||||
dcMockableServer :: I.IORef MockConfig -> I.IORef (Maybe API.QueryRequest) -> Server API.Api
|
||||
dcMockableServer mcfg mquery = mockCapabilitiesHandler mcfg :<|> mockSchemaHandler mcfg :<|> mockQueryHandler mcfg mquery
|
||||
type HealthcheckApi =
|
||||
"healthz"
|
||||
:> Get '[JSON] ()
|
||||
|
||||
healthcheckHandler :: Handler ()
|
||||
healthcheckHandler = pure ()
|
||||
|
||||
dcMockableServer :: I.IORef MockConfig -> I.IORef (Maybe API.QueryRequest) -> Server (API.Api :<|> HealthcheckApi)
|
||||
dcMockableServer mcfg mquery = (mockCapabilitiesHandler mcfg :<|> mockSchemaHandler mcfg :<|> mockQueryHandler mcfg mquery) :<|> healthcheckHandler
|
||||
|
||||
mockAgentPort :: Warp.Port
|
||||
mockAgentPort = 65006
|
||||
|
||||
runMockServer :: I.IORef MockConfig -> I.IORef (Maybe API.QueryRequest) -> IO ()
|
||||
runMockServer mcfg mquery = do
|
||||
let app = serve (Proxy :: Proxy API.Api) $ dcMockableServer mcfg mquery
|
||||
Warp.run 65006 app
|
||||
let app = serve (Proxy :: Proxy (API.Api :<|> HealthcheckApi)) $ dcMockableServer mcfg mquery
|
||||
Warp.run mockAgentPort app
|
||||
|
Loading…
Reference in New Issue
Block a user