From 5003dc5d85d21d5042572071b22fad1654f36881 Mon Sep 17 00:00:00 2001 From: Dan Lynch Date: Wed, 6 May 2026 23:30:02 +0000 Subject: [PATCH 1/4] =?UTF-8?q?feat:=20per-table=20storage=20middleware=20?= =?UTF-8?q?=E2=80=94=20upload=20fields=20on=20bucket=20types,=20delete=20m?= =?UTF-8?q?iddleware=20on=20file=20tables?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace global requestUploadUrl/requestBulkUploadUrls mutations with per-table fields on @storageBuckets-tagged types. Replace global deleteFile mutation with middleware that wraps PostGraphile's generated delete* mutations on @storageFiles- tagged tables with S3 cleanup. Key changes: - plugin.ts: rewritten with GraphQLObjectType_fields hook for upload fields and GraphQLObjectType_fields_field hook for delete middleware - storage-module-cache.ts: add loadAllStorageModules() and resolveStorageConfigFromCodec() for codec-based scope resolution (no probing) - download-url-field.ts: use codec-based resolution instead of app-level only - s3-signer.ts: add deleteS3Object() function - upload.integration.test.ts: update to use per-table bucket query pattern - s3-signer.integration.test.ts: add deleteS3Object tests --- .../__tests__/s3-signer.integration.test.ts | 36 + .../src/download-url-field.ts | 17 +- .../src/index.ts | 11 +- .../src/plugin.ts | 751 ++++++++++-------- .../src/s3-signer.ts | 24 +- .../src/storage-module-cache.ts | 60 ++ .../__tests__/upload.integration.test.ts | 92 +-- 7 files changed, 591 insertions(+), 400 deletions(-) diff --git a/graphile/graphile-presigned-url-plugin/__tests__/s3-signer.integration.test.ts b/graphile/graphile-presigned-url-plugin/__tests__/s3-signer.integration.test.ts index 2474a1f3c..8890ac4d9 100644 --- a/graphile/graphile-presigned-url-plugin/__tests__/s3-signer.integration.test.ts +++ b/graphile/graphile-presigned-url-plugin/__tests__/s3-signer.integration.test.ts @@ -16,6 +16,7 @@ import { generatePresignedPutUrl, generatePresignedGetUrl, headObject, + deleteS3Object, } from '../src/s3-signer'; import type { S3Config } from '../src/types'; @@ -229,6 +230,41 @@ describe('s3-signer integration (MinIO)', () => { }); }); + describe('deleteS3Object', () => { + it('should delete an existing object from S3', async () => { + const key = 'test-delete-' + Date.now() + '.txt'; + const content = 'file to delete'; + const contentType = 'text/plain'; + + // Upload a file first + const putUrl = await generatePresignedPutUrl( + s3Config, + key, + contentType, + Buffer.byteLength(content), + ); + const putRes = await uploadToPresignedUrl(putUrl, content, contentType); + expect(putRes.status).toBe(200); + + // Verify it exists + const beforeHead = await headObject(s3Config, key); + expect(beforeHead).not.toBeNull(); + + // Delete it + await deleteS3Object(s3Config, key); + + // Verify it's gone + const afterHead = await headObject(s3Config, key); + expect(afterHead).toBeNull(); + }); + + it('should be idempotent (no error deleting non-existent key)', async () => { + await expect( + deleteS3Object(s3Config, 'non-existent-key-' + Date.now()), + ).resolves.toBeUndefined(); + }); + }); + describe('full round-trip: PUT → HEAD → GET', () => { it('should upload, verify, and download a text payload', async () => { const key = 'roundtrip-test-' + Date.now() + '.txt'; diff --git a/graphile/graphile-presigned-url-plugin/src/download-url-field.ts b/graphile/graphile-presigned-url-plugin/src/download-url-field.ts index 0a6f7abae..a58d3b07d 100644 --- a/graphile/graphile-presigned-url-plugin/src/download-url-field.ts +++ b/graphile/graphile-presigned-url-plugin/src/download-url-field.ts @@ -20,12 +20,13 @@ */ import type { GraphileConfig } from 'graphile-config'; +import 'graphile-build'; import { context as grafastContext, lambda, object } from 'grafast'; import { Logger } from '@pgpmjs/logger'; import type { PresignedUrlPluginOptions, S3Config, StorageModuleConfig } from './types'; import { generatePresignedGetUrl } from './s3-signer'; -import { getStorageModuleConfig } from './storage-module-cache'; +import { loadAllStorageModules, resolveStorageConfigFromCodec } from './storage-module-cache'; const log = new Logger('graphile-presigned-url:download-url'); @@ -110,6 +111,8 @@ export function createDownloadUrlPlugin( graphql: { GraphQLString }, } = build; + const capturedCodec = pgCodec; + return build.extend( fields, { @@ -121,12 +124,10 @@ export function createDownloadUrlPlugin( 'For private files, returns a time-limited presigned URL.', type: GraphQLString, plan($parent: any) { - // Access file attributes from the parent PgSelectSingleStep const $key = $parent.get('key'); const $isPublic = $parent.get('is_public'); const $filename = $parent.get('filename'); - // Access GraphQL context for per-database config resolution const $withPgClient = (grafastContext() as any).get('withPgClient'); const $pgSettings = (grafastContext() as any).get('pgSettings'); @@ -141,9 +142,8 @@ export function createDownloadUrlPlugin( return lambda($combined, async ({ key, isPublic, filename, withPgClient, pgSettings }: any) => { if (!key) return null; - // Resolve per-database config (bucket, publicUrlPrefix, expiry) - let s3ForDb = resolveS3(options); // fallback to global - let downloadUrlExpirySeconds = 3600; // fallback default + let s3ForDb = resolveS3(options); + let downloadUrlExpirySeconds = 3600; try { if (withPgClient && pgSettings) { const resolved = await withPgClient(null, async (pgClient: any) => { @@ -152,7 +152,8 @@ export function createDownloadUrlPlugin( }); const databaseId = dbResult.rows[0]?.id; if (!databaseId) return null; - const config = await getStorageModuleConfig(pgClient, databaseId); + const allConfigs = await loadAllStorageModules(pgClient, databaseId); + const config = resolveStorageConfigFromCodec(capturedCodec, allConfigs); if (!config) return null; return { config, databaseId }; }); @@ -166,11 +167,9 @@ export function createDownloadUrlPlugin( } if (isPublic && s3ForDb.publicUrlPrefix) { - // Public file: return direct CDN URL (per-database prefix) return `${s3ForDb.publicUrlPrefix}/${key}`; } - // Private file: generate presigned GET URL (per-database bucket) return generatePresignedGetUrl( s3ForDb, key, diff --git a/graphile/graphile-presigned-url-plugin/src/index.ts b/graphile/graphile-presigned-url-plugin/src/index.ts index b8b209222..94e3babc0 100644 --- a/graphile/graphile-presigned-url-plugin/src/index.ts +++ b/graphile/graphile-presigned-url-plugin/src/index.ts @@ -1,9 +1,10 @@ /** * Presigned URL Plugin for PostGraphile v5 * - * Provides presigned URL upload capabilities for PostGraphile v5: - * - requestUploadUrl mutation (presigned PUT URL generation + dedup) - * - downloadUrl computed field (presigned GET URL / public URL) + * Provides per-table S3 storage middleware for PostGraphile v5: + * - Upload fields on @storageBuckets types (requestUploadUrl, requestBulkUploadUrls) + * - Delete middleware on @storageFiles tables (S3 cleanup on delete) + * - downloadUrl computed field on @storageFiles types * * @example * ```typescript @@ -29,8 +30,8 @@ export { PresignedUrlPlugin, createPresignedUrlPlugin } from './plugin'; export { createDownloadUrlPlugin } from './download-url-field'; export { PresignedUrlPreset } from './preset'; -export { getStorageModuleConfig, getStorageModuleConfigForOwner, getBucketConfig, resolveStorageModuleByFileId, clearStorageModuleCache, clearBucketCache, isS3BucketProvisioned, markS3BucketProvisioned } from './storage-module-cache'; -export { generatePresignedPutUrl, generatePresignedGetUrl, headObject } from './s3-signer'; +export { getStorageModuleConfig, getStorageModuleConfigForOwner, getBucketConfig, resolveStorageModuleByFileId, loadAllStorageModules, resolveStorageConfigFromCodec, clearStorageModuleCache, clearBucketCache, isS3BucketProvisioned, markS3BucketProvisioned } from './storage-module-cache'; +export { generatePresignedPutUrl, generatePresignedGetUrl, deleteS3Object, headObject } from './s3-signer'; export type { BucketConfig, StorageModuleConfig, diff --git a/graphile/graphile-presigned-url-plugin/src/plugin.ts b/graphile/graphile-presigned-url-plugin/src/plugin.ts index 030095498..212943871 100644 --- a/graphile/graphile-presigned-url-plugin/src/plugin.ts +++ b/graphile/graphile-presigned-url-plugin/src/plugin.ts @@ -1,26 +1,29 @@ /** - * Presigned URL Plugin for PostGraphile v5 + * Per-Table Storage Middleware Plugin for PostGraphile v5 * - * Adds presigned URL upload support to PostGraphile v5: + * Hooks into PostGraphile's auto-generated CRUD mutations to add S3 operations: * - * 1. `requestUploadUrl` mutation — generates a presigned PUT URL for direct - * client-to-S3 upload. Checks bucket access via RLS, deduplicates by - * content hash via UNIQUE(bucket_id, key) constraint. + * 1. Delete middleware — wraps `delete*` mutations on `@storageFiles`-tagged tables + * with S3 object cleanup (sync + async GC fallback via AFTER DELETE trigger). * - * 2. `downloadUrl` computed field on File types — generates presigned GET URLs - * for private files, returns public URL prefix + key for public files. + * 2. Upload fields — adds `requestUploadUrl` and `requestBulkUploadUrls` fields + * on `@storageBuckets`-tagged types, so clients upload via the typed bucket API. * - * Uses the extendSchema + grafast plan pattern (same as PublicKeySignature). + * 3. downloadUrl — handled by download-url-field.ts (separate plugin). + * + * No global mutations — all S3 operations are scoped to the per-table types that + * PostGraphile already generates. Scope resolution uses the codec's schema/table + * name matched against cached storage module configs. */ import { context as grafastContext, lambda, object } from 'grafast'; import type { GraphileConfig } from 'graphile-config'; -import { extendSchema, gql } from 'graphile-utils'; +import 'graphile-build'; import { Logger } from '@pgpmjs/logger'; import type { PresignedUrlPluginOptions, S3Config, StorageModuleConfig, BucketConfig } from './types'; -import { getStorageModuleConfig, getStorageModuleConfigForOwner, getBucketConfig, isS3BucketProvisioned, markS3BucketProvisioned } from './storage-module-cache'; -import { generatePresignedPutUrl } from './s3-signer'; +import { loadAllStorageModules, resolveStorageConfigFromCodec, isS3BucketProvisioned, markS3BucketProvisioned } from './storage-module-cache'; +import { generatePresignedPutUrl, deleteS3Object } from './s3-signer'; const log = new Logger('graphile-presigned-url:plugin'); @@ -28,32 +31,20 @@ const log = new Logger('graphile-presigned-url:plugin'); const MAX_CONTENT_HASH_LENGTH = 128; const MAX_CONTENT_TYPE_LENGTH = 255; -const MAX_BUCKET_KEY_LENGTH = 255; const MAX_CUSTOM_KEY_LENGTH = 1024; const SHA256_HEX_REGEX = /^[a-f0-9]{64}$/; const CUSTOM_KEY_REGEX = /^[a-zA-Z0-9][a-zA-Z0-9_.\-\/]*$/; // --- Helpers --- -/** - * Validate a SHA-256 hex string. - */ function isValidSha256(hash: string): boolean { return SHA256_HEX_REGEX.test(hash); } -/** - * Build the S3 key from content hash. - * Format: {contentHash} (flat namespace, content-addressed) - */ function buildS3Key(contentHash: string): string { return contentHash; } -/** - * Validate a custom S3 key. - * Must be 1-1024 chars, no path traversal, no leading slash, no null bytes. - */ function validateCustomKey(key: string): string | null { if (key.length === 0 || key.length > MAX_CUSTOM_KEY_LENGTH) { return 'INVALID_KEY_LENGTH: must be 1-1024 characters'; @@ -73,11 +64,6 @@ function validateCustomKey(key: string): string | null { return null; } -/** - * Derive an ltree path from a custom S3 key's directory portion. - * e.g., "reports/2024/Q1/revenue.pdf" → "reports.2024.Q1" - * Returns null if the key has no directory component. - */ function derivePathFromKey(key: string): string | null { const lastSlash = key.lastIndexOf('/'); if (lastSlash <= 0) return null; @@ -85,12 +71,6 @@ function derivePathFromKey(key: string): string | null { return dir.replace(/\//g, '.'); } -/** - * Resolve the database_id from the JWT context. - * The server middleware sets jwt.claims.database_id, which is accessible - * via jwt_private.current_database_id() — a simple function call, no - * metaschema query needed. - */ async function resolveDatabaseId(pgClient: any): Promise { const result = await pgClient.query({ text: `SELECT jwt_private.current_database_id() AS id`, @@ -98,31 +78,15 @@ async function resolveDatabaseId(pgClient: any): Promise { return result.rows[0]?.id ?? null; } -// --- Plugin factory --- - -/** - * Resolve the S3 config from the options. If the option is a lazy getter - * function, call it (and cache the result). This avoids reading env vars - * or constructing an S3Client at module-import time. - */ function resolveS3(options: PresignedUrlPluginOptions): S3Config { if (typeof options.s3 === 'function') { const resolved = options.s3(); - // Cache so subsequent calls don't re-evaluate options.s3 = resolved; return resolved; } return options.s3; } -/** - * Build a per-database S3Config by overlaying storage_module overrides - * onto the global S3Config. - * - * - Bucket name: from resolveBucketName(databaseId) if provided, else global - * - publicUrlPrefix: from storageConfig.publicUrlPrefix if set, else global - * - S3 client (credentials, endpoint): always global (shared IAM key) - */ function resolveS3ForDatabase( options: PresignedUrlPluginOptions, storageConfig: StorageModuleConfig, @@ -145,16 +109,6 @@ function resolveS3ForDatabase( }; } -/** - * Ensure the S3 bucket for a database exists, provisioning it lazily if needed. - * - * Checks an in-memory Set of known-provisioned bucket names. On the first - * request for an unseen bucket, calls the `ensureBucketProvisioned` callback - * (which creates the bucket with correct CORS, policies, etc.), then marks - * it as provisioned so subsequent requests skip the check entirely. - * - * If no `ensureBucketProvisioned` callback is configured, this is a no-op. - */ async function ensureS3BucketExists( options: PresignedUrlPluginOptions, s3BucketName: string, @@ -171,288 +125,414 @@ async function ensureS3BucketExists( log.info(`Lazy-provisioned S3 bucket "${s3BucketName}" successfully`); } +// --- Plugin factory --- + export function createPresignedUrlPlugin( options: PresignedUrlPluginOptions, ): GraphileConfig.Plugin { - return extendSchema(() => ({ - typeDefs: gql` - input RequestUploadUrlInput { - """Bucket key (e.g., "public", "private")""" - bucketKey: String! - """ - Owner entity ID for entity-scoped uploads. - Omit for app-level (database-wide) storage. - When provided, resolves the storage module for the entity type - that owns this entity instance (e.g., a data room ID, team ID). - """ - ownerId: UUID - """SHA-256 content hash computed by the client (hex-encoded, 64 chars)""" - contentHash: String! - """MIME type of the file (e.g., "image/png")""" - contentType: String! - """File size in bytes""" - size: Int! - """Original filename (optional, for display and Content-Disposition)""" - filename: String - """ - Custom S3 key (e.g., "reports/2024/Q1.pdf"). - Only allowed when the bucket has allow_custom_keys=true. - When omitted, key defaults to contentHash (content-addressed dedup). - When provided, the file is stored at this key. - Re-uploading to an existing key auto-creates a new version. - """ - key: String - } - - type RequestUploadUrlPayload { - """Presigned PUT URL (null if file was deduplicated)""" - uploadUrl: String - """The file ID (existing if deduplicated, new if fresh upload)""" - fileId: UUID! - """The S3 object key""" - key: String! - """Whether this file was deduplicated (already exists with same hash)""" - deduplicated: Boolean! - """Presigned URL expiry time (null if deduplicated)""" - expiresAt: Datetime - """ID of the previous version (set when re-uploading to an existing custom key)""" - previousVersionId: UUID - } - - input BulkUploadFileInput { - """SHA-256 content hash computed by the client (hex-encoded, 64 chars)""" - contentHash: String! - """MIME type of the file (e.g., "image/png")""" - contentType: String! - """File size in bytes""" - size: Int! - """Original filename (optional, for display and Content-Disposition)""" - filename: String - """Custom S3 key (only when bucket has allow_custom_keys=true)""" - key: String - } - - input RequestBulkUploadUrlsInput { - """Bucket key (e.g., "public", "private")""" - bucketKey: String! - """Owner entity ID for entity-scoped uploads""" - ownerId: UUID - """Array of files to upload""" - files: [BulkUploadFileInput!]! - } - - type BulkUploadFilePayload { - """Presigned PUT URL (null if file was deduplicated)""" - uploadUrl: String - """The file ID""" - fileId: UUID! - """The S3 object key""" - key: String! - """Whether this file was deduplicated""" - deduplicated: Boolean! - """Presigned URL expiry time (null if deduplicated)""" - expiresAt: Datetime - """ID of the previous version (set when re-uploading to an existing custom key)""" - previousVersionId: UUID - """Index of this file in the input array (for client correlation)""" - index: Int! - } - - type RequestBulkUploadUrlsPayload { - """Array of results, one per input file""" - files: [BulkUploadFilePayload!]! - } - - extend type Mutation { - """ - Request a presigned URL for uploading a file directly to S3. - Client computes SHA-256 of the file content and provides it here. - If a file with the same hash already exists (dedup), returns the - existing file ID and deduplicated=true with no uploadUrl. - """ - requestUploadUrl( - input: RequestUploadUrlInput! - ): RequestUploadUrlPayload - - """ - Request presigned URLs for uploading multiple files in a single batch. - Subject to per-storage-module limits (max_bulk_files, max_bulk_total_size). - Each file is processed independently — some may dedup while others get fresh URLs. - """ - requestBulkUploadUrls( - input: RequestBulkUploadUrlsInput! - ): RequestBulkUploadUrlsPayload - } - `, - plans: { - Mutation: { - requestUploadUrl(_$mutation: any, fieldArgs: any) { - const $input = fieldArgs.getRaw('input'); - const $withPgClient = (grafastContext() as any).get('withPgClient'); - const $pgSettings = (grafastContext() as any).get('pgSettings'); - const $combined = object({ - input: $input, - withPgClient: $withPgClient, - pgSettings: $pgSettings, + return { + name: 'PresignedUrlPlugin', + version: '1.0.0', + description: 'Per-table S3 storage middleware: upload fields on @storageBuckets, delete middleware on @storageFiles', + + after: ['PgAttributesPlugin', 'PgMutationCreatePlugin', 'PgMutationUpdateDeletePlugin'], + + schema: { + hooks: { + /** + * Add requestUploadUrl and requestBulkUploadUrls fields on @storageBuckets types. + */ + GraphQLObjectType_fields(fields, build, context) { + const { + scope: { pgCodec, isPgClassType }, + } = context as any; + + if (!isPgClassType || !pgCodec || !pgCodec.attributes) { + return fields; + } + + const tags = (pgCodec.extensions as any)?.tags; + if (!tags?.storageBuckets) { + return fields; + } + + log.debug(`Adding upload fields to bucket type: ${pgCodec.name} (has @storageBuckets tag)`); + + const { + graphql: { + GraphQLString, + GraphQLNonNull, + GraphQLInt, + GraphQLBoolean, + GraphQLObjectType, + GraphQLList, + GraphQLInputObjectType, + }, + } = build; + + // --- Shared output types --- + + const UploadUrlPayloadType = new GraphQLObjectType({ + name: `${build.inflection.upperCamelCase(pgCodec.name)}RequestUploadUrlPayload`, + fields: { + uploadUrl: { type: GraphQLString, description: 'Presigned PUT URL (null if deduplicated)' }, + fileId: { type: new GraphQLNonNull(GraphQLString), description: 'The file ID' }, + key: { type: new GraphQLNonNull(GraphQLString), description: 'The S3 object key' }, + deduplicated: { type: new GraphQLNonNull(GraphQLBoolean), description: 'Whether this file was deduplicated' }, + expiresAt: { type: GraphQLString, description: 'Presigned URL expiry time (null if deduplicated)' }, + previousVersionId: { type: GraphQLString, description: 'ID of the previous version' }, + }, }); - return lambda($combined, async ({ input, withPgClient, pgSettings }: any) => { - const result = await processUpload(options, input, withPgClient, pgSettings); - return result; - }); - }, - requestBulkUploadUrls(_$mutation: any, fieldArgs: any) { - const $input = fieldArgs.getRaw('input'); - const $withPgClient = (grafastContext() as any).get('withPgClient'); - const $pgSettings = (grafastContext() as any).get('pgSettings'); - const $combined = object({ - input: $input, - withPgClient: $withPgClient, - pgSettings: $pgSettings, + const BulkUploadFilePayloadType = new GraphQLObjectType({ + name: `${build.inflection.upperCamelCase(pgCodec.name)}BulkUploadFilePayload`, + fields: { + uploadUrl: { type: GraphQLString }, + fileId: { type: new GraphQLNonNull(GraphQLString) }, + key: { type: new GraphQLNonNull(GraphQLString) }, + deduplicated: { type: new GraphQLNonNull(GraphQLBoolean) }, + expiresAt: { type: GraphQLString }, + previousVersionId: { type: GraphQLString }, + index: { type: new GraphQLNonNull(GraphQLInt), description: 'Index in the input array' }, + }, }); - return lambda($combined, async ({ input, withPgClient, pgSettings }: any) => { - const { bucketKey, ownerId, files } = input; - - if (!bucketKey || typeof bucketKey !== 'string' || bucketKey.length > MAX_BUCKET_KEY_LENGTH) { - throw new Error('INVALID_BUCKET_KEY'); - } - if (!Array.isArray(files) || files.length === 0) { - throw new Error('INVALID_FILES: must provide at least one file'); - } - - return withPgClient(pgSettings, async (pgClient: any) => { - return pgClient.withTransaction(async (txClient: any) => { - const databaseId = await resolveDatabaseId(txClient); - if (!databaseId) { - throw new Error('DATABASE_NOT_FOUND'); - } + const BulkUploadUrlsPayloadType = new GraphQLObjectType({ + name: `${build.inflection.upperCamelCase(pgCodec.name)}RequestBulkUploadUrlsPayload`, + fields: { + files: { type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(BulkUploadFilePayloadType))) }, + }, + }); - const storageConfig = ownerId - ? await getStorageModuleConfigForOwner(txClient, databaseId, ownerId) - : await getStorageModuleConfig(txClient, databaseId); - if (!storageConfig) { - throw new Error( - ownerId - ? 'STORAGE_MODULE_NOT_FOUND_FOR_OWNER: no storage module found for the given ownerId' - : 'STORAGE_MODULE_NOT_PROVISIONED', - ); - } + const BulkUploadFileInputType = new GraphQLInputObjectType({ + name: `${build.inflection.upperCamelCase(pgCodec.name)}BulkUploadFileInput`, + fields: { + contentHash: { type: new GraphQLNonNull(GraphQLString) }, + contentType: { type: new GraphQLNonNull(GraphQLString) }, + size: { type: new GraphQLNonNull(GraphQLInt) }, + filename: { type: GraphQLString }, + key: { type: GraphQLString }, + }, + }); - // --- Validate bulk limits --- - if (files.length > storageConfig.maxBulkFiles) { - throw new Error(`BULK_LIMIT_EXCEEDED: max ${storageConfig.maxBulkFiles} files per batch`); - } - const totalSize = files.reduce((sum: number, f: any) => sum + (f.size || 0), 0); - if (totalSize > storageConfig.maxBulkTotalSize) { - throw new Error(`BULK_SIZE_EXCEEDED: total size ${totalSize} exceeds max ${storageConfig.maxBulkTotalSize} bytes`); - } + // Capture codec for closure + const capturedCodec = pgCodec; + + return build.extend( + fields, + { + requestUploadUrl: context.fieldWithHooks( + { fieldName: 'requestUploadUrl' } as any, + { + description: 'Request a presigned URL for uploading a file to this bucket.', + type: UploadUrlPayloadType, + args: { + contentHash: { type: new GraphQLNonNull(GraphQLString), description: 'SHA-256 content hash (hex-encoded, 64 chars)' }, + contentType: { type: new GraphQLNonNull(GraphQLString), description: 'MIME type of the file' }, + size: { type: new GraphQLNonNull(GraphQLInt), description: 'File size in bytes' }, + filename: { type: GraphQLString, description: 'Original filename (optional)' }, + key: { type: GraphQLString, description: 'Custom S3 key (only when bucket has allow_custom_keys=true)' }, + }, + plan($parent: any, fieldArgs: any) { + const $bucketId = $parent.get('id'); + const $bucketKey = $parent.get('key'); + const $bucketType = $parent.get('type'); + const $bucketIsPublic = $parent.get('is_public'); + const $bucketAllowCustomKeys = $parent.get('allow_custom_keys'); + const $bucketAllowedMimeTypes = $parent.get('allowed_mime_types'); + const $bucketMaxFileSize = $parent.get('max_file_size'); + const $bucketOwnerId = capturedCodec.attributes.owner_id ? $parent.get('owner_id') : lambda(null, (): null => null); + + const $contentHash = fieldArgs.getRaw('contentHash'); + const $contentType = fieldArgs.getRaw('contentType'); + const $size = fieldArgs.getRaw('size'); + const $filename = fieldArgs.getRaw('filename'); + const $customKey = fieldArgs.getRaw('key'); + + const $withPgClient = (grafastContext() as any).get('withPgClient'); + const $pgSettings = (grafastContext() as any).get('pgSettings'); + + const $combined = object({ + bucketId: $bucketId, + bucketKey: $bucketKey, + bucketType: $bucketType, + bucketIsPublic: $bucketIsPublic, + bucketAllowCustomKeys: $bucketAllowCustomKeys, + bucketAllowedMimeTypes: $bucketAllowedMimeTypes, + bucketMaxFileSize: $bucketMaxFileSize, + bucketOwnerId: $bucketOwnerId, + contentHash: $contentHash, + contentType: $contentType, + size: $size, + filename: $filename, + customKey: $customKey, + withPgClient: $withPgClient, + pgSettings: $pgSettings, + }); + + return lambda($combined, async (vals: any) => { + return vals.withPgClient(vals.pgSettings, async (pgClient: any) => { + return pgClient.withTransaction(async (txClient: any) => { + const databaseId = await resolveDatabaseId(txClient); + if (!databaseId) throw new Error('DATABASE_NOT_FOUND'); + + const allConfigs = await loadAllStorageModules(txClient, databaseId); + const storageConfig = resolveStorageConfigFromCodec(capturedCodec, allConfigs); + if (!storageConfig) throw new Error('STORAGE_MODULE_NOT_FOUND'); + + const bucket: BucketConfig = { + id: vals.bucketId, + key: vals.bucketKey, + type: vals.bucketType, + is_public: vals.bucketIsPublic, + owner_id: vals.bucketOwnerId, + allowed_mime_types: vals.bucketAllowedMimeTypes, + max_file_size: vals.bucketMaxFileSize, + allow_custom_keys: vals.bucketAllowCustomKeys ?? false, + }; + + const s3ForDb = resolveS3ForDatabase(options, storageConfig, databaseId); + await ensureS3BucketExists(options, s3ForDb.bucket, bucket, databaseId, storageConfig.allowedOrigins); + + return processSingleFile( + options, txClient, storageConfig, databaseId, bucket, s3ForDb, { + contentHash: vals.contentHash, + contentType: vals.contentType, + size: vals.size, + filename: vals.filename, + key: vals.customKey, + }, + ); + }); + }); + }); + }, + }, + ), + requestBulkUploadUrls: context.fieldWithHooks( + { fieldName: 'requestBulkUploadUrls' } as any, + { + description: 'Request presigned URLs for uploading multiple files to this bucket.', + type: BulkUploadUrlsPayloadType, + args: { + files: { + type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(BulkUploadFileInputType))), + description: 'Array of files to upload', + }, + }, + plan($parent: any, fieldArgs: any) { + const $bucketId = $parent.get('id'); + const $bucketKey = $parent.get('key'); + const $bucketType = $parent.get('type'); + const $bucketIsPublic = $parent.get('is_public'); + const $bucketAllowCustomKeys = $parent.get('allow_custom_keys'); + const $bucketAllowedMimeTypes = $parent.get('allowed_mime_types'); + const $bucketMaxFileSize = $parent.get('max_file_size'); + const $bucketOwnerId = capturedCodec.attributes.owner_id ? $parent.get('owner_id') : lambda(null, (): null => null); + + const $files = fieldArgs.getRaw('files'); + const $withPgClient = (grafastContext() as any).get('withPgClient'); + const $pgSettings = (grafastContext() as any).get('pgSettings'); + + const $combined = object({ + bucketId: $bucketId, + bucketKey: $bucketKey, + bucketType: $bucketType, + bucketIsPublic: $bucketIsPublic, + bucketAllowCustomKeys: $bucketAllowCustomKeys, + bucketAllowedMimeTypes: $bucketAllowedMimeTypes, + bucketMaxFileSize: $bucketMaxFileSize, + bucketOwnerId: $bucketOwnerId, + files: $files, + withPgClient: $withPgClient, + pgSettings: $pgSettings, + }); + + return lambda($combined, async (vals: any) => { + const { files } = vals; + if (!Array.isArray(files) || files.length === 0) { + throw new Error('INVALID_FILES: must provide at least one file'); + } + + return vals.withPgClient(vals.pgSettings, async (pgClient: any) => { + return pgClient.withTransaction(async (txClient: any) => { + const databaseId = await resolveDatabaseId(txClient); + if (!databaseId) throw new Error('DATABASE_NOT_FOUND'); + + const allConfigs = await loadAllStorageModules(txClient, databaseId); + const storageConfig = resolveStorageConfigFromCodec(capturedCodec, allConfigs); + if (!storageConfig) throw new Error('STORAGE_MODULE_NOT_FOUND'); + + if (files.length > storageConfig.maxBulkFiles) { + throw new Error(`BULK_LIMIT_EXCEEDED: max ${storageConfig.maxBulkFiles} files per batch`); + } + const totalSize = files.reduce((sum: number, f: any) => sum + (f.size || 0), 0); + if (totalSize > storageConfig.maxBulkTotalSize) { + throw new Error(`BULK_SIZE_EXCEEDED: total size ${totalSize} exceeds max ${storageConfig.maxBulkTotalSize} bytes`); + } + + const bucket: BucketConfig = { + id: vals.bucketId, + key: vals.bucketKey, + type: vals.bucketType, + is_public: vals.bucketIsPublic, + owner_id: vals.bucketOwnerId, + allowed_mime_types: vals.bucketAllowedMimeTypes, + max_file_size: vals.bucketMaxFileSize, + allow_custom_keys: vals.bucketAllowCustomKeys ?? false, + }; + + const s3ForDb = resolveS3ForDatabase(options, storageConfig, databaseId); + await ensureS3BucketExists(options, s3ForDb.bucket, bucket, databaseId, storageConfig.allowedOrigins); + + const results = []; + for (let i = 0; i < files.length; i++) { + const result = await processSingleFile( + options, txClient, storageConfig, databaseId, bucket, s3ForDb, files[i], + ); + results.push({ ...result, index: i }); + } + + return { files: results }; + }); + }); + }); + }, + }, + ), + }, + `PresignedUrlPlugin adding upload fields to ${pgCodec.name}`, + ); + }, - const bucket = await getBucketConfig(txClient, storageConfig, databaseId, bucketKey, ownerId); - if (!bucket) { - throw new Error('BUCKET_NOT_FOUND'); + /** + * Wrap delete* mutations on @storageFiles-tagged tables with S3 cleanup. + * + * Pattern: identical to graphile-bucket-provisioner-plugin's create/update hooks. + * 1. Read the file row BEFORE delete (need key + bucket_id for S3 cleanup) + * 2. Call PostGraphile's generated delete (RLS enforced) + * 3. If delete succeeded, check refcount and attempt sync S3 delete + * 4. AFTER DELETE trigger (constructive-db) enqueues async GC job as fallback + */ + GraphQLObjectType_fields_field(field: any, build: any, context: any) { + const { + scope: { isRootMutation, fieldName, pgCodec }, + } = context; + + if (!isRootMutation || !pgCodec || !pgCodec.attributes) { + return field; + } + + const tags = pgCodec.extensions?.tags; + if (!tags?.storageFiles) { + return field; + } + + if (!fieldName.startsWith('delete')) { + return field; + } + + log.debug(`Wrapping delete mutation "${fieldName}" with S3 cleanup (codec: ${pgCodec.name})`); + + const defaultResolver = (obj: any) => obj[fieldName]; + const { resolve: oldResolve = defaultResolver, ...rest } = field; + const capturedCodec = pgCodec; + + return { + ...rest, + async resolve(source: any, args: any, graphqlContext: any, info: any) { + // Extract the file ID from the mutation input + const inputKey = Object.keys(args.input || {}).find( + (k) => k !== 'clientMutationId', + ); + const fileInput = inputKey ? args.input[inputKey] : null; + + let fileRow: { key: string; bucket_id: string } | null = null; + + if (fileInput) { + // Read the file row BEFORE delete to get the S3 key + bucket_id + const withPgClient = graphqlContext.withPgClient; + const pgSettings = graphqlContext.pgSettings; + + if (withPgClient) { + try { + await withPgClient(pgSettings, async (pgClient: any) => { + const databaseId = await resolveDatabaseId(pgClient); + if (!databaseId) return; + + const allConfigs = await loadAllStorageModules(pgClient, databaseId); + const storageConfig = resolveStorageConfigFromCodec(capturedCodec, allConfigs); + if (!storageConfig) return; + + // Read the file row (RLS enforced) + const result = await pgClient.query({ + text: `SELECT key, bucket_id FROM ${storageConfig.filesQualifiedName} WHERE id = $1 LIMIT 1`, + values: [fileInput], + }); + if (result.rows.length > 0) { + fileRow = result.rows[0] as { key: string; bucket_id: string }; + } + }); + } catch (err: any) { + log.warn(`Pre-delete file lookup failed: ${err.message}`); + } } - - // --- Ensure S3 bucket exists once for the batch --- - const s3ForDb = resolveS3ForDatabase(options, storageConfig, databaseId); - await ensureS3BucketExists(options, s3ForDb.bucket, bucket, databaseId, storageConfig.allowedOrigins); - - // --- Process each file --- - const results = []; - for (let i = 0; i < files.length; i++) { - const fileInput = files[i]; - const singleInput = { - ...fileInput, - bucketKey, - ownerId, - }; - const result = await processSingleFile( - options, txClient, storageConfig, databaseId, bucket, s3ForDb, singleInput, - ); - results.push({ ...result, index: i }); + } + + // Call PostGraphile's generated delete (RLS enforced) + const result = await oldResolve(source, args, graphqlContext, info); + + // Attempt sync S3 cleanup if we have the file row + if (fileRow) { + const withPgClient = graphqlContext.withPgClient; + const pgSettings = graphqlContext.pgSettings; + + if (withPgClient) { + try { + await withPgClient(pgSettings, async (pgClient: any) => { + const databaseId = await resolveDatabaseId(pgClient); + if (!databaseId) return; + + const allConfigs = await loadAllStorageModules(pgClient, databaseId); + const storageConfig = resolveStorageConfigFromCodec(capturedCodec, allConfigs); + if (!storageConfig) return; + + // Check refcount: any other file with the same key in this bucket? + const refResult = await pgClient.query({ + text: `SELECT COUNT(*)::int AS ref_count FROM ${storageConfig.filesQualifiedName} WHERE key = $1 AND bucket_id = $2`, + values: [fileRow!.key, fileRow!.bucket_id], + }); + const refCount = refResult.rows[0]?.ref_count ?? 0; + + if (refCount > 0) { + log.info(`File deleted from DB; S3 key ${fileRow!.key} still referenced by ${refCount} file(s)`); + return; + } + + // No other references — attempt sync S3 delete + const s3ForDb = resolveS3ForDatabase(options, storageConfig, databaseId); + await deleteS3Object(s3ForDb, fileRow!.key); + log.info(`Sync S3 delete succeeded for key=${fileRow!.key}`); + }); + } catch (err: any) { + // Sync S3 delete failed — the AFTER DELETE trigger has enqueued an async GC job + log.warn(`Sync S3 delete failed for key=${fileRow.key}; async GC job will retry: ${err.message}`); + } } + } - return { files: results }; - }); - }); - }); + return result; + }, + }; }, }, }, - })); + }; } // --- Shared upload logic --- -/** - * Process a single upload request (used by both requestUploadUrl and requestBulkUploadUrls). - */ -async function processUpload( - options: PresignedUrlPluginOptions, - input: any, - withPgClient: any, - pgSettings: any, -) { - const { bucketKey, ownerId, contentHash, contentType, size, filename, key: customKey } = input; - - if (!bucketKey || typeof bucketKey !== 'string' || bucketKey.length > MAX_BUCKET_KEY_LENGTH) { - throw new Error('INVALID_BUCKET_KEY'); - } - if (!contentHash || typeof contentHash !== 'string' || contentHash.length > MAX_CONTENT_HASH_LENGTH) { - throw new Error('INVALID_CONTENT_HASH'); - } - if (!isValidSha256(contentHash)) { - throw new Error('INVALID_CONTENT_HASH_FORMAT: must be a 64-char lowercase hex SHA-256'); - } - if (!contentType || typeof contentType !== 'string' || contentType.length > MAX_CONTENT_TYPE_LENGTH) { - throw new Error('INVALID_CONTENT_TYPE'); - } - - return withPgClient(pgSettings, async (pgClient: any) => { - return pgClient.withTransaction(async (txClient: any) => { - const databaseId = await resolveDatabaseId(txClient); - if (!databaseId) { - throw new Error('DATABASE_NOT_FOUND'); - } - - const storageConfig = ownerId - ? await getStorageModuleConfigForOwner(txClient, databaseId, ownerId) - : await getStorageModuleConfig(txClient, databaseId); - if (!storageConfig) { - throw new Error( - ownerId - ? 'STORAGE_MODULE_NOT_FOUND_FOR_OWNER: no storage module found for the given ownerId' - : 'STORAGE_MODULE_NOT_PROVISIONED', - ); - } - - if (typeof size !== 'number' || size <= 0 || size > storageConfig.defaultMaxFileSize) { - throw new Error(`INVALID_FILE_SIZE: must be between 1 and ${storageConfig.defaultMaxFileSize} bytes`); - } - if (filename !== undefined && filename !== null) { - if (typeof filename !== 'string' || filename.length > storageConfig.maxFilenameLength) { - throw new Error('INVALID_FILENAME'); - } - } - - const bucket = await getBucketConfig(txClient, storageConfig, databaseId, bucketKey, ownerId); - if (!bucket) { - throw new Error('BUCKET_NOT_FOUND'); - } - - const s3ForDb = resolveS3ForDatabase(options, storageConfig, databaseId); - await ensureS3BucketExists(options, s3ForDb.bucket, bucket, databaseId, storageConfig.allowedOrigins); - - return processSingleFile(options, txClient, storageConfig, databaseId, bucket, s3ForDb, input); - }); - }); -} - -/** - * Process a single file upload within an already-resolved context. - * Handles dedup, custom keys, versioning, and auto-path derivation. - */ async function processSingleFile( options: PresignedUrlPluginOptions, txClient: any, @@ -464,8 +544,10 @@ async function processSingleFile( ) { const { contentHash, contentType, size, filename, key: customKey } = input; - // --- Validate inputs --- - if (!contentHash || !isValidSha256(contentHash)) { + if (!contentHash || typeof contentHash !== 'string' || contentHash.length > MAX_CONTENT_HASH_LENGTH) { + throw new Error('INVALID_CONTENT_HASH'); + } + if (!isValidSha256(contentHash)) { throw new Error('INVALID_CONTENT_HASH_FORMAT: must be a 64-char lowercase hex SHA-256'); } if (!contentType || typeof contentType !== 'string' || contentType.length > MAX_CONTENT_TYPE_LENGTH) { @@ -480,7 +562,7 @@ async function processSingleFile( } } - // --- Validate content type against bucket's allowed_mime_types --- + // Validate content type against bucket's allowed_mime_types if (bucket.allowed_mime_types && bucket.allowed_mime_types.length > 0) { const allowed = bucket.allowed_mime_types as string[]; const isAllowed = allowed.some((pattern: string) => { @@ -496,12 +578,12 @@ async function processSingleFile( } } - // --- Validate size against bucket's max_file_size --- + // Validate size against bucket's max_file_size if (bucket.max_file_size && size > bucket.max_file_size) { throw new Error(`FILE_TOO_LARGE: exceeds bucket max of ${bucket.max_file_size} bytes`); } - // --- Determine S3 key --- + // Determine S3 key let s3Key: string; let isCustomKey = false; if (customKey) { @@ -518,12 +600,10 @@ async function processSingleFile( s3Key = buildS3Key(contentHash); } - // --- Dedup / versioning check --- + // Dedup / versioning check let previousVersionId: string | null = null; if (isCustomKey) { - // Custom key mode: check if a file with this key already exists in this bucket. - // If so, auto-version by linking via previous_version_id. const existingResult = await txClient.query({ text: `SELECT id, content_hash FROM ${storageConfig.filesQualifiedName} @@ -536,7 +616,6 @@ async function processSingleFile( if (existingResult.rows.length > 0) { const existing = existingResult.rows[0]; - // Same content hash = true dedup (no new upload needed) if (existing.content_hash === contentHash) { log.info(`Dedup hit (custom key): file ${existing.id} for key ${s3Key}`); return { @@ -548,12 +627,10 @@ async function processSingleFile( previousVersionId: null as string | null, }; } - // Different content = new version previousVersionId = existing.id; log.info(`Versioning: new version of key ${s3Key}, previous=${previousVersionId}`); } } else { - // Hash-based mode: dedup by content_hash in this bucket const dedupResult = await txClient.query({ text: `SELECT id FROM ${storageConfig.filesQualifiedName} @@ -578,29 +655,25 @@ async function processSingleFile( } } - // --- Auto-derive ltree path from custom key directory (only when has_path_shares) --- + // Auto-derive ltree path from custom key directory (only when has_path_shares) const derivedPath = isCustomKey && storageConfig.hasPathShares ? derivePathFromKey(s3Key) : null; - // --- Create file record --- + // Create file record const hasOwnerColumn = storageConfig.membershipType !== null; const columns = ['bucket_id', 'key', 'content_hash', 'mime_type', 'size', 'filename', 'is_public']; const values: any[] = [bucket.id, s3Key, contentHash, contentType, size, filename || null, bucket.is_public]; - let paramIdx = values.length; if (hasOwnerColumn) { columns.push('owner_id'); values.push(bucket.owner_id); - paramIdx = values.length; } if (previousVersionId) { columns.push('previous_version_id'); values.push(previousVersionId); - paramIdx = values.length; } if (derivedPath) { columns.push('path'); values.push(derivedPath); - paramIdx = values.length; } const placeholders = values.map((_: any, i: number) => `$${i + 1}`).join(', '); @@ -614,7 +687,7 @@ async function processSingleFile( const fileId = fileResult.rows[0].id; - // --- Generate presigned PUT URL --- + // Generate presigned PUT URL const uploadUrl = await generatePresignedPutUrl( s3ForDb, s3Key, diff --git a/graphile/graphile-presigned-url-plugin/src/s3-signer.ts b/graphile/graphile-presigned-url-plugin/src/s3-signer.ts index ded687974..c4fbba5d6 100644 --- a/graphile/graphile-presigned-url-plugin/src/s3-signer.ts +++ b/graphile/graphile-presigned-url-plugin/src/s3-signer.ts @@ -3,6 +3,7 @@ import { PutObjectCommand, GetObjectCommand, HeadObjectCommand, + DeleteObjectCommand, } from '@aws-sdk/client-s3'; import { getSignedUrl } from '@aws-sdk/s3-request-presigner'; import { Logger } from '@pgpmjs/logger'; @@ -78,9 +79,28 @@ export async function generatePresignedGetUrl( } /** - * Check if an object exists in S3 and optionally verify its content-type. + * Delete an object from S3. + * + * Idempotent — deleting a non-existent key is a no-op (S3 returns 204). * - * Checks whether an object exists in S3 and retrieves its content-type. + * @param s3Config - S3 client and bucket configuration + * @param key - S3 object key to delete + */ +export async function deleteS3Object( + s3Config: S3Config, + key: string, +): Promise { + await s3Config.client.send( + new DeleteObjectCommand({ + Bucket: s3Config.bucket, + Key: key, + }), + ); + log.debug(`Deleted S3 object: bucket=${s3Config.bucket}, key=${key}`); +} + +/** + * Check if an object exists in S3 and optionally verify its content-type. * * @param s3Config - S3 client and bucket configuration * @param key - S3 object key diff --git a/graphile/graphile-presigned-url-plugin/src/storage-module-cache.ts b/graphile/graphile-presigned-url-plugin/src/storage-module-cache.ts index 4ec64e5c4..cf1c7e482 100644 --- a/graphile/graphile-presigned-url-plugin/src/storage-module-cache.ts +++ b/graphile/graphile-presigned-url-plugin/src/storage-module-cache.ts @@ -321,6 +321,66 @@ export async function resolveStorageModuleByFileId( return null; } +/** + * Load all storage modules for a database, using the LRU cache. + * + * Returns an array of all StorageModuleConfig entries (app-level + entity-scoped). + * The result is cached per-database so subsequent calls avoid the DB query. + */ +export async function loadAllStorageModules( + pgClient: { query: (opts: { text: string; values?: unknown[] }) => Promise<{ rows: unknown[] }> }, + databaseId: string, +): Promise { + const cacheKey = `storage:${databaseId}:all-list`; + const cached = storageModuleCache.get(cacheKey); + if (cached) { + return (cached as any)._allConfigs as StorageModuleConfig[]; + } + + log.debug(`Loading all storage modules for database ${databaseId}`); + const result = await pgClient.query({ text: ALL_STORAGE_MODULES_QUERY, values: [databaseId] }); + const configs = (result.rows as StorageModuleRow[]).map(buildConfig); + + // Cache each individual config by its membership type + for (const config of configs) { + const key = config.membershipType === null + ? `storage:${databaseId}:app` + : `storage:${databaseId}:mt:${config.membershipType}`; + storageModuleCache.set(key, config); + } + + // Store the full list under a sentinel key + const sentinel = { ...configs[0] || {}, _allConfigs: configs } as any; + storageModuleCache.set(cacheKey, sentinel); + + return configs; +} + +/** + * Resolve the storage module config from a PostGraphile pgCodec. + * + * Matches the codec's schema + table name against cached storage modules. + * Works for both files codecs (@storageFiles) and buckets codecs (@storageBuckets). + * + * @param pgCodec - The PostGraphile codec (has extensions.pg.schemaName, name) + * @param allConfigs - All storage module configs for this database + * @returns The matching StorageModuleConfig or null + */ +export function resolveStorageConfigFromCodec( + pgCodec: { name: string; extensions?: { pg?: { schemaName?: string } }; sqlType?: string }, + allConfigs: StorageModuleConfig[], +): StorageModuleConfig | null { + const schemaName = pgCodec.extensions?.pg?.schemaName; + const tableName = pgCodec.name; + + if (!schemaName || !tableName) return null; + + return allConfigs.find((c) => + (c.filesTableName === tableName && c.schemaName === schemaName) || + (c.bucketsTableName === tableName && c.schemaName === schemaName), + ) || null; +} + // --- Bucket metadata cache --- /** diff --git a/graphql/server-test/__tests__/upload.integration.test.ts b/graphql/server-test/__tests__/upload.integration.test.ts index d9a07e529..bd7b26cf9 100644 --- a/graphql/server-test/__tests__/upload.integration.test.ts +++ b/graphql/server-test/__tests__/upload.integration.test.ts @@ -1,8 +1,8 @@ /** * Upload Integration Tests — end-to-end presigned URL flow * - * Exercises the full upload pipeline for both public and private files: - * requestUploadUrl → PUT to presigned URL → downloadUrl + * Exercises the per-table upload pipeline: + * query bucket → requestUploadUrl field → PUT to presigned URL → downloadUrl * * Uses real MinIO (available in CI as minio_cdn service) and lazy bucket * provisioning. No RLS — that will be tested in constructive-db. @@ -42,29 +42,31 @@ const seedFiles = [ // --- GraphQL operations --- const REQUEST_UPLOAD_URL = ` - mutation RequestUploadUrl($input: RequestUploadUrlInput!) { - requestUploadUrl(input: $input) { - uploadUrl - fileId - key - deduplicated - expiresAt + query RequestUploadUrl($key: String!, $contentHash: String!, $contentType: String!, $size: Int!, $filename: String) { + bucketByKey(key: $key) { + id + requestUploadUrl( + contentHash: $contentHash + contentType: $contentType + size: $size + filename: $filename + ) { + uploadUrl + fileId + key + deduplicated + expiresAt + } } } `; // --- Helpers --- -/** - * Generate a deterministic SHA-256 hex hash for test content. - */ function sha256(content: string): string { return crypto.createHash('sha256').update(content).digest('hex'); } -/** - * PUT file content to a presigned URL using fetch. - */ async function putToPresignedUrl( url: string, content: string, @@ -82,7 +84,7 @@ async function putToPresignedUrl( // --- Tests --- -describe('Upload integration (presigned URL flow)', () => { +describe('Upload integration (per-table presigned URL flow)', () => { let request: supertest.Agent; let teardown: () => Promise; @@ -118,31 +120,33 @@ describe('Upload integration (presigned URL flow)', () => { if (teardown) await teardown(); }); - describe('Public file upload', () => { + describe('Public file upload via bucket field', () => { const fileContent = 'Hello, public world!'; const contentType = 'text/plain'; const contentHash = sha256(fileContent); let uploadUrl: string; let fileId: string; - it('should return a presigned PUT URL via requestUploadUrl', async () => { + it('should return a presigned PUT URL via bucket.requestUploadUrl', async () => { const res = await postGraphQL({ query: REQUEST_UPLOAD_URL, variables: { - input: { - bucketKey: 'public', - contentHash, - contentType, - size: Buffer.byteLength(fileContent), - filename: 'hello-public.txt', - }, + key: 'public', + contentHash, + contentType, + size: Buffer.byteLength(fileContent), + filename: 'hello-public.txt', }, }); expect(res.status).toBe(200); expect(res.body.errors).toBeUndefined(); - const payload = res.body.data.requestUploadUrl; + const bucket = res.body.data.bucketByKey; + expect(bucket).toBeTruthy(); + expect(bucket.id).toBeTruthy(); + + const payload = bucket.requestUploadUrl; expect(payload.uploadUrl).toBeTruthy(); expect(payload.fileId).toBeTruthy(); expect(payload.key).toBe(contentHash); @@ -159,31 +163,32 @@ describe('Upload integration (presigned URL flow)', () => { }); }); - describe('Private file upload', () => { + describe('Private file upload via bucket field', () => { const fileContent = 'Hello, private world!'; const contentType = 'text/plain'; const contentHash = sha256(fileContent); let uploadUrl: string; let fileId: string; - it('should return a presigned PUT URL via requestUploadUrl', async () => { + it('should return a presigned PUT URL via bucket.requestUploadUrl', async () => { const res = await postGraphQL({ query: REQUEST_UPLOAD_URL, variables: { - input: { - bucketKey: 'private', - contentHash, - contentType, - size: Buffer.byteLength(fileContent), - filename: 'hello-private.txt', - }, + key: 'private', + contentHash, + contentType, + size: Buffer.byteLength(fileContent), + filename: 'hello-private.txt', }, }); expect(res.status).toBe(200); expect(res.body.errors).toBeUndefined(); - const payload = res.body.data.requestUploadUrl; + const bucket = res.body.data.bucketByKey; + expect(bucket).toBeTruthy(); + + const payload = bucket.requestUploadUrl; expect(payload.uploadUrl).toBeTruthy(); expect(payload.fileId).toBeTruthy(); expect(payload.key).toBe(contentHash); @@ -202,27 +207,24 @@ describe('Upload integration (presigned URL flow)', () => { describe('Deduplication', () => { it('should return deduplicated=true for a file with an existing content hash', async () => { - // Re-request the same public file content hash const fileContent = 'Hello, public world!'; const contentHash = sha256(fileContent); const res = await postGraphQL({ query: REQUEST_UPLOAD_URL, variables: { - input: { - bucketKey: 'public', - contentHash, - contentType: 'text/plain', - size: Buffer.byteLength(fileContent), - filename: 'hello-public-copy.txt', - }, + key: 'public', + contentHash, + contentType: 'text/plain', + size: Buffer.byteLength(fileContent), + filename: 'hello-public-copy.txt', }, }); expect(res.status).toBe(200); expect(res.body.errors).toBeUndefined(); - const payload = res.body.data.requestUploadUrl; + const payload = res.body.data.bucketByKey.requestUploadUrl; expect(payload.deduplicated).toBe(true); expect(payload.uploadUrl).toBeNull(); expect(payload.expiresAt).toBeNull(); From 21bd5b5949f0d1d96641778ba8c7be002653dc9c Mon Sep 17 00:00:00 2001 From: Dan Lynch Date: Wed, 6 May 2026 23:32:43 +0000 Subject: [PATCH 2/4] feat: update upload-client for per-table bucket query pattern - queries.ts: replace global mutation with buildRequestUploadUrlQuery() builder - upload.ts: query bucket by key, extract upload payload from nested response - types.ts: add bucketQueryField option, replace status with previousVersionId - index.ts: export new query builder + DEFAULT_BUCKET_QUERY_FIELD - upload.test.ts: mock executor returns per-table nested bucket response --- .../upload-client/__tests__/upload.test.ts | 209 ++++++++++-------- packages/upload-client/src/index.ts | 4 +- packages/upload-client/src/queries.ts | 54 ++++- packages/upload-client/src/types.ts | 12 +- packages/upload-client/src/upload.ts | 34 ++- 5 files changed, 188 insertions(+), 125 deletions(-) diff --git a/packages/upload-client/__tests__/upload.test.ts b/packages/upload-client/__tests__/upload.test.ts index 445917e80..9c1e8dcfe 100644 --- a/packages/upload-client/__tests__/upload.test.ts +++ b/packages/upload-client/__tests__/upload.test.ts @@ -1,6 +1,6 @@ import { uploadFile } from '../src/upload'; import { UploadError } from '../src/types'; -import { REQUEST_UPLOAD_URL_MUTATION } from '../src/queries'; +import { DEFAULT_BUCKET_QUERY_FIELD } from '../src/queries'; import type { GraphQLExecutor, FileInput } from '../src/types'; /** @@ -34,7 +34,6 @@ const HELLO_WORLD_HASH = 'b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7 const originalFetch = global.fetch; beforeEach(() => { - // Reset fetch mock before each test global.fetch = originalFetch; }); @@ -42,32 +41,40 @@ afterAll(() => { global.fetch = originalFetch; }); +/** + * Build a mock executor that returns data nested under the bucket query field. + * The per-table pattern returns: { bucketByKey: { requestUploadUrl: { ... } } } + */ +function createMockExecutor( + payload: Record, + bucketQueryField = DEFAULT_BUCKET_QUERY_FIELD, +): { execute: GraphQLExecutor; calls: Array<{ query: string; variables: Record }> } { + const calls: Array<{ query: string; variables: Record }> = []; + const execute: GraphQLExecutor = async (query, variables) => { + calls.push({ query, variables }); + return { + [bucketQueryField]: { + id: 'bucket-uuid', + requestUploadUrl: payload, + }, + }; + }; + return { execute, calls }; +} + describe('uploadFile', () => { describe('fresh upload (not deduplicated)', () => { - it('should hash, request URL, and PUT to S3', async () => { + it('should hash, request URL via bucket field, and PUT to S3', async () => { const file = createMockFile('hello world'); - const executeCalls: Array<{ query: string; variables: Record }> = []; - - const execute: GraphQLExecutor = async (query, variables) => { - executeCalls.push({ query, variables }); - - if (query === REQUEST_UPLOAD_URL_MUTATION) { - return { - requestUploadUrl: { - uploadUrl: 'https://s3.example.com/presigned-put-url', - fileId: 'file-uuid-123', - key: HELLO_WORLD_HASH, - deduplicated: false, - expiresAt: new Date(Date.now() + 900_000).toISOString(), - status: 'requested', - }, - }; - } - - throw new Error(`Unexpected query: ${query}`); - }; + const { execute, calls } = createMockExecutor({ + uploadUrl: 'https://s3.example.com/presigned-put-url', + fileId: 'file-uuid-123', + key: HELLO_WORLD_HASH, + deduplicated: false, + expiresAt: new Date(Date.now() + 900_000).toISOString(), + previousVersionId: null, + }); - // Mock fetch for S3 PUT global.fetch = jest.fn().mockResolvedValue({ ok: true, status: 200, @@ -80,20 +87,19 @@ describe('uploadFile', () => { execute, }); - // Verify result expect(result.fileId).toBe('file-uuid-123'); expect(result.key).toBe(HELLO_WORLD_HASH); expect(result.deduplicated).toBe(false); - expect(result.status).toBe('requested'); - // Verify requestUploadUrl was called with correct input - expect(executeCalls[0].query).toBe(REQUEST_UPLOAD_URL_MUTATION); - const requestInput = (executeCalls[0].variables.input as Record); - expect(requestInput.bucketKey).toBe('avatars'); - expect(requestInput.contentHash).toBe(HELLO_WORLD_HASH); - expect(requestInput.contentType).toBe('text/plain'); - expect(requestInput.size).toBe(11); - expect(requestInput.filename).toBe('test.txt'); + // Verify per-table query was called with flat variables (not input object) + expect(calls).toHaveLength(1); + expect(calls[0].query).toContain('bucketByKey'); + expect(calls[0].query).toContain('requestUploadUrl'); + expect(calls[0].variables.key).toBe('avatars'); + expect(calls[0].variables.contentHash).toBe(HELLO_WORLD_HASH); + expect(calls[0].variables.contentType).toBe('text/plain'); + expect(calls[0].variables.size).toBe(11); + expect(calls[0].variables.filename).toBe('test.txt'); // Verify S3 PUT was called expect(global.fetch).toHaveBeenCalledWith( @@ -103,35 +109,20 @@ describe('uploadFile', () => { headers: { 'Content-Type': 'text/plain' }, }), ); - - // Only requestUploadUrl should have been called (no confirm step) - expect(executeCalls).toHaveLength(1); }); }); describe('deduplicated upload', () => { - it('should skip PUT and confirm when deduplicated', async () => { + it('should skip PUT when deduplicated', async () => { const file = createMockFile('hello world'); - const executeCalls: Array<{ query: string }> = []; - - const execute: GraphQLExecutor = async (query) => { - executeCalls.push({ query }); - - if (query === REQUEST_UPLOAD_URL_MUTATION) { - return { - requestUploadUrl: { - uploadUrl: null, - fileId: 'existing-file-uuid', - key: HELLO_WORLD_HASH, - deduplicated: true, - expiresAt: null, - status: 'ready', - }, - }; - } - - throw new Error(`Unexpected query after dedup: ${query}`); - }; + const { execute, calls } = createMockExecutor({ + uploadUrl: null, + fileId: 'existing-file-uuid', + key: HELLO_WORLD_HASH, + deduplicated: true, + expiresAt: null, + previousVersionId: null, + }); global.fetch = jest.fn(); @@ -143,15 +134,44 @@ describe('uploadFile', () => { expect(result.fileId).toBe('existing-file-uuid'); expect(result.deduplicated).toBe(true); - expect(result.status).toBe('ready'); - // Only requestUploadUrl should have been called (no PUT) - expect(executeCalls).toHaveLength(1); - expect(executeCalls[0].query).toBe(REQUEST_UPLOAD_URL_MUTATION); + expect(calls).toHaveLength(1); expect(global.fetch).not.toHaveBeenCalled(); }); }); + describe('custom bucketQueryField', () => { + it('should use the provided bucket query field name', async () => { + const file = createMockFile('hello world'); + const { execute, calls } = createMockExecutor( + { + uploadUrl: 'https://s3.example.com/put', + fileId: 'file-1', + key: HELLO_WORLD_HASH, + deduplicated: false, + expiresAt: new Date().toISOString(), + previousVersionId: null, + }, + 'appBucketByKey', + ); + + global.fetch = jest.fn().mockResolvedValue({ + ok: true, + status: 200, + text: async () => '', + }); + + await uploadFile({ + file, + bucketKey: 'private', + execute, + bucketQueryField: 'appBucketByKey', + }); + + expect(calls[0].query).toContain('appBucketByKey'); + }); + }); + describe('error handling', () => { it('should throw INVALID_FILE for null file', async () => { const execute: GraphQLExecutor = jest.fn(); @@ -168,7 +188,7 @@ describe('uploadFile', () => { ).rejects.toMatchObject({ code: 'INVALID_FILE' }); }); - it('should throw REQUEST_UPLOAD_URL_FAILED when mutation fails', async () => { + it('should throw REQUEST_UPLOAD_URL_FAILED when query fails', async () => { const file = createMockFile('test'); const execute: GraphQLExecutor = async () => { throw new Error('Network error'); @@ -179,24 +199,28 @@ describe('uploadFile', () => { ).rejects.toMatchObject({ code: 'REQUEST_UPLOAD_URL_FAILED' }); }); - it('should throw PUT_UPLOAD_FAILED when S3 returns error', async () => { + it('should throw REQUEST_UPLOAD_URL_FAILED when bucket not found', async () => { const file = createMockFile('test'); - const execute: GraphQLExecutor = async (query) => { - if (query === REQUEST_UPLOAD_URL_MUTATION) { - return { - requestUploadUrl: { - uploadUrl: 'https://s3.example.com/put', - fileId: 'file-1', - key: 'hash', - deduplicated: false, - expiresAt: new Date().toISOString(), - status: 'requested', - }, - }; - } - throw new Error('Unexpected'); + const execute: GraphQLExecutor = async () => { + return { bucketByKey: null } as any; }; + await expect( + uploadFile({ file, bucketKey: 'nonexistent', execute }), + ).rejects.toMatchObject({ code: 'REQUEST_UPLOAD_URL_FAILED' }); + }); + + it('should throw PUT_UPLOAD_FAILED when S3 returns error', async () => { + const file = createMockFile('test'); + const { execute } = createMockExecutor({ + uploadUrl: 'https://s3.example.com/put', + fileId: 'file-1', + key: 'hash', + deduplicated: false, + expiresAt: new Date().toISOString(), + previousVersionId: null, + }); + global.fetch = jest.fn().mockResolvedValue({ ok: false, status: 403, @@ -225,24 +249,14 @@ describe('uploadFile', () => { describe('content type handling', () => { it('should use application/octet-stream when file.type is empty', async () => { const file = createMockFile('binary data', 'file.bin', ''); - const executeCalls: Array<{ query: string; variables: Record }> = []; - - const execute: GraphQLExecutor = async (query, variables) => { - executeCalls.push({ query, variables }); - if (query === REQUEST_UPLOAD_URL_MUTATION) { - return { - requestUploadUrl: { - uploadUrl: 'https://s3.example.com/put', - fileId: 'file-1', - key: 'hash', - deduplicated: false, - expiresAt: new Date().toISOString(), - status: 'requested', - }, - }; - } - throw new Error('Unexpected'); - }; + const { execute, calls } = createMockExecutor({ + uploadUrl: 'https://s3.example.com/put', + fileId: 'file-1', + key: 'hash', + deduplicated: false, + expiresAt: new Date().toISOString(), + previousVersionId: null, + }); global.fetch = jest.fn().mockResolvedValue({ ok: true, @@ -252,8 +266,7 @@ describe('uploadFile', () => { await uploadFile({ file, bucketKey: 'test', execute }); - const requestInput = (executeCalls[0].variables.input as Record); - expect(requestInput.contentType).toBe('application/octet-stream'); + expect(calls[0].variables.contentType).toBe('application/octet-stream'); }); }); }); diff --git a/packages/upload-client/src/index.ts b/packages/upload-client/src/index.ts index 6689f2a2d..6bd562d64 100644 --- a/packages/upload-client/src/index.ts +++ b/packages/upload-client/src/index.ts @@ -32,8 +32,8 @@ export { hashFile, hashFileChunked } from './hash'; // Orchestrator export { uploadFile } from './upload'; -// GraphQL query strings (for custom integrations) -export { REQUEST_UPLOAD_URL_MUTATION } from './queries'; +// GraphQL query builders (for custom integrations) +export { buildRequestUploadUrlQuery, REQUEST_UPLOAD_URL_QUERY, REQUEST_UPLOAD_URL_MUTATION, DEFAULT_BUCKET_QUERY_FIELD } from './queries'; // Types export type { diff --git a/packages/upload-client/src/queries.ts b/packages/upload-client/src/queries.ts index a95618f3b..54262d38d 100644 --- a/packages/upload-client/src/queries.ts +++ b/packages/upload-client/src/queries.ts @@ -1,19 +1,51 @@ /** - * GraphQL mutation strings for the presigned URL upload pipeline. + * GraphQL query builders for the per-table presigned URL upload pipeline. * * These are plain strings — no graphql-tag dependency needed. - * They match the schema defined in graphile-presigned-url-plugin. + * They match the per-table schema defined in graphile-presigned-url-plugin: + * upload fields are on bucket types (via @storageBuckets smart tag), + * not global mutations. */ -export const REQUEST_UPLOAD_URL_MUTATION = ` - mutation RequestUploadUrl($input: RequestUploadUrlInput!) { - requestUploadUrl(input: $input) { - uploadUrl - fileId - key - deduplicated - expiresAt - status +/** + * Build the GraphQL query for requesting an upload URL from a specific bucket type. + * + * The query fetches a bucket by key from the per-table PostGraphile type, + * then calls the requestUploadUrl field on that bucket instance. + * + * @param bucketQueryField - The PostGraphile query field name for the bucket type + * (e.g., "bucketByKey", "appBucketByKey", "dataRoomBucketByKeyAndOwnerId") + */ +export function buildRequestUploadUrlQuery(bucketQueryField: string): string { + return ` + query RequestUploadUrl($key: String!, $contentHash: String!, $contentType: String!, $size: Int!, $filename: String) { + ${bucketQueryField}(key: $key) { + id + requestUploadUrl( + contentHash: $contentHash + contentType: $contentType + size: $size + filename: $filename + ) { + uploadUrl + fileId + key + deduplicated + expiresAt + } } } `; +} + +/** Default query field for app-level buckets */ +export const DEFAULT_BUCKET_QUERY_FIELD = 'bucketByKey'; + +/** Pre-built query for the default bucket type */ +export const REQUEST_UPLOAD_URL_QUERY = buildRequestUploadUrlQuery(DEFAULT_BUCKET_QUERY_FIELD); + +/** + * @deprecated Use REQUEST_UPLOAD_URL_QUERY instead. + * Kept for backward compatibility during migration. + */ +export const REQUEST_UPLOAD_URL_MUTATION = REQUEST_UPLOAD_URL_QUERY; diff --git a/packages/upload-client/src/types.ts b/packages/upload-client/src/types.ts index fab10051a..ac0b3094b 100644 --- a/packages/upload-client/src/types.ts +++ b/packages/upload-client/src/types.ts @@ -32,8 +32,8 @@ export interface RequestUploadUrlPayload { deduplicated: boolean; /** Presigned URL expiry time (ISO string, null if deduplicated) */ expiresAt: string | null; - /** File status — 'requested' for fresh uploads, 'uploaded'/'processed' for deduplicated files */ - status: string; + /** ID of the previous version (when uploading a new version of a custom-keyed file) */ + previousVersionId: string | null; } // --- Client options --- @@ -69,6 +69,12 @@ export interface UploadFileOptions { bucketKey: string; /** GraphQL executor function */ execute: GraphQLExecutor; + /** + * PostGraphile query field for the bucket type (e.g., "bucketByKey", "appBucketByKey"). + * Defaults to "bucketByKey". Override for entity-scoped storage modules where the + * bucket table has a different PostGraphile-inflected name. + */ + bucketQueryField?: string; /** Progress callback (0-100) — only fires during the S3 PUT */ onProgress?: (percent: number) => void; /** AbortSignal for cancellation */ @@ -82,8 +88,6 @@ export interface UploadResult { key: string; /** Whether this file was deduplicated (no bytes uploaded) */ deduplicated: boolean; - /** File status after upload ("requested" for fresh uploads, existing status for dedup) */ - status: string; } // --- File input abstraction --- diff --git a/packages/upload-client/src/upload.ts b/packages/upload-client/src/upload.ts index 69599c969..6a1c2fd59 100644 --- a/packages/upload-client/src/upload.ts +++ b/packages/upload-client/src/upload.ts @@ -8,7 +8,7 @@ */ import { hashFile } from './hash'; -import { REQUEST_UPLOAD_URL_MUTATION } from './queries'; +import { buildRequestUploadUrlQuery, DEFAULT_BUCKET_QUERY_FIELD } from './queries'; import { UploadError } from './types'; import type { UploadFileOptions, @@ -40,7 +40,7 @@ import type { * ``` */ export async function uploadFile(options: UploadFileOptions): Promise { - const { file, bucketKey, execute, onProgress, signal } = options; + const { file, bucketKey, execute, onProgress, signal, bucketQueryField } = options; // --- Validate input --- if (!file) { @@ -60,8 +60,9 @@ export async function uploadFile(options: UploadFileOptions): Promise { + const query = buildRequestUploadUrlQuery(bucketQueryField); + try { - const data = await execute(REQUEST_UPLOAD_URL_MUTATION, { input }); - const payload = data.requestUploadUrl as RequestUploadUrlPayload | undefined; + const data = await execute(query, { + key: input.bucketKey, + contentHash: input.contentHash, + contentType: input.contentType, + size: input.size, + filename: input.filename, + }); + + // Extract from the nested bucket response: { bucketByKey: { requestUploadUrl: { ... } } } + const bucketData = data[bucketQueryField] as Record | undefined; + if (!bucketData) { + throw new UploadError('REQUEST_UPLOAD_URL_FAILED', `Bucket not found for query field "${bucketQueryField}"`); + } + const payload = bucketData.requestUploadUrl as RequestUploadUrlPayload | undefined; if (!payload) { throw new UploadError('REQUEST_UPLOAD_URL_FAILED', 'No data returned from requestUploadUrl'); } @@ -130,7 +144,7 @@ async function requestUploadUrl( if (err instanceof UploadError) throw err; throw new UploadError( 'REQUEST_UPLOAD_URL_FAILED', - `requestUploadUrl mutation failed: ${err instanceof Error ? err.message : String(err)}`, + `requestUploadUrl query failed: ${err instanceof Error ? err.message : String(err)}`, err, ); } From 9d5b07174e59d8caa0b11992bfaefdbdc18b05e1 Mon Sep 17 00:00:00 2001 From: Dan Lynch Date: Thu, 7 May 2026 00:15:59 +0000 Subject: [PATCH 3/4] fix: use collection query in upload test, regenerate snapshots MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Replace bucketByKey (disabled by NoUniqueLookupPreset) with buckets(condition: { key: $key }) { nodes { ... } } collection query - Delete stale schema snapshots that referenced removed global mutations (requestUploadUrl, requestBulkUploadUrls) — jest will regenerate them --- .../schema-snapshot.test.ts.snap | 2529 --------- .../__tests__/upload.integration.test.ts | 34 +- .../__snapshots__/graphile-test.test.ts.snap | 5028 ----------------- 3 files changed, 18 insertions(+), 7573 deletions(-) delete mode 100644 graphql/server-test/__tests__/__snapshots__/schema-snapshot.test.ts.snap delete mode 100644 graphql/test/__tests__/__snapshots__/graphile-test.test.ts.snap diff --git a/graphql/server-test/__tests__/__snapshots__/schema-snapshot.test.ts.snap b/graphql/server-test/__tests__/__snapshots__/schema-snapshot.test.ts.snap deleted file mode 100644 index dec27269b..000000000 --- a/graphql/server-test/__tests__/__snapshots__/schema-snapshot.test.ts.snap +++ /dev/null @@ -1,2529 +0,0 @@ -// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing - -exports[`Schema Snapshot should generate consistent GraphQL SDL from the test schema 1`] = ` -""""A connection to a list of \`PostTag\` values.""" -type PostTagConnection { - """A list of \`PostTag\` objects.""" - nodes: [PostTag]! - - """ - A list of edges which contains the \`PostTag\` and cursor to aid in pagination. - """ - edges: [PostTagEdge]! - - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """The count of *all* \`PostTag\` you could get from the connection.""" - totalCount: Int! -} - -type PostTag { - id: UUID! - postId: UUID! - tagId: UUID! - createdAt: Datetime - - """Reads a single \`Post\` that is related to this \`PostTag\`.""" - post: Post - - """Reads a single \`Tag\` that is related to this \`PostTag\`.""" - tag: Tag -} - -""" -A universally unique identifier as defined by [RFC 4122](https://tools.ietf.org/html/rfc4122). -""" -scalar UUID - -""" -A point in time as described by the [ISO -8601](https://en.wikipedia.org/wiki/ISO_8601) and, if it has a timezone, [RFC -3339](https://datatracker.ietf.org/doc/html/rfc3339) standards. Input values -that do not conform to both ISO 8601 and RFC 3339 may be coerced, which may lead -to unexpected results. -""" -scalar Datetime - -type Post { - id: UUID! - authorId: UUID! - title: String! - slug: String! - content: String - excerpt: String - isPublished: Boolean - publishedAt: Datetime - viewCount: Int - createdAt: Datetime - updatedAt: Datetime - - """Reads and enables pagination through a set of \`Tag\`.""" - tags( - """Only read the first \`n\` values of the set.""" - first: Int - - """Only read the last \`n\` values of the set.""" - last: Int - - """ - Skip the first \`n\` values from our \`after\` cursor, an alternative to cursor - based pagination. May not be used with \`last\`. - """ - offset: Int - - """Read all values in the set before (above) this cursor.""" - before: Cursor - - """Read all values in the set after (below) this cursor.""" - after: Cursor - - """ - A filter to be used in determining which values should be returned by the collection. - """ - where: TagFilter - - """The method to use when ordering \`Tag\`.""" - orderBy: [TagOrderBy!] = [PRIMARY_KEY_ASC] - ): PostTagsManyToManyConnection! - - """Reads a single \`User\` that is related to this \`Post\`.""" - author: User - - """Reads and enables pagination through a set of \`PostTag\`.""" - postTags( - """Only read the first \`n\` values of the set.""" - first: Int - - """Only read the last \`n\` values of the set.""" - last: Int - - """ - Skip the first \`n\` values from our \`after\` cursor, an alternative to cursor - based pagination. May not be used with \`last\`. - """ - offset: Int - - """Read all values in the set before (above) this cursor.""" - before: Cursor - - """Read all values in the set after (below) this cursor.""" - after: Cursor - - """ - A filter to be used in determining which values should be returned by the collection. - """ - where: PostTagFilter - - """The method to use when ordering \`PostTag\`.""" - orderBy: [PostTagOrderBy!] = [PRIMARY_KEY_ASC] - ): PostTagConnection! - - """Reads and enables pagination through a set of \`Comment\`.""" - comments( - """Only read the first \`n\` values of the set.""" - first: Int - - """Only read the last \`n\` values of the set.""" - last: Int - - """ - Skip the first \`n\` values from our \`after\` cursor, an alternative to cursor - based pagination. May not be used with \`last\`. - """ - offset: Int - - """Read all values in the set before (above) this cursor.""" - before: Cursor - - """Read all values in the set after (below) this cursor.""" - after: Cursor - - """ - A filter to be used in determining which values should be returned by the collection. - """ - where: CommentFilter - - """The method to use when ordering \`Comment\`.""" - orderBy: [CommentOrderBy!] = [PRIMARY_KEY_ASC] - ): CommentConnection! -} - -"""A connection to a list of \`Tag\` values, with data from \`PostTag\`.""" -type PostTagsManyToManyConnection { - """A list of \`Tag\` objects.""" - nodes: [Tag]! - - """ - A list of edges which contains the \`Tag\`, info from the \`PostTag\`, and the cursor to aid in pagination. - """ - edges: [PostTagsManyToManyEdge!]! - - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """The count of *all* \`Tag\` you could get from the connection.""" - totalCount: Int! -} - -type Tag { - id: UUID! - name: String! - slug: String! - description: String - color: String - createdAt: Datetime - - """Reads and enables pagination through a set of \`Post\`.""" - posts( - """Only read the first \`n\` values of the set.""" - first: Int - - """Only read the last \`n\` values of the set.""" - last: Int - - """ - Skip the first \`n\` values from our \`after\` cursor, an alternative to cursor - based pagination. May not be used with \`last\`. - """ - offset: Int - - """Read all values in the set before (above) this cursor.""" - before: Cursor - - """Read all values in the set after (below) this cursor.""" - after: Cursor - - """ - A filter to be used in determining which values should be returned by the collection. - """ - where: PostFilter - - """The method to use when ordering \`Post\`.""" - orderBy: [PostOrderBy!] = [PRIMARY_KEY_ASC] - ): TagPostsManyToManyConnection! - - """Reads and enables pagination through a set of \`PostTag\`.""" - postTags( - """Only read the first \`n\` values of the set.""" - first: Int - - """Only read the last \`n\` values of the set.""" - last: Int - - """ - Skip the first \`n\` values from our \`after\` cursor, an alternative to cursor - based pagination. May not be used with \`last\`. - """ - offset: Int - - """Read all values in the set before (above) this cursor.""" - before: Cursor - - """Read all values in the set after (below) this cursor.""" - after: Cursor - - """ - A filter to be used in determining which values should be returned by the collection. - """ - where: PostTagFilter - - """The method to use when ordering \`PostTag\`.""" - orderBy: [PostTagOrderBy!] = [PRIMARY_KEY_ASC] - ): PostTagConnection! -} - -"""A connection to a list of \`Post\` values, with data from \`PostTag\`.""" -type TagPostsManyToManyConnection { - """A list of \`Post\` objects.""" - nodes: [Post]! - - """ - A list of edges which contains the \`Post\`, info from the \`PostTag\`, and the cursor to aid in pagination. - """ - edges: [TagPostsManyToManyEdge!]! - - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """The count of *all* \`Post\` you could get from the connection.""" - totalCount: Int! -} - -"""A \`Post\` edge in the connection, with data from \`PostTag\`.""" -type TagPostsManyToManyEdge { - """A cursor for use in pagination.""" - cursor: Cursor - - """The \`Post\` at the end of the edge.""" - node: Post - id: UUID! - createdAt: Datetime -} - -"""A location in a connection that can be used for resuming pagination.""" -scalar Cursor - -"""Information about pagination in a connection.""" -type PageInfo { - """When paginating forwards, are there more items?""" - hasNextPage: Boolean! - - """When paginating backwards, are there more items?""" - hasPreviousPage: Boolean! - - """When paginating backwards, the cursor to continue.""" - startCursor: Cursor - - """When paginating forwards, the cursor to continue.""" - endCursor: Cursor -} - -""" -A filter to be used against \`Post\` object types. All fields are combined with a logical ‘and.’ -""" -input PostFilter { - """Filter by the object’s \`id\` field.""" - id: UUIDFilter - - """Filter by the object’s \`authorId\` field.""" - authorId: UUIDFilter - - """Filter by the object’s \`title\` field.""" - title: StringFilter - - """Filter by the object’s \`slug\` field.""" - slug: StringFilter - - """Filter by the object’s \`content\` field.""" - content: StringFilter - - """Filter by the object’s \`excerpt\` field.""" - excerpt: StringFilter - - """Filter by the object’s \`isPublished\` field.""" - isPublished: BooleanFilter - - """Filter by the object’s \`publishedAt\` field.""" - publishedAt: DatetimeFilter - - """Filter by the object’s \`viewCount\` field.""" - viewCount: IntFilter - - """Filter by the object’s \`createdAt\` field.""" - createdAt: DatetimeFilter - - """Filter by the object’s \`updatedAt\` field.""" - updatedAt: DatetimeFilter - - """Checks for all expressions in this list.""" - and: [PostFilter!] - - """Checks for any expressions in this list.""" - or: [PostFilter!] - - """Negates the expression.""" - not: PostFilter - - """Filter by the object’s \`author\` relation.""" - author: UserFilter - - """Filter by the object’s \`postTags\` relation.""" - postTags: PostToManyPostTagFilter - - """\`postTags\` exist.""" - postTagsExist: Boolean - - """Filter by the object’s \`comments\` relation.""" - comments: PostToManyCommentFilter - - """\`comments\` exist.""" - commentsExist: Boolean -} - -""" -A filter to be used against UUID fields. All fields are combined with a logical ‘and.’ -""" -input UUIDFilter { - """ - Is null (if \`true\` is specified) or is not null (if \`false\` is specified). - """ - isNull: Boolean - - """Equal to the specified value.""" - equalTo: UUID - - """Not equal to the specified value.""" - notEqualTo: UUID - - """ - Not equal to the specified value, treating null like an ordinary value. - """ - distinctFrom: UUID - - """Equal to the specified value, treating null like an ordinary value.""" - notDistinctFrom: UUID - - """Included in the specified list.""" - in: [UUID!] - - """Not included in the specified list.""" - notIn: [UUID!] - - """Less than the specified value.""" - lessThan: UUID - - """Less than or equal to the specified value.""" - lessThanOrEqualTo: UUID - - """Greater than the specified value.""" - greaterThan: UUID - - """Greater than or equal to the specified value.""" - greaterThanOrEqualTo: UUID -} - -""" -A filter to be used against String fields. All fields are combined with a logical ‘and.’ -""" -input StringFilter { - """ - Is null (if \`true\` is specified) or is not null (if \`false\` is specified). - """ - isNull: Boolean - - """Equal to the specified value.""" - equalTo: String - - """Not equal to the specified value.""" - notEqualTo: String - - """ - Not equal to the specified value, treating null like an ordinary value. - """ - distinctFrom: String - - """Equal to the specified value, treating null like an ordinary value.""" - notDistinctFrom: String - - """Included in the specified list.""" - in: [String!] - - """Not included in the specified list.""" - notIn: [String!] - - """Less than the specified value.""" - lessThan: String - - """Less than or equal to the specified value.""" - lessThanOrEqualTo: String - - """Greater than the specified value.""" - greaterThan: String - - """Greater than or equal to the specified value.""" - greaterThanOrEqualTo: String - - """Contains the specified string (case-sensitive).""" - includes: String - - """Does not contain the specified string (case-sensitive).""" - notIncludes: String - - """Contains the specified string (case-insensitive).""" - includesInsensitive: String - - """Does not contain the specified string (case-insensitive).""" - notIncludesInsensitive: String - - """Starts with the specified string (case-sensitive).""" - startsWith: String - - """Does not start with the specified string (case-sensitive).""" - notStartsWith: String - - """Starts with the specified string (case-insensitive).""" - startsWithInsensitive: String - - """Does not start with the specified string (case-insensitive).""" - notStartsWithInsensitive: String - - """Ends with the specified string (case-sensitive).""" - endsWith: String - - """Does not end with the specified string (case-sensitive).""" - notEndsWith: String - - """Ends with the specified string (case-insensitive).""" - endsWithInsensitive: String - - """Does not end with the specified string (case-insensitive).""" - notEndsWithInsensitive: String - - """ - Matches the specified pattern (case-sensitive). An underscore (_) matches any single character; a percent sign (%) matches any sequence of zero or more characters. - """ - like: String - - """ - Does not match the specified pattern (case-sensitive). An underscore (_) matches any single character; a percent sign (%) matches any sequence of zero or more characters. - """ - notLike: String - - """ - Matches the specified pattern (case-insensitive). An underscore (_) matches any single character; a percent sign (%) matches any sequence of zero or more characters. - """ - likeInsensitive: String - - """ - Does not match the specified pattern (case-insensitive). An underscore (_) matches any single character; a percent sign (%) matches any sequence of zero or more characters. - """ - notLikeInsensitive: String - - """Equal to the specified value (case-insensitive).""" - equalToInsensitive: String - - """Not equal to the specified value (case-insensitive).""" - notEqualToInsensitive: String - - """ - Not equal to the specified value, treating null like an ordinary value (case-insensitive). - """ - distinctFromInsensitive: String - - """ - Equal to the specified value, treating null like an ordinary value (case-insensitive). - """ - notDistinctFromInsensitive: String - - """Included in the specified list (case-insensitive).""" - inInsensitive: [String!] - - """Not included in the specified list (case-insensitive).""" - notInInsensitive: [String!] - - """Less than the specified value (case-insensitive).""" - lessThanInsensitive: String - - """Less than or equal to the specified value (case-insensitive).""" - lessThanOrEqualToInsensitive: String - - """Greater than the specified value (case-insensitive).""" - greaterThanInsensitive: String - - """Greater than or equal to the specified value (case-insensitive).""" - greaterThanOrEqualToInsensitive: String -} - -""" -A filter to be used against Boolean fields. All fields are combined with a logical ‘and.’ -""" -input BooleanFilter { - """ - Is null (if \`true\` is specified) or is not null (if \`false\` is specified). - """ - isNull: Boolean - - """Equal to the specified value.""" - equalTo: Boolean - - """Not equal to the specified value.""" - notEqualTo: Boolean - - """ - Not equal to the specified value, treating null like an ordinary value. - """ - distinctFrom: Boolean - - """Equal to the specified value, treating null like an ordinary value.""" - notDistinctFrom: Boolean - - """Included in the specified list.""" - in: [Boolean!] - - """Not included in the specified list.""" - notIn: [Boolean!] - - """Less than the specified value.""" - lessThan: Boolean - - """Less than or equal to the specified value.""" - lessThanOrEqualTo: Boolean - - """Greater than the specified value.""" - greaterThan: Boolean - - """Greater than or equal to the specified value.""" - greaterThanOrEqualTo: Boolean -} - -""" -A filter to be used against Datetime fields. All fields are combined with a logical ‘and.’ -""" -input DatetimeFilter { - """ - Is null (if \`true\` is specified) or is not null (if \`false\` is specified). - """ - isNull: Boolean - - """Equal to the specified value.""" - equalTo: Datetime - - """Not equal to the specified value.""" - notEqualTo: Datetime - - """ - Not equal to the specified value, treating null like an ordinary value. - """ - distinctFrom: Datetime - - """Equal to the specified value, treating null like an ordinary value.""" - notDistinctFrom: Datetime - - """Included in the specified list.""" - in: [Datetime!] - - """Not included in the specified list.""" - notIn: [Datetime!] - - """Less than the specified value.""" - lessThan: Datetime - - """Less than or equal to the specified value.""" - lessThanOrEqualTo: Datetime - - """Greater than the specified value.""" - greaterThan: Datetime - - """Greater than or equal to the specified value.""" - greaterThanOrEqualTo: Datetime -} - -""" -A filter to be used against Int fields. All fields are combined with a logical ‘and.’ -""" -input IntFilter { - """ - Is null (if \`true\` is specified) or is not null (if \`false\` is specified). - """ - isNull: Boolean - - """Equal to the specified value.""" - equalTo: Int - - """Not equal to the specified value.""" - notEqualTo: Int - - """ - Not equal to the specified value, treating null like an ordinary value. - """ - distinctFrom: Int - - """Equal to the specified value, treating null like an ordinary value.""" - notDistinctFrom: Int - - """Included in the specified list.""" - in: [Int!] - - """Not included in the specified list.""" - notIn: [Int!] - - """Less than the specified value.""" - lessThan: Int - - """Less than or equal to the specified value.""" - lessThanOrEqualTo: Int - - """Greater than the specified value.""" - greaterThan: Int - - """Greater than or equal to the specified value.""" - greaterThanOrEqualTo: Int -} - -""" -A filter to be used against \`User\` object types. All fields are combined with a logical ‘and.’ -""" -input UserFilter { - """Filter by the object’s \`id\` field.""" - id: UUIDFilter - - """Filter by the object’s \`email\` field.""" - email: StringFilter - - """Filter by the object’s \`username\` field.""" - username: StringFilter - - """Filter by the object’s \`displayName\` field.""" - displayName: StringFilter - - """Filter by the object’s \`bio\` field.""" - bio: StringFilter - - """Filter by the object’s \`isActive\` field.""" - isActive: BooleanFilter - - """Filter by the object’s \`role\` field.""" - role: StringFilter - - """Filter by the object’s \`createdAt\` field.""" - createdAt: DatetimeFilter - - """Filter by the object’s \`updatedAt\` field.""" - updatedAt: DatetimeFilter - - """Checks for all expressions in this list.""" - and: [UserFilter!] - - """Checks for any expressions in this list.""" - or: [UserFilter!] - - """Negates the expression.""" - not: UserFilter - - """Filter by the object’s \`authoredPosts\` relation.""" - authoredPosts: UserToManyPostFilter - - """\`authoredPosts\` exist.""" - authoredPostsExist: Boolean - - """Filter by the object’s \`authoredComments\` relation.""" - authoredComments: UserToManyCommentFilter - - """\`authoredComments\` exist.""" - authoredCommentsExist: Boolean -} - -""" -A filter to be used against many \`Post\` object types. All fields are combined with a logical ‘and.’ -""" -input UserToManyPostFilter { - """Filters to entities where at least one related entity matches.""" - some: PostFilter - - """Filters to entities where every related entity matches.""" - every: PostFilter - - """Filters to entities where no related entity matches.""" - none: PostFilter -} - -""" -A filter to be used against many \`Comment\` object types. All fields are combined with a logical ‘and.’ -""" -input UserToManyCommentFilter { - """Filters to entities where at least one related entity matches.""" - some: CommentFilter - - """Filters to entities where every related entity matches.""" - every: CommentFilter - - """Filters to entities where no related entity matches.""" - none: CommentFilter -} - -""" -A filter to be used against \`Comment\` object types. All fields are combined with a logical ‘and.’ -""" -input CommentFilter { - """Filter by the object’s \`id\` field.""" - id: UUIDFilter - - """Filter by the object’s \`postId\` field.""" - postId: UUIDFilter - - """Filter by the object’s \`authorId\` field.""" - authorId: UUIDFilter - - """Filter by the object’s \`parentId\` field.""" - parentId: UUIDFilter - - """Filter by the object’s \`content\` field.""" - content: StringFilter - - """Filter by the object’s \`isApproved\` field.""" - isApproved: BooleanFilter - - """Filter by the object’s \`likesCount\` field.""" - likesCount: IntFilter - - """Filter by the object’s \`createdAt\` field.""" - createdAt: DatetimeFilter - - """Filter by the object’s \`updatedAt\` field.""" - updatedAt: DatetimeFilter - - """Checks for all expressions in this list.""" - and: [CommentFilter!] - - """Checks for any expressions in this list.""" - or: [CommentFilter!] - - """Negates the expression.""" - not: CommentFilter - - """Filter by the object’s \`author\` relation.""" - author: UserFilter - - """Filter by the object’s \`parent\` relation.""" - parent: CommentFilter - - """A related \`parent\` exists.""" - parentExists: Boolean - - """Filter by the object’s \`post\` relation.""" - post: PostFilter - - """Filter by the object’s \`childComments\` relation.""" - childComments: CommentToManyCommentFilter - - """\`childComments\` exist.""" - childCommentsExist: Boolean -} - -""" -A filter to be used against many \`Comment\` object types. All fields are combined with a logical ‘and.’ -""" -input CommentToManyCommentFilter { - """Filters to entities where at least one related entity matches.""" - some: CommentFilter - - """Filters to entities where every related entity matches.""" - every: CommentFilter - - """Filters to entities where no related entity matches.""" - none: CommentFilter -} - -""" -A filter to be used against many \`PostTag\` object types. All fields are combined with a logical ‘and.’ -""" -input PostToManyPostTagFilter { - """Filters to entities where at least one related entity matches.""" - some: PostTagFilter - - """Filters to entities where every related entity matches.""" - every: PostTagFilter - - """Filters to entities where no related entity matches.""" - none: PostTagFilter -} - -""" -A filter to be used against \`PostTag\` object types. All fields are combined with a logical ‘and.’ -""" -input PostTagFilter { - """Filter by the object’s \`id\` field.""" - id: UUIDFilter - - """Filter by the object’s \`postId\` field.""" - postId: UUIDFilter - - """Filter by the object’s \`tagId\` field.""" - tagId: UUIDFilter - - """Filter by the object’s \`createdAt\` field.""" - createdAt: DatetimeFilter - - """Checks for all expressions in this list.""" - and: [PostTagFilter!] - - """Checks for any expressions in this list.""" - or: [PostTagFilter!] - - """Negates the expression.""" - not: PostTagFilter - - """Filter by the object’s \`post\` relation.""" - post: PostFilter - - """Filter by the object’s \`tag\` relation.""" - tag: TagFilter -} - -""" -A filter to be used against \`Tag\` object types. All fields are combined with a logical ‘and.’ -""" -input TagFilter { - """Filter by the object’s \`id\` field.""" - id: UUIDFilter - - """Filter by the object’s \`name\` field.""" - name: StringFilter - - """Filter by the object’s \`slug\` field.""" - slug: StringFilter - - """Filter by the object’s \`description\` field.""" - description: StringFilter - - """Filter by the object’s \`color\` field.""" - color: StringFilter - - """Filter by the object’s \`createdAt\` field.""" - createdAt: DatetimeFilter - - """Checks for all expressions in this list.""" - and: [TagFilter!] - - """Checks for any expressions in this list.""" - or: [TagFilter!] - - """Negates the expression.""" - not: TagFilter - - """Filter by the object’s \`postTags\` relation.""" - postTags: TagToManyPostTagFilter - - """\`postTags\` exist.""" - postTagsExist: Boolean -} - -""" -A filter to be used against many \`PostTag\` object types. All fields are combined with a logical ‘and.’ -""" -input TagToManyPostTagFilter { - """Filters to entities where at least one related entity matches.""" - some: PostTagFilter - - """Filters to entities where every related entity matches.""" - every: PostTagFilter - - """Filters to entities where no related entity matches.""" - none: PostTagFilter -} - -""" -A filter to be used against many \`Comment\` object types. All fields are combined with a logical ‘and.’ -""" -input PostToManyCommentFilter { - """Filters to entities where at least one related entity matches.""" - some: CommentFilter - - """Filters to entities where every related entity matches.""" - every: CommentFilter - - """Filters to entities where no related entity matches.""" - none: CommentFilter -} - -"""Methods to use when ordering \`Post\`.""" -enum PostOrderBy { - NATURAL - PRIMARY_KEY_ASC - PRIMARY_KEY_DESC - ID_ASC - ID_DESC - AUTHOR_ID_ASC - AUTHOR_ID_DESC - TITLE_ASC - TITLE_DESC - SLUG_ASC - SLUG_DESC - CONTENT_ASC - CONTENT_DESC - EXCERPT_ASC - EXCERPT_DESC - IS_PUBLISHED_ASC - IS_PUBLISHED_DESC - PUBLISHED_AT_ASC - PUBLISHED_AT_DESC - VIEW_COUNT_ASC - VIEW_COUNT_DESC - CREATED_AT_ASC - CREATED_AT_DESC - UPDATED_AT_ASC - UPDATED_AT_DESC -} - -"""Methods to use when ordering \`PostTag\`.""" -enum PostTagOrderBy { - NATURAL - PRIMARY_KEY_ASC - PRIMARY_KEY_DESC - ID_ASC - ID_DESC - POST_ID_ASC - POST_ID_DESC - TAG_ID_ASC - TAG_ID_DESC - CREATED_AT_ASC - CREATED_AT_DESC -} - -"""A \`Tag\` edge in the connection, with data from \`PostTag\`.""" -type PostTagsManyToManyEdge { - """A cursor for use in pagination.""" - cursor: Cursor - - """The \`Tag\` at the end of the edge.""" - node: Tag - id: UUID! - createdAt: Datetime -} - -"""Methods to use when ordering \`Tag\`.""" -enum TagOrderBy { - NATURAL - PRIMARY_KEY_ASC - PRIMARY_KEY_DESC - ID_ASC - ID_DESC - NAME_ASC - NAME_DESC - SLUG_ASC - SLUG_DESC - DESCRIPTION_ASC - DESCRIPTION_DESC - COLOR_ASC - COLOR_DESC - CREATED_AT_ASC - CREATED_AT_DESC -} - -type User { - id: UUID! - email: String! - username: String! - displayName: String - bio: String - isActive: Boolean - role: String - createdAt: Datetime - updatedAt: Datetime - - """Reads and enables pagination through a set of \`Post\`.""" - authoredPosts( - """Only read the first \`n\` values of the set.""" - first: Int - - """Only read the last \`n\` values of the set.""" - last: Int - - """ - Skip the first \`n\` values from our \`after\` cursor, an alternative to cursor - based pagination. May not be used with \`last\`. - """ - offset: Int - - """Read all values in the set before (above) this cursor.""" - before: Cursor - - """Read all values in the set after (below) this cursor.""" - after: Cursor - - """ - A filter to be used in determining which values should be returned by the collection. - """ - where: PostFilter - - """The method to use when ordering \`Post\`.""" - orderBy: [PostOrderBy!] = [PRIMARY_KEY_ASC] - ): PostConnection! - - """Reads and enables pagination through a set of \`Comment\`.""" - authoredComments( - """Only read the first \`n\` values of the set.""" - first: Int - - """Only read the last \`n\` values of the set.""" - last: Int - - """ - Skip the first \`n\` values from our \`after\` cursor, an alternative to cursor - based pagination. May not be used with \`last\`. - """ - offset: Int - - """Read all values in the set before (above) this cursor.""" - before: Cursor - - """Read all values in the set after (below) this cursor.""" - after: Cursor - - """ - A filter to be used in determining which values should be returned by the collection. - """ - where: CommentFilter - - """The method to use when ordering \`Comment\`.""" - orderBy: [CommentOrderBy!] = [PRIMARY_KEY_ASC] - ): CommentConnection! -} - -"""A connection to a list of \`Post\` values.""" -type PostConnection { - """A list of \`Post\` objects.""" - nodes: [Post]! - - """ - A list of edges which contains the \`Post\` and cursor to aid in pagination. - """ - edges: [PostEdge]! - - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """The count of *all* \`Post\` you could get from the connection.""" - totalCount: Int! -} - -"""A \`Post\` edge in the connection.""" -type PostEdge { - """A cursor for use in pagination.""" - cursor: Cursor - - """The \`Post\` at the end of the edge.""" - node: Post -} - -"""A connection to a list of \`Comment\` values.""" -type CommentConnection { - """A list of \`Comment\` objects.""" - nodes: [Comment]! - - """ - A list of edges which contains the \`Comment\` and cursor to aid in pagination. - """ - edges: [CommentEdge]! - - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """The count of *all* \`Comment\` you could get from the connection.""" - totalCount: Int! -} - -type Comment { - id: UUID! - postId: UUID! - authorId: UUID! - parentId: UUID - content: String! - isApproved: Boolean - likesCount: Int - createdAt: Datetime - updatedAt: Datetime - - """Reads a single \`User\` that is related to this \`Comment\`.""" - author: User - - """Reads a single \`Comment\` that is related to this \`Comment\`.""" - parent: Comment - - """Reads a single \`Post\` that is related to this \`Comment\`.""" - post: Post - - """Reads and enables pagination through a set of \`Comment\`.""" - childComments( - """Only read the first \`n\` values of the set.""" - first: Int - - """Only read the last \`n\` values of the set.""" - last: Int - - """ - Skip the first \`n\` values from our \`after\` cursor, an alternative to cursor - based pagination. May not be used with \`last\`. - """ - offset: Int - - """Read all values in the set before (above) this cursor.""" - before: Cursor - - """Read all values in the set after (below) this cursor.""" - after: Cursor - - """ - A filter to be used in determining which values should be returned by the collection. - """ - where: CommentFilter - - """The method to use when ordering \`Comment\`.""" - orderBy: [CommentOrderBy!] = [PRIMARY_KEY_ASC] - ): CommentConnection! -} - -"""Methods to use when ordering \`Comment\`.""" -enum CommentOrderBy { - NATURAL - PRIMARY_KEY_ASC - PRIMARY_KEY_DESC - ID_ASC - ID_DESC - POST_ID_ASC - POST_ID_DESC - AUTHOR_ID_ASC - AUTHOR_ID_DESC - PARENT_ID_ASC - PARENT_ID_DESC - CONTENT_ASC - CONTENT_DESC - IS_APPROVED_ASC - IS_APPROVED_DESC - LIKES_COUNT_ASC - LIKES_COUNT_DESC - CREATED_AT_ASC - CREATED_AT_DESC - UPDATED_AT_ASC - UPDATED_AT_DESC -} - -"""A \`Comment\` edge in the connection.""" -type CommentEdge { - """A cursor for use in pagination.""" - cursor: Cursor - - """The \`Comment\` at the end of the edge.""" - node: Comment -} - -"""A \`PostTag\` edge in the connection.""" -type PostTagEdge { - """A cursor for use in pagination.""" - cursor: Cursor - - """The \`PostTag\` at the end of the edge.""" - node: PostTag -} - -"""A connection to a list of \`Tag\` values.""" -type TagConnection { - """A list of \`Tag\` objects.""" - nodes: [Tag]! - - """ - A list of edges which contains the \`Tag\` and cursor to aid in pagination. - """ - edges: [TagEdge]! - - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """The count of *all* \`Tag\` you could get from the connection.""" - totalCount: Int! -} - -"""A \`Tag\` edge in the connection.""" -type TagEdge { - """A cursor for use in pagination.""" - cursor: Cursor - - """The \`Tag\` at the end of the edge.""" - node: Tag -} - -"""A connection to a list of \`User\` values.""" -type UserConnection { - """A list of \`User\` objects.""" - nodes: [User]! - - """ - A list of edges which contains the \`User\` and cursor to aid in pagination. - """ - edges: [UserEdge]! - - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """The count of *all* \`User\` you could get from the connection.""" - totalCount: Int! -} - -"""A \`User\` edge in the connection.""" -type UserEdge { - """A cursor for use in pagination.""" - cursor: Cursor - - """The \`User\` at the end of the edge.""" - node: User -} - -"""Methods to use when ordering \`User\`.""" -enum UserOrderBy { - NATURAL - PRIMARY_KEY_ASC - PRIMARY_KEY_DESC - ID_ASC - ID_DESC - EMAIL_ASC - EMAIL_DESC - USERNAME_ASC - USERNAME_DESC - DISPLAY_NAME_ASC - DISPLAY_NAME_DESC - BIO_ASC - BIO_DESC - IS_ACTIVE_ASC - IS_ACTIVE_DESC - ROLE_ASC - ROLE_DESC - CREATED_AT_ASC - CREATED_AT_DESC - UPDATED_AT_ASC - UPDATED_AT_DESC -} - -"""Root meta schema type""" -type MetaSchema { - tables: [MetaTable!]! -} - -"""Information about a database table""" -type MetaTable { - name: String! - schemaName: String! - fields: [MetaField!]! - indexes: [MetaIndex!]! - constraints: MetaConstraints! - foreignKeyConstraints: [MetaForeignKeyConstraint!]! - primaryKeyConstraints: [MetaPrimaryKeyConstraint!]! - uniqueConstraints: [MetaUniqueConstraint!]! - relations: MetaRelations! - inflection: MetaInflection! - query: MetaQuery! -} - -"""Information about a table field/column""" -type MetaField { - name: String! - type: MetaType! - isNotNull: Boolean! - hasDefault: Boolean! - isPrimaryKey: Boolean! - isForeignKey: Boolean! - description: String -} - -"""Information about a PostgreSQL type""" -type MetaType { - pgType: String! - gqlType: String! - isArray: Boolean! - isNotNull: Boolean - hasDefault: Boolean - subtype: String -} - -"""Information about a database index""" -type MetaIndex { - name: String! - isUnique: Boolean! - isPrimary: Boolean! - columns: [String!]! - fields: [MetaField!] -} - -"""Table constraints""" -type MetaConstraints { - primaryKey: MetaPrimaryKeyConstraint - unique: [MetaUniqueConstraint!]! - foreignKey: [MetaForeignKeyConstraint!]! -} - -"""Information about a primary key constraint""" -type MetaPrimaryKeyConstraint { - name: String! - fields: [MetaField!]! -} - -"""Information about a unique constraint""" -type MetaUniqueConstraint { - name: String! - fields: [MetaField!]! -} - -"""Information about a foreign key constraint""" -type MetaForeignKeyConstraint { - name: String! - fields: [MetaField!]! - referencedTable: String! - referencedFields: [String!]! - refFields: [MetaField!] - refTable: MetaRefTable -} - -"""Reference to a related table""" -type MetaRefTable { - name: String! -} - -"""Table relations""" -type MetaRelations { - belongsTo: [MetaBelongsToRelation!]! - has: [MetaHasRelation!]! - hasOne: [MetaHasRelation!]! - hasMany: [MetaHasRelation!]! - manyToMany: [MetaManyToManyRelation!]! -} - -"""A belongs-to (forward FK) relation""" -type MetaBelongsToRelation { - fieldName: String - isUnique: Boolean! - type: String - keys: [MetaField!]! - references: MetaRefTable! -} - -"""A has-one or has-many (reverse FK) relation""" -type MetaHasRelation { - fieldName: String - isUnique: Boolean! - type: String - keys: [MetaField!]! - referencedBy: MetaRefTable! -} - -"""A many-to-many relation via junction table""" -type MetaManyToManyRelation { - fieldName: String - type: String - junctionTable: MetaRefTable! - junctionLeftConstraint: MetaForeignKeyConstraint! - junctionLeftKeyAttributes: [MetaField!]! - junctionRightConstraint: MetaForeignKeyConstraint! - junctionRightKeyAttributes: [MetaField!]! - leftKeyAttributes: [MetaField!]! - rightKeyAttributes: [MetaField!]! - rightTable: MetaRefTable! -} - -"""Table inflection names""" -type MetaInflection { - tableType: String! - allRows: String! - connection: String! - edge: String! - filterType: String - orderByType: String! - conditionType: String! - patchType: String - createInputType: String! - createPayloadType: String! - updatePayloadType: String - deletePayloadType: String! -} - -"""Table query/mutation names""" -type MetaQuery { - all: String! - one: String - create: String - update: String - delete: String -} - -"""The output of our create \`PostTag\` mutation.""" -type CreatePostTagPayload { - """ - The exact same \`clientMutationId\` that was provided in the mutation input, - unchanged and unused. May be used by a client to track mutations. - """ - clientMutationId: String - - """The \`PostTag\` that was created by this mutation.""" - postTag: PostTag - - """ - Our root query field type. Allows us to run any query from our mutation payload. - """ - query: Query - - """An edge for our \`PostTag\`. May be used by Relay 1.""" - postTagEdge( - """The method to use when ordering \`PostTag\`.""" - orderBy: [PostTagOrderBy!]! = [PRIMARY_KEY_ASC] - ): PostTagEdge -} - -"""All input for the create \`PostTag\` mutation.""" -input CreatePostTagInput { - """ - An arbitrary string value with no semantic meaning. Will be included in the - payload verbatim. May be used to track mutations by the client. - """ - clientMutationId: String - - """The \`PostTag\` to be created by this mutation.""" - postTag: PostTagInput! -} - -"""An input for mutations affecting \`PostTag\`""" -input PostTagInput { - id: UUID - postId: UUID! - tagId: UUID! - createdAt: Datetime -} - -"""The output of our create \`Tag\` mutation.""" -type CreateTagPayload { - """ - The exact same \`clientMutationId\` that was provided in the mutation input, - unchanged and unused. May be used by a client to track mutations. - """ - clientMutationId: String - - """The \`Tag\` that was created by this mutation.""" - tag: Tag - - """ - Our root query field type. Allows us to run any query from our mutation payload. - """ - query: Query - - """An edge for our \`Tag\`. May be used by Relay 1.""" - tagEdge( - """The method to use when ordering \`Tag\`.""" - orderBy: [TagOrderBy!]! = [PRIMARY_KEY_ASC] - ): TagEdge -} - -"""All input for the create \`Tag\` mutation.""" -input CreateTagInput { - """ - An arbitrary string value with no semantic meaning. Will be included in the - payload verbatim. May be used to track mutations by the client. - """ - clientMutationId: String - - """The \`Tag\` to be created by this mutation.""" - tag: TagInput! -} - -"""An input for mutations affecting \`Tag\`""" -input TagInput { - id: UUID - name: String! - slug: String! - description: String - color: String - createdAt: Datetime -} - -"""The output of our create \`User\` mutation.""" -type CreateUserPayload { - """ - The exact same \`clientMutationId\` that was provided in the mutation input, - unchanged and unused. May be used by a client to track mutations. - """ - clientMutationId: String - - """The \`User\` that was created by this mutation.""" - user: User - - """ - Our root query field type. Allows us to run any query from our mutation payload. - """ - query: Query - - """An edge for our \`User\`. May be used by Relay 1.""" - userEdge( - """The method to use when ordering \`User\`.""" - orderBy: [UserOrderBy!]! = [PRIMARY_KEY_ASC] - ): UserEdge -} - -"""All input for the create \`User\` mutation.""" -input CreateUserInput { - """ - An arbitrary string value with no semantic meaning. Will be included in the - payload verbatim. May be used to track mutations by the client. - """ - clientMutationId: String - - """The \`User\` to be created by this mutation.""" - user: UserInput! -} - -"""An input for mutations affecting \`User\`""" -input UserInput { - id: UUID - email: String! - username: String! - displayName: String - bio: String - isActive: Boolean - role: String - createdAt: Datetime - updatedAt: Datetime -} - -"""The output of our create \`Comment\` mutation.""" -type CreateCommentPayload { - """ - The exact same \`clientMutationId\` that was provided in the mutation input, - unchanged and unused. May be used by a client to track mutations. - """ - clientMutationId: String - - """The \`Comment\` that was created by this mutation.""" - comment: Comment - - """ - Our root query field type. Allows us to run any query from our mutation payload. - """ - query: Query - - """An edge for our \`Comment\`. May be used by Relay 1.""" - commentEdge( - """The method to use when ordering \`Comment\`.""" - orderBy: [CommentOrderBy!]! = [PRIMARY_KEY_ASC] - ): CommentEdge -} - -"""All input for the create \`Comment\` mutation.""" -input CreateCommentInput { - """ - An arbitrary string value with no semantic meaning. Will be included in the - payload verbatim. May be used to track mutations by the client. - """ - clientMutationId: String - - """The \`Comment\` to be created by this mutation.""" - comment: CommentInput! -} - -"""An input for mutations affecting \`Comment\`""" -input CommentInput { - id: UUID - postId: UUID! - authorId: UUID! - parentId: UUID - content: String! - isApproved: Boolean - likesCount: Int - createdAt: Datetime - updatedAt: Datetime -} - -"""The output of our create \`Post\` mutation.""" -type CreatePostPayload { - """ - The exact same \`clientMutationId\` that was provided in the mutation input, - unchanged and unused. May be used by a client to track mutations. - """ - clientMutationId: String - - """The \`Post\` that was created by this mutation.""" - post: Post - - """ - Our root query field type. Allows us to run any query from our mutation payload. - """ - query: Query - - """An edge for our \`Post\`. May be used by Relay 1.""" - postEdge( - """The method to use when ordering \`Post\`.""" - orderBy: [PostOrderBy!]! = [PRIMARY_KEY_ASC] - ): PostEdge -} - -"""All input for the create \`Post\` mutation.""" -input CreatePostInput { - """ - An arbitrary string value with no semantic meaning. Will be included in the - payload verbatim. May be used to track mutations by the client. - """ - clientMutationId: String - - """The \`Post\` to be created by this mutation.""" - post: PostInput! -} - -"""An input for mutations affecting \`Post\`""" -input PostInput { - id: UUID - authorId: UUID! - title: String! - slug: String! - content: String - excerpt: String - isPublished: Boolean - publishedAt: Datetime - viewCount: Int - createdAt: Datetime - updatedAt: Datetime -} - -"""The output of our update \`PostTag\` mutation.""" -type UpdatePostTagPayload { - """ - The exact same \`clientMutationId\` that was provided in the mutation input, - unchanged and unused. May be used by a client to track mutations. - """ - clientMutationId: String - - """The \`PostTag\` that was updated by this mutation.""" - postTag: PostTag - - """ - Our root query field type. Allows us to run any query from our mutation payload. - """ - query: Query - - """An edge for our \`PostTag\`. May be used by Relay 1.""" - postTagEdge( - """The method to use when ordering \`PostTag\`.""" - orderBy: [PostTagOrderBy!]! = [PRIMARY_KEY_ASC] - ): PostTagEdge -} - -"""All input for the \`updatePostTag\` mutation.""" -input UpdatePostTagInput { - """ - An arbitrary string value with no semantic meaning. Will be included in the - payload verbatim. May be used to track mutations by the client. - """ - clientMutationId: String - id: UUID! - - """ - An object where the defined keys will be set on the \`PostTag\` being updated. - """ - postTagPatch: PostTagPatch! -} - -""" -Represents an update to a \`PostTag\`. Fields that are set will be updated. -""" -input PostTagPatch { - id: UUID - postId: UUID - tagId: UUID - createdAt: Datetime -} - -"""The output of our update \`Tag\` mutation.""" -type UpdateTagPayload { - """ - The exact same \`clientMutationId\` that was provided in the mutation input, - unchanged and unused. May be used by a client to track mutations. - """ - clientMutationId: String - - """The \`Tag\` that was updated by this mutation.""" - tag: Tag - - """ - Our root query field type. Allows us to run any query from our mutation payload. - """ - query: Query - - """An edge for our \`Tag\`. May be used by Relay 1.""" - tagEdge( - """The method to use when ordering \`Tag\`.""" - orderBy: [TagOrderBy!]! = [PRIMARY_KEY_ASC] - ): TagEdge -} - -"""All input for the \`updateTag\` mutation.""" -input UpdateTagInput { - """ - An arbitrary string value with no semantic meaning. Will be included in the - payload verbatim. May be used to track mutations by the client. - """ - clientMutationId: String - id: UUID! - - """ - An object where the defined keys will be set on the \`Tag\` being updated. - """ - tagPatch: TagPatch! -} - -"""Represents an update to a \`Tag\`. Fields that are set will be updated.""" -input TagPatch { - id: UUID - name: String - slug: String - description: String - color: String - createdAt: Datetime -} - -"""The output of our update \`User\` mutation.""" -type UpdateUserPayload { - """ - The exact same \`clientMutationId\` that was provided in the mutation input, - unchanged and unused. May be used by a client to track mutations. - """ - clientMutationId: String - - """The \`User\` that was updated by this mutation.""" - user: User - - """ - Our root query field type. Allows us to run any query from our mutation payload. - """ - query: Query - - """An edge for our \`User\`. May be used by Relay 1.""" - userEdge( - """The method to use when ordering \`User\`.""" - orderBy: [UserOrderBy!]! = [PRIMARY_KEY_ASC] - ): UserEdge -} - -"""All input for the \`updateUser\` mutation.""" -input UpdateUserInput { - """ - An arbitrary string value with no semantic meaning. Will be included in the - payload verbatim. May be used to track mutations by the client. - """ - clientMutationId: String - id: UUID! - - """ - An object where the defined keys will be set on the \`User\` being updated. - """ - userPatch: UserPatch! -} - -"""Represents an update to a \`User\`. Fields that are set will be updated.""" -input UserPatch { - id: UUID - email: String - username: String - displayName: String - bio: String - isActive: Boolean - role: String - createdAt: Datetime - updatedAt: Datetime -} - -"""The output of our update \`Comment\` mutation.""" -type UpdateCommentPayload { - """ - The exact same \`clientMutationId\` that was provided in the mutation input, - unchanged and unused. May be used by a client to track mutations. - """ - clientMutationId: String - - """The \`Comment\` that was updated by this mutation.""" - comment: Comment - - """ - Our root query field type. Allows us to run any query from our mutation payload. - """ - query: Query - - """An edge for our \`Comment\`. May be used by Relay 1.""" - commentEdge( - """The method to use when ordering \`Comment\`.""" - orderBy: [CommentOrderBy!]! = [PRIMARY_KEY_ASC] - ): CommentEdge -} - -"""All input for the \`updateComment\` mutation.""" -input UpdateCommentInput { - """ - An arbitrary string value with no semantic meaning. Will be included in the - payload verbatim. May be used to track mutations by the client. - """ - clientMutationId: String - id: UUID! - - """ - An object where the defined keys will be set on the \`Comment\` being updated. - """ - commentPatch: CommentPatch! -} - -""" -Represents an update to a \`Comment\`. Fields that are set will be updated. -""" -input CommentPatch { - id: UUID - postId: UUID - authorId: UUID - parentId: UUID - content: String - isApproved: Boolean - likesCount: Int - createdAt: Datetime - updatedAt: Datetime -} - -"""The output of our update \`Post\` mutation.""" -type UpdatePostPayload { - """ - The exact same \`clientMutationId\` that was provided in the mutation input, - unchanged and unused. May be used by a client to track mutations. - """ - clientMutationId: String - - """The \`Post\` that was updated by this mutation.""" - post: Post - - """ - Our root query field type. Allows us to run any query from our mutation payload. - """ - query: Query - - """An edge for our \`Post\`. May be used by Relay 1.""" - postEdge( - """The method to use when ordering \`Post\`.""" - orderBy: [PostOrderBy!]! = [PRIMARY_KEY_ASC] - ): PostEdge -} - -"""All input for the \`updatePost\` mutation.""" -input UpdatePostInput { - """ - An arbitrary string value with no semantic meaning. Will be included in the - payload verbatim. May be used to track mutations by the client. - """ - clientMutationId: String - id: UUID! - - """ - An object where the defined keys will be set on the \`Post\` being updated. - """ - postPatch: PostPatch! -} - -"""Represents an update to a \`Post\`. Fields that are set will be updated.""" -input PostPatch { - id: UUID - authorId: UUID - title: String - slug: String - content: String - excerpt: String - isPublished: Boolean - publishedAt: Datetime - viewCount: Int - createdAt: Datetime - updatedAt: Datetime -} - -"""The output of our delete \`PostTag\` mutation.""" -type DeletePostTagPayload { - """ - The exact same \`clientMutationId\` that was provided in the mutation input, - unchanged and unused. May be used by a client to track mutations. - """ - clientMutationId: String - - """The \`PostTag\` that was deleted by this mutation.""" - postTag: PostTag - - """ - Our root query field type. Allows us to run any query from our mutation payload. - """ - query: Query - - """An edge for our \`PostTag\`. May be used by Relay 1.""" - postTagEdge( - """The method to use when ordering \`PostTag\`.""" - orderBy: [PostTagOrderBy!]! = [PRIMARY_KEY_ASC] - ): PostTagEdge -} - -"""All input for the \`deletePostTag\` mutation.""" -input DeletePostTagInput { - """ - An arbitrary string value with no semantic meaning. Will be included in the - payload verbatim. May be used to track mutations by the client. - """ - clientMutationId: String - id: UUID! -} - -"""The output of our delete \`Tag\` mutation.""" -type DeleteTagPayload { - """ - The exact same \`clientMutationId\` that was provided in the mutation input, - unchanged and unused. May be used by a client to track mutations. - """ - clientMutationId: String - - """The \`Tag\` that was deleted by this mutation.""" - tag: Tag - - """ - Our root query field type. Allows us to run any query from our mutation payload. - """ - query: Query - - """An edge for our \`Tag\`. May be used by Relay 1.""" - tagEdge( - """The method to use when ordering \`Tag\`.""" - orderBy: [TagOrderBy!]! = [PRIMARY_KEY_ASC] - ): TagEdge -} - -"""All input for the \`deleteTag\` mutation.""" -input DeleteTagInput { - """ - An arbitrary string value with no semantic meaning. Will be included in the - payload verbatim. May be used to track mutations by the client. - """ - clientMutationId: String - id: UUID! -} - -"""The output of our delete \`User\` mutation.""" -type DeleteUserPayload { - """ - The exact same \`clientMutationId\` that was provided in the mutation input, - unchanged and unused. May be used by a client to track mutations. - """ - clientMutationId: String - - """The \`User\` that was deleted by this mutation.""" - user: User - - """ - Our root query field type. Allows us to run any query from our mutation payload. - """ - query: Query - - """An edge for our \`User\`. May be used by Relay 1.""" - userEdge( - """The method to use when ordering \`User\`.""" - orderBy: [UserOrderBy!]! = [PRIMARY_KEY_ASC] - ): UserEdge -} - -"""All input for the \`deleteUser\` mutation.""" -input DeleteUserInput { - """ - An arbitrary string value with no semantic meaning. Will be included in the - payload verbatim. May be used to track mutations by the client. - """ - clientMutationId: String - id: UUID! -} - -"""The output of our delete \`Comment\` mutation.""" -type DeleteCommentPayload { - """ - The exact same \`clientMutationId\` that was provided in the mutation input, - unchanged and unused. May be used by a client to track mutations. - """ - clientMutationId: String - - """The \`Comment\` that was deleted by this mutation.""" - comment: Comment - - """ - Our root query field type. Allows us to run any query from our mutation payload. - """ - query: Query - - """An edge for our \`Comment\`. May be used by Relay 1.""" - commentEdge( - """The method to use when ordering \`Comment\`.""" - orderBy: [CommentOrderBy!]! = [PRIMARY_KEY_ASC] - ): CommentEdge -} - -"""All input for the \`deleteComment\` mutation.""" -input DeleteCommentInput { - """ - An arbitrary string value with no semantic meaning. Will be included in the - payload verbatim. May be used to track mutations by the client. - """ - clientMutationId: String - id: UUID! -} - -"""The output of our delete \`Post\` mutation.""" -type DeletePostPayload { - """ - The exact same \`clientMutationId\` that was provided in the mutation input, - unchanged and unused. May be used by a client to track mutations. - """ - clientMutationId: String - - """The \`Post\` that was deleted by this mutation.""" - post: Post - - """ - Our root query field type. Allows us to run any query from our mutation payload. - """ - query: Query - - """An edge for our \`Post\`. May be used by Relay 1.""" - postEdge( - """The method to use when ordering \`Post\`.""" - orderBy: [PostOrderBy!]! = [PRIMARY_KEY_ASC] - ): PostEdge -} - -"""All input for the \`deletePost\` mutation.""" -input DeletePostInput { - """ - An arbitrary string value with no semantic meaning. Will be included in the - payload verbatim. May be used to track mutations by the client. - """ - clientMutationId: String - id: UUID! -} - -input RequestUploadUrlInput { - """Bucket key (e.g., "public", "private")""" - bucketKey: String! - - """ - Owner entity ID for entity-scoped uploads. - Omit for app-level (database-wide) storage. - When provided, resolves the storage module for the entity type - that owns this entity instance (e.g., a data room ID, team ID). - """ - ownerId: UUID - - """SHA-256 content hash computed by the client (hex-encoded, 64 chars)""" - contentHash: String! - - """MIME type of the file (e.g., "image/png")""" - contentType: String! - - """File size in bytes""" - size: Int! - - """Original filename (optional, for display and Content-Disposition)""" - filename: String - - """ - Custom S3 key (e.g., "reports/2024/Q1.pdf"). - Only allowed when the bucket has allow_custom_keys=true. - When omitted, key defaults to contentHash (content-addressed dedup). - When provided, the file is stored at this key. - Re-uploading to an existing key auto-creates a new version. - """ - key: String -} - -type RequestUploadUrlPayload { - """Presigned PUT URL (null if file was deduplicated)""" - uploadUrl: String - - """The file ID (existing if deduplicated, new if fresh upload)""" - fileId: UUID! - - """The S3 object key""" - key: String! - - """Whether this file was deduplicated (already exists with same hash)""" - deduplicated: Boolean! - - """Presigned URL expiry time (null if deduplicated)""" - expiresAt: Datetime - - """ - ID of the previous version (set when re-uploading to an existing custom key) - """ - previousVersionId: UUID -} - -input BulkUploadFileInput { - """SHA-256 content hash computed by the client (hex-encoded, 64 chars)""" - contentHash: String! - - """MIME type of the file (e.g., "image/png")""" - contentType: String! - - """File size in bytes""" - size: Int! - - """Original filename (optional, for display and Content-Disposition)""" - filename: String - - """Custom S3 key (only when bucket has allow_custom_keys=true)""" - key: String -} - -input RequestBulkUploadUrlsInput { - """Bucket key (e.g., "public", "private")""" - bucketKey: String! - - """Owner entity ID for entity-scoped uploads""" - ownerId: UUID - - """Array of files to upload""" - files: [BulkUploadFileInput!]! -} - -type BulkUploadFilePayload { - """Presigned PUT URL (null if file was deduplicated)""" - uploadUrl: String - - """The file ID""" - fileId: UUID! - - """The S3 object key""" - key: String! - - """Whether this file was deduplicated""" - deduplicated: Boolean! - - """Presigned URL expiry time (null if deduplicated)""" - expiresAt: Datetime - - """ - ID of the previous version (set when re-uploading to an existing custom key) - """ - previousVersionId: UUID - - """Index of this file in the input array (for client correlation)""" - index: Int! -} - -type RequestBulkUploadUrlsPayload { - """Array of results, one per input file""" - files: [BulkUploadFilePayload!]! -} - -"""The root query type which gives access points into the data universe.""" -type Query { - """Reads and enables pagination through a set of \`PostTag\`.""" - postTags( - """Only read the first \`n\` values of the set.""" - first: Int - - """Only read the last \`n\` values of the set.""" - last: Int - - """ - Skip the first \`n\` values from our \`after\` cursor, an alternative to cursor - based pagination. May not be used with \`last\`. - """ - offset: Int - - """Read all values in the set before (above) this cursor.""" - before: Cursor - - """Read all values in the set after (below) this cursor.""" - after: Cursor - - """ - A filter to be used in determining which values should be returned by the collection. - """ - where: PostTagFilter - - """The method to use when ordering \`PostTag\`.""" - orderBy: [PostTagOrderBy!] = [PRIMARY_KEY_ASC] - ): PostTagConnection - - """Reads and enables pagination through a set of \`Tag\`.""" - tags( - """Only read the first \`n\` values of the set.""" - first: Int - - """Only read the last \`n\` values of the set.""" - last: Int - - """ - Skip the first \`n\` values from our \`after\` cursor, an alternative to cursor - based pagination. May not be used with \`last\`. - """ - offset: Int - - """Read all values in the set before (above) this cursor.""" - before: Cursor - - """Read all values in the set after (below) this cursor.""" - after: Cursor - - """ - A filter to be used in determining which values should be returned by the collection. - """ - where: TagFilter - - """The method to use when ordering \`Tag\`.""" - orderBy: [TagOrderBy!] = [PRIMARY_KEY_ASC] - ): TagConnection - - """Reads and enables pagination through a set of \`User\`.""" - users( - """Only read the first \`n\` values of the set.""" - first: Int - - """Only read the last \`n\` values of the set.""" - last: Int - - """ - Skip the first \`n\` values from our \`after\` cursor, an alternative to cursor - based pagination. May not be used with \`last\`. - """ - offset: Int - - """Read all values in the set before (above) this cursor.""" - before: Cursor - - """Read all values in the set after (below) this cursor.""" - after: Cursor - - """ - A filter to be used in determining which values should be returned by the collection. - """ - where: UserFilter - - """The method to use when ordering \`User\`.""" - orderBy: [UserOrderBy!] = [PRIMARY_KEY_ASC] - ): UserConnection - - """Reads and enables pagination through a set of \`Comment\`.""" - comments( - """Only read the first \`n\` values of the set.""" - first: Int - - """Only read the last \`n\` values of the set.""" - last: Int - - """ - Skip the first \`n\` values from our \`after\` cursor, an alternative to cursor - based pagination. May not be used with \`last\`. - """ - offset: Int - - """Read all values in the set before (above) this cursor.""" - before: Cursor - - """Read all values in the set after (below) this cursor.""" - after: Cursor - - """ - A filter to be used in determining which values should be returned by the collection. - """ - where: CommentFilter - - """The method to use when ordering \`Comment\`.""" - orderBy: [CommentOrderBy!] = [PRIMARY_KEY_ASC] - ): CommentConnection - - """Reads and enables pagination through a set of \`Post\`.""" - posts( - """Only read the first \`n\` values of the set.""" - first: Int - - """Only read the last \`n\` values of the set.""" - last: Int - - """ - Skip the first \`n\` values from our \`after\` cursor, an alternative to cursor - based pagination. May not be used with \`last\`. - """ - offset: Int - - """Read all values in the set before (above) this cursor.""" - before: Cursor - - """Read all values in the set after (below) this cursor.""" - after: Cursor - - """ - A filter to be used in determining which values should be returned by the collection. - """ - where: PostFilter - - """The method to use when ordering \`Post\`.""" - orderBy: [PostOrderBy!] = [PRIMARY_KEY_ASC] - ): PostConnection - - """ - Metadata about the database schema, including tables, fields, indexes, and constraints. Useful for code generation tools. - """ - _meta: MetaSchema -} - -""" -The root mutation type which contains root level fields which mutate data. -""" -type Mutation { - """Creates a single \`PostTag\`.""" - createPostTag( - """ - The exclusive input argument for this mutation. An object type, make sure to see documentation for this object’s fields. - """ - input: CreatePostTagInput! - ): CreatePostTagPayload - - """Creates a single \`Tag\`.""" - createTag( - """ - The exclusive input argument for this mutation. An object type, make sure to see documentation for this object’s fields. - """ - input: CreateTagInput! - ): CreateTagPayload - - """Creates a single \`User\`.""" - createUser( - """ - The exclusive input argument for this mutation. An object type, make sure to see documentation for this object’s fields. - """ - input: CreateUserInput! - ): CreateUserPayload - - """Creates a single \`Comment\`.""" - createComment( - """ - The exclusive input argument for this mutation. An object type, make sure to see documentation for this object’s fields. - """ - input: CreateCommentInput! - ): CreateCommentPayload - - """Creates a single \`Post\`.""" - createPost( - """ - The exclusive input argument for this mutation. An object type, make sure to see documentation for this object’s fields. - """ - input: CreatePostInput! - ): CreatePostPayload - - """Updates a single \`PostTag\` using a unique key and a patch.""" - updatePostTag( - """ - The exclusive input argument for this mutation. An object type, make sure to see documentation for this object’s fields. - """ - input: UpdatePostTagInput! - ): UpdatePostTagPayload - - """Updates a single \`Tag\` using a unique key and a patch.""" - updateTag( - """ - The exclusive input argument for this mutation. An object type, make sure to see documentation for this object’s fields. - """ - input: UpdateTagInput! - ): UpdateTagPayload - - """Updates a single \`User\` using a unique key and a patch.""" - updateUser( - """ - The exclusive input argument for this mutation. An object type, make sure to see documentation for this object’s fields. - """ - input: UpdateUserInput! - ): UpdateUserPayload - - """Updates a single \`Comment\` using a unique key and a patch.""" - updateComment( - """ - The exclusive input argument for this mutation. An object type, make sure to see documentation for this object’s fields. - """ - input: UpdateCommentInput! - ): UpdateCommentPayload - - """Updates a single \`Post\` using a unique key and a patch.""" - updatePost( - """ - The exclusive input argument for this mutation. An object type, make sure to see documentation for this object’s fields. - """ - input: UpdatePostInput! - ): UpdatePostPayload - - """Deletes a single \`PostTag\` using a unique key.""" - deletePostTag( - """ - The exclusive input argument for this mutation. An object type, make sure to see documentation for this object’s fields. - """ - input: DeletePostTagInput! - ): DeletePostTagPayload - - """Deletes a single \`Tag\` using a unique key.""" - deleteTag( - """ - The exclusive input argument for this mutation. An object type, make sure to see documentation for this object’s fields. - """ - input: DeleteTagInput! - ): DeleteTagPayload - - """Deletes a single \`User\` using a unique key.""" - deleteUser( - """ - The exclusive input argument for this mutation. An object type, make sure to see documentation for this object’s fields. - """ - input: DeleteUserInput! - ): DeleteUserPayload - - """Deletes a single \`Comment\` using a unique key.""" - deleteComment( - """ - The exclusive input argument for this mutation. An object type, make sure to see documentation for this object’s fields. - """ - input: DeleteCommentInput! - ): DeleteCommentPayload - - """Deletes a single \`Post\` using a unique key.""" - deletePost( - """ - The exclusive input argument for this mutation. An object type, make sure to see documentation for this object’s fields. - """ - input: DeletePostInput! - ): DeletePostPayload - - """ - Request a presigned URL for uploading a file directly to S3. - Client computes SHA-256 of the file content and provides it here. - If a file with the same hash already exists (dedup), returns the - existing file ID and deduplicated=true with no uploadUrl. - """ - requestUploadUrl( - """ - The exclusive input argument for this mutation. An object type, make sure to see documentation for this object’s fields. - """ - input: RequestUploadUrlInput! - ): RequestUploadUrlPayload - - """ - Request presigned URLs for uploading multiple files in a single batch. - Subject to per-storage-module limits (max_bulk_files, max_bulk_total_size). - Each file is processed independently — some may dedup while others get fresh URLs. - """ - requestBulkUploadUrls( - """ - The exclusive input argument for this mutation. An object type, make sure to see documentation for this object’s fields. - """ - input: RequestBulkUploadUrlsInput! - ): RequestBulkUploadUrlsPayload - - """ - Provision an S3 bucket for a logical bucket in the database. - Reads the bucket config via RLS, then creates and configures - the S3 bucket with the appropriate privacy policies, CORS rules, - and lifecycle settings. - """ - provisionBucket( - """ - The exclusive input argument for this mutation. An object type, make sure to see documentation for this object’s fields. - """ - input: ProvisionBucketInput! - ): ProvisionBucketPayload -} - -input ProvisionBucketInput { - """The logical bucket key (e.g., "public", "private")""" - bucketKey: String! - - """ - Owner entity ID for entity-scoped bucket provisioning. - Omit for app-level (database-wide) storage. - """ - ownerId: UUID -} - -type ProvisionBucketPayload { - """Whether provisioning succeeded""" - success: Boolean! - - """The S3 bucket name that was provisioned""" - bucketName: String! - - """The access type applied""" - accessType: String! - - """The storage provider used""" - provider: String! - - """The S3 endpoint (null for AWS S3 default)""" - endpoint: String - - """Error message if provisioning failed""" - error: String -}" -`; diff --git a/graphql/server-test/__tests__/upload.integration.test.ts b/graphql/server-test/__tests__/upload.integration.test.ts index bd7b26cf9..5668bad2b 100644 --- a/graphql/server-test/__tests__/upload.integration.test.ts +++ b/graphql/server-test/__tests__/upload.integration.test.ts @@ -43,19 +43,21 @@ const seedFiles = [ const REQUEST_UPLOAD_URL = ` query RequestUploadUrl($key: String!, $contentHash: String!, $contentType: String!, $size: Int!, $filename: String) { - bucketByKey(key: $key) { - id - requestUploadUrl( - contentHash: $contentHash - contentType: $contentType - size: $size - filename: $filename - ) { - uploadUrl - fileId - key - deduplicated - expiresAt + buckets(condition: { key: $key }) { + nodes { + id + requestUploadUrl( + contentHash: $contentHash + contentType: $contentType + size: $size + filename: $filename + ) { + uploadUrl + fileId + key + deduplicated + expiresAt + } } } } @@ -142,7 +144,7 @@ describe('Upload integration (per-table presigned URL flow)', () => { expect(res.status).toBe(200); expect(res.body.errors).toBeUndefined(); - const bucket = res.body.data.bucketByKey; + const bucket = res.body.data.buckets.nodes[0]; expect(bucket).toBeTruthy(); expect(bucket.id).toBeTruthy(); @@ -185,7 +187,7 @@ describe('Upload integration (per-table presigned URL flow)', () => { expect(res.status).toBe(200); expect(res.body.errors).toBeUndefined(); - const bucket = res.body.data.bucketByKey; + const bucket = res.body.data.buckets.nodes[0]; expect(bucket).toBeTruthy(); const payload = bucket.requestUploadUrl; @@ -224,7 +226,7 @@ describe('Upload integration (per-table presigned URL flow)', () => { expect(res.status).toBe(200); expect(res.body.errors).toBeUndefined(); - const payload = res.body.data.bucketByKey.requestUploadUrl; + const payload = res.body.data.buckets.nodes[0].requestUploadUrl; expect(payload.deduplicated).toBe(true); expect(payload.uploadUrl).toBeNull(); expect(payload.expiresAt).toBeNull(); diff --git a/graphql/test/__tests__/__snapshots__/graphile-test.test.ts.snap b/graphql/test/__tests__/__snapshots__/graphile-test.test.ts.snap deleted file mode 100644 index 68edec297..000000000 --- a/graphql/test/__tests__/__snapshots__/graphile-test.test.ts.snap +++ /dev/null @@ -1,5028 +0,0 @@ -// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing - -exports[`introspection query snapshot: introspection 1`] = ` -{ - "data": { - "__schema": { - "directives": [ - { - "args": [ - { - "defaultValue": null, - "description": "Included when true.", - "name": "if", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null, - }, - }, - }, - ], - "description": "Directs the executor to include this field or fragment only when the \`if\` argument is true.", - "locations": [ - "FIELD", - "FRAGMENT_SPREAD", - "INLINE_FRAGMENT", - ], - "name": "include", - }, - { - "args": [ - { - "defaultValue": null, - "description": "Skipped when true.", - "name": "if", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null, - }, - }, - }, - ], - "description": "Directs the executor to skip this field or fragment when the \`if\` argument is true.", - "locations": [ - "FIELD", - "FRAGMENT_SPREAD", - "INLINE_FRAGMENT", - ], - "name": "skip", - }, - { - "args": [ - { - "defaultValue": ""No longer supported"", - "description": "Explains why this element was deprecated, usually also including a suggestion for how to access supported similar data. Formatted using the Markdown syntax, as specified by [CommonMark](https://commonmark.org/).", - "name": "reason", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - ], - "description": "Marks an element of a GraphQL schema as no longer supported.", - "locations": [ - "FIELD_DEFINITION", - "ARGUMENT_DEFINITION", - "INPUT_FIELD_DEFINITION", - "ENUM_VALUE", - ], - "name": "deprecated", - }, - { - "args": [ - { - "defaultValue": null, - "description": "The URL that specifies the behavior of this scalar.", - "name": "url", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - }, - ], - "description": "Exposes a URL that specifies the behavior of this scalar.", - "locations": [ - "SCALAR", - ], - "name": "specifiedBy", - }, - { - "args": [], - "description": "Indicates exactly one field must be supplied and this field must not be \`null\`.", - "locations": [ - "INPUT_OBJECT", - ], - "name": "oneOf", - }, - ], - "mutationType": { - "name": "Mutation", - }, - "queryType": { - "name": "Query", - }, - "subscriptionType": null, - "types": [ - { - "description": "A connection to a list of \`User\` values.", - "enumValues": null, - "fields": [ - { - "args": [], - "deprecationReason": null, - "description": "A list of \`User\` objects.", - "isDeprecated": false, - "name": "nodes", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "User", - "ofType": null, - }, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": "A list of edges which contains the \`User\` and cursor to aid in pagination.", - "isDeprecated": false, - "name": "edges", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "UserEdge", - "ofType": null, - }, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": "Information to aid in pagination.", - "isDeprecated": false, - "name": "pageInfo", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "PageInfo", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": "The count of *all* \`User\` you could get from the connection.", - "isDeprecated": false, - "name": "totalCount", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null, - }, - }, - }, - ], - "inputFields": null, - "interfaces": [], - "kind": "OBJECT", - "name": "UserConnection", - "possibleTypes": null, - }, - { - "description": null, - "enumValues": null, - "fields": [ - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "id", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "username", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - }, - ], - "inputFields": null, - "interfaces": [], - "kind": "OBJECT", - "name": "User", - "possibleTypes": null, - }, - { - "description": "The \`Int\` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.", - "enumValues": null, - "fields": null, - "inputFields": null, - "interfaces": null, - "kind": "SCALAR", - "name": "Int", - "possibleTypes": null, - }, - { - "description": "The \`String\` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.", - "enumValues": null, - "fields": null, - "inputFields": null, - "interfaces": null, - "kind": "SCALAR", - "name": "String", - "possibleTypes": null, - }, - { - "description": "A \`User\` edge in the connection.", - "enumValues": null, - "fields": [ - { - "args": [], - "deprecationReason": null, - "description": "A cursor for use in pagination.", - "isDeprecated": false, - "name": "cursor", - "type": { - "kind": "SCALAR", - "name": "Cursor", - "ofType": null, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": "The \`User\` at the end of the edge.", - "isDeprecated": false, - "name": "node", - "type": { - "kind": "OBJECT", - "name": "User", - "ofType": null, - }, - }, - ], - "inputFields": null, - "interfaces": [], - "kind": "OBJECT", - "name": "UserEdge", - "possibleTypes": null, - }, - { - "description": "A location in a connection that can be used for resuming pagination.", - "enumValues": null, - "fields": null, - "inputFields": null, - "interfaces": null, - "kind": "SCALAR", - "name": "Cursor", - "possibleTypes": null, - }, - { - "description": "Information about pagination in a connection.", - "enumValues": null, - "fields": [ - { - "args": [], - "deprecationReason": null, - "description": "When paginating forwards, are there more items?", - "isDeprecated": false, - "name": "hasNextPage", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": "When paginating backwards, are there more items?", - "isDeprecated": false, - "name": "hasPreviousPage", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": "When paginating backwards, the cursor to continue.", - "isDeprecated": false, - "name": "startCursor", - "type": { - "kind": "SCALAR", - "name": "Cursor", - "ofType": null, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": "When paginating forwards, the cursor to continue.", - "isDeprecated": false, - "name": "endCursor", - "type": { - "kind": "SCALAR", - "name": "Cursor", - "ofType": null, - }, - }, - ], - "inputFields": null, - "interfaces": [], - "kind": "OBJECT", - "name": "PageInfo", - "possibleTypes": null, - }, - { - "description": "The \`Boolean\` scalar type represents \`true\` or \`false\`.", - "enumValues": null, - "fields": null, - "inputFields": null, - "interfaces": null, - "kind": "SCALAR", - "name": "Boolean", - "possibleTypes": null, - }, - { - "description": "A filter to be used against \`User\` object types. All fields are combined with a logical ‘and.’", - "enumValues": null, - "fields": null, - "inputFields": [ - { - "defaultValue": null, - "description": "Filter by the object’s \`id\` field.", - "name": "id", - "type": { - "kind": "INPUT_OBJECT", - "name": "IntFilter", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": "Filter by the object’s \`username\` field.", - "name": "username", - "type": { - "kind": "INPUT_OBJECT", - "name": "StringFilter", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": "Checks for all expressions in this list.", - "name": "and", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "UserFilter", - "ofType": null, - }, - }, - }, - }, - { - "defaultValue": null, - "description": "Checks for any expressions in this list.", - "name": "or", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "UserFilter", - "ofType": null, - }, - }, - }, - }, - { - "defaultValue": null, - "description": "Negates the expression.", - "name": "not", - "type": { - "kind": "INPUT_OBJECT", - "name": "UserFilter", - "ofType": null, - }, - }, - ], - "interfaces": null, - "kind": "INPUT_OBJECT", - "name": "UserFilter", - "possibleTypes": null, - }, - { - "description": "A filter to be used against Int fields. All fields are combined with a logical ‘and.’", - "enumValues": null, - "fields": null, - "inputFields": [ - { - "defaultValue": null, - "description": "Is null (if \`true\` is specified) or is not null (if \`false\` is specified).", - "name": "isNull", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": "Equal to the specified value.", - "name": "equalTo", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": "Not equal to the specified value.", - "name": "notEqualTo", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": "Not equal to the specified value, treating null like an ordinary value.", - "name": "distinctFrom", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": "Equal to the specified value, treating null like an ordinary value.", - "name": "notDistinctFrom", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": "Included in the specified list.", - "name": "in", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null, - }, - }, - }, - }, - { - "defaultValue": null, - "description": "Not included in the specified list.", - "name": "notIn", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null, - }, - }, - }, - }, - { - "defaultValue": null, - "description": "Less than the specified value.", - "name": "lessThan", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": "Less than or equal to the specified value.", - "name": "lessThanOrEqualTo", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": "Greater than the specified value.", - "name": "greaterThan", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": "Greater than or equal to the specified value.", - "name": "greaterThanOrEqualTo", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null, - }, - }, - ], - "interfaces": null, - "kind": "INPUT_OBJECT", - "name": "IntFilter", - "possibleTypes": null, - }, - { - "description": "A filter to be used against String fields. All fields are combined with a logical ‘and.’", - "enumValues": null, - "fields": null, - "inputFields": [ - { - "defaultValue": null, - "description": "Is null (if \`true\` is specified) or is not null (if \`false\` is specified).", - "name": "isNull", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": "Equal to the specified value.", - "name": "equalTo", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": "Not equal to the specified value.", - "name": "notEqualTo", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": "Not equal to the specified value, treating null like an ordinary value.", - "name": "distinctFrom", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": "Equal to the specified value, treating null like an ordinary value.", - "name": "notDistinctFrom", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": "Included in the specified list.", - "name": "in", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - }, - }, - { - "defaultValue": null, - "description": "Not included in the specified list.", - "name": "notIn", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - }, - }, - { - "defaultValue": null, - "description": "Less than the specified value.", - "name": "lessThan", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": "Less than or equal to the specified value.", - "name": "lessThanOrEqualTo", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": "Greater than the specified value.", - "name": "greaterThan", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": "Greater than or equal to the specified value.", - "name": "greaterThanOrEqualTo", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": "Contains the specified string (case-sensitive).", - "name": "includes", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": "Does not contain the specified string (case-sensitive).", - "name": "notIncludes", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": "Contains the specified string (case-insensitive).", - "name": "includesInsensitive", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": "Does not contain the specified string (case-insensitive).", - "name": "notIncludesInsensitive", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": "Starts with the specified string (case-sensitive).", - "name": "startsWith", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": "Does not start with the specified string (case-sensitive).", - "name": "notStartsWith", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": "Starts with the specified string (case-insensitive).", - "name": "startsWithInsensitive", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": "Does not start with the specified string (case-insensitive).", - "name": "notStartsWithInsensitive", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": "Ends with the specified string (case-sensitive).", - "name": "endsWith", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": "Does not end with the specified string (case-sensitive).", - "name": "notEndsWith", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": "Ends with the specified string (case-insensitive).", - "name": "endsWithInsensitive", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": "Does not end with the specified string (case-insensitive).", - "name": "notEndsWithInsensitive", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": "Matches the specified pattern (case-sensitive). An underscore (_) matches any single character; a percent sign (%) matches any sequence of zero or more characters.", - "name": "like", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": "Does not match the specified pattern (case-sensitive). An underscore (_) matches any single character; a percent sign (%) matches any sequence of zero or more characters.", - "name": "notLike", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": "Matches the specified pattern (case-insensitive). An underscore (_) matches any single character; a percent sign (%) matches any sequence of zero or more characters.", - "name": "likeInsensitive", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": "Does not match the specified pattern (case-insensitive). An underscore (_) matches any single character; a percent sign (%) matches any sequence of zero or more characters.", - "name": "notLikeInsensitive", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": "Equal to the specified value (case-insensitive).", - "name": "equalToInsensitive", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": "Not equal to the specified value (case-insensitive).", - "name": "notEqualToInsensitive", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": "Not equal to the specified value, treating null like an ordinary value (case-insensitive).", - "name": "distinctFromInsensitive", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": "Equal to the specified value, treating null like an ordinary value (case-insensitive).", - "name": "notDistinctFromInsensitive", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": "Included in the specified list (case-insensitive).", - "name": "inInsensitive", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - }, - }, - { - "defaultValue": null, - "description": "Not included in the specified list (case-insensitive).", - "name": "notInInsensitive", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - }, - }, - { - "defaultValue": null, - "description": "Less than the specified value (case-insensitive).", - "name": "lessThanInsensitive", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": "Less than or equal to the specified value (case-insensitive).", - "name": "lessThanOrEqualToInsensitive", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": "Greater than the specified value (case-insensitive).", - "name": "greaterThanInsensitive", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": "Greater than or equal to the specified value (case-insensitive).", - "name": "greaterThanOrEqualToInsensitive", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - ], - "interfaces": null, - "kind": "INPUT_OBJECT", - "name": "StringFilter", - "possibleTypes": null, - }, - { - "description": "Methods to use when ordering \`User\`.", - "enumValues": [ - { - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "NATURAL", - }, - { - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "PRIMARY_KEY_ASC", - }, - { - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "PRIMARY_KEY_DESC", - }, - { - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "ID_ASC", - }, - { - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "ID_DESC", - }, - { - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "USERNAME_ASC", - }, - { - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "USERNAME_DESC", - }, - ], - "fields": null, - "inputFields": null, - "interfaces": null, - "kind": "ENUM", - "name": "UserOrderBy", - "possibleTypes": null, - }, - { - "description": "Root meta schema type", - "enumValues": null, - "fields": [ - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "tables", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "MetaTable", - "ofType": null, - }, - }, - }, - }, - }, - ], - "inputFields": null, - "interfaces": [], - "kind": "OBJECT", - "name": "MetaSchema", - "possibleTypes": null, - }, - { - "description": "Information about a database table", - "enumValues": null, - "fields": [ - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "name", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "schemaName", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "fields", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "MetaField", - "ofType": null, - }, - }, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "indexes", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "MetaIndex", - "ofType": null, - }, - }, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "constraints", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "MetaConstraints", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "foreignKeyConstraints", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "MetaForeignKeyConstraint", - "ofType": null, - }, - }, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "primaryKeyConstraints", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "MetaPrimaryKeyConstraint", - "ofType": null, - }, - }, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "uniqueConstraints", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "MetaUniqueConstraint", - "ofType": null, - }, - }, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "relations", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "MetaRelations", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "inflection", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "MetaInflection", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "query", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "MetaQuery", - "ofType": null, - }, - }, - }, - ], - "inputFields": null, - "interfaces": [], - "kind": "OBJECT", - "name": "MetaTable", - "possibleTypes": null, - }, - { - "description": "Information about a table field/column", - "enumValues": null, - "fields": [ - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "name", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "type", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "MetaType", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "isNotNull", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "hasDefault", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "isPrimaryKey", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "isForeignKey", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "description", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - ], - "inputFields": null, - "interfaces": [], - "kind": "OBJECT", - "name": "MetaField", - "possibleTypes": null, - }, - { - "description": "Information about a PostgreSQL type", - "enumValues": null, - "fields": [ - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "pgType", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "gqlType", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "isArray", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "isNotNull", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "hasDefault", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "subtype", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - ], - "inputFields": null, - "interfaces": [], - "kind": "OBJECT", - "name": "MetaType", - "possibleTypes": null, - }, - { - "description": "Information about a database index", - "enumValues": null, - "fields": [ - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "name", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "isUnique", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "isPrimary", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "columns", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "fields", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "MetaField", - "ofType": null, - }, - }, - }, - }, - ], - "inputFields": null, - "interfaces": [], - "kind": "OBJECT", - "name": "MetaIndex", - "possibleTypes": null, - }, - { - "description": "Table constraints", - "enumValues": null, - "fields": [ - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "primaryKey", - "type": { - "kind": "OBJECT", - "name": "MetaPrimaryKeyConstraint", - "ofType": null, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "unique", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "MetaUniqueConstraint", - "ofType": null, - }, - }, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "foreignKey", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "MetaForeignKeyConstraint", - "ofType": null, - }, - }, - }, - }, - }, - ], - "inputFields": null, - "interfaces": [], - "kind": "OBJECT", - "name": "MetaConstraints", - "possibleTypes": null, - }, - { - "description": "Information about a primary key constraint", - "enumValues": null, - "fields": [ - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "name", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "fields", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "MetaField", - "ofType": null, - }, - }, - }, - }, - }, - ], - "inputFields": null, - "interfaces": [], - "kind": "OBJECT", - "name": "MetaPrimaryKeyConstraint", - "possibleTypes": null, - }, - { - "description": "Information about a unique constraint", - "enumValues": null, - "fields": [ - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "name", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "fields", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "MetaField", - "ofType": null, - }, - }, - }, - }, - }, - ], - "inputFields": null, - "interfaces": [], - "kind": "OBJECT", - "name": "MetaUniqueConstraint", - "possibleTypes": null, - }, - { - "description": "Information about a foreign key constraint", - "enumValues": null, - "fields": [ - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "name", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "fields", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "MetaField", - "ofType": null, - }, - }, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "referencedTable", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "referencedFields", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "refFields", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "MetaField", - "ofType": null, - }, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "refTable", - "type": { - "kind": "OBJECT", - "name": "MetaRefTable", - "ofType": null, - }, - }, - ], - "inputFields": null, - "interfaces": [], - "kind": "OBJECT", - "name": "MetaForeignKeyConstraint", - "possibleTypes": null, - }, - { - "description": "Reference to a related table", - "enumValues": null, - "fields": [ - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "name", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - }, - ], - "inputFields": null, - "interfaces": [], - "kind": "OBJECT", - "name": "MetaRefTable", - "possibleTypes": null, - }, - { - "description": "Table relations", - "enumValues": null, - "fields": [ - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "belongsTo", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "MetaBelongsToRelation", - "ofType": null, - }, - }, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "has", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "MetaHasRelation", - "ofType": null, - }, - }, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "hasOne", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "MetaHasRelation", - "ofType": null, - }, - }, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "hasMany", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "MetaHasRelation", - "ofType": null, - }, - }, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "manyToMany", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "MetaManyToManyRelation", - "ofType": null, - }, - }, - }, - }, - }, - ], - "inputFields": null, - "interfaces": [], - "kind": "OBJECT", - "name": "MetaRelations", - "possibleTypes": null, - }, - { - "description": "A belongs-to (forward FK) relation", - "enumValues": null, - "fields": [ - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "fieldName", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "isUnique", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "type", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "keys", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "MetaField", - "ofType": null, - }, - }, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "references", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "MetaRefTable", - "ofType": null, - }, - }, - }, - ], - "inputFields": null, - "interfaces": [], - "kind": "OBJECT", - "name": "MetaBelongsToRelation", - "possibleTypes": null, - }, - { - "description": "A has-one or has-many (reverse FK) relation", - "enumValues": null, - "fields": [ - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "fieldName", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "isUnique", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "type", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "keys", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "MetaField", - "ofType": null, - }, - }, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "referencedBy", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "MetaRefTable", - "ofType": null, - }, - }, - }, - ], - "inputFields": null, - "interfaces": [], - "kind": "OBJECT", - "name": "MetaHasRelation", - "possibleTypes": null, - }, - { - "description": "A many-to-many relation via junction table", - "enumValues": null, - "fields": [ - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "fieldName", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "type", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "junctionTable", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "MetaRefTable", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "junctionLeftConstraint", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "MetaForeignKeyConstraint", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "junctionLeftKeyAttributes", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "MetaField", - "ofType": null, - }, - }, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "junctionRightConstraint", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "MetaForeignKeyConstraint", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "junctionRightKeyAttributes", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "MetaField", - "ofType": null, - }, - }, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "leftKeyAttributes", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "MetaField", - "ofType": null, - }, - }, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "rightKeyAttributes", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "MetaField", - "ofType": null, - }, - }, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "rightTable", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "MetaRefTable", - "ofType": null, - }, - }, - }, - ], - "inputFields": null, - "interfaces": [], - "kind": "OBJECT", - "name": "MetaManyToManyRelation", - "possibleTypes": null, - }, - { - "description": "Table inflection names", - "enumValues": null, - "fields": [ - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "tableType", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "allRows", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "connection", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "edge", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "filterType", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "orderByType", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "conditionType", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "patchType", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "createInputType", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "createPayloadType", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "updatePayloadType", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "deletePayloadType", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - }, - ], - "inputFields": null, - "interfaces": [], - "kind": "OBJECT", - "name": "MetaInflection", - "possibleTypes": null, - }, - { - "description": "Table query/mutation names", - "enumValues": null, - "fields": [ - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "all", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "one", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "create", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "update", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "delete", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - ], - "inputFields": null, - "interfaces": [], - "kind": "OBJECT", - "name": "MetaQuery", - "possibleTypes": null, - }, - { - "description": "The output of our create \`User\` mutation.", - "enumValues": null, - "fields": [ - { - "args": [], - "deprecationReason": null, - "description": "The exact same \`clientMutationId\` that was provided in the mutation input, -unchanged and unused. May be used by a client to track mutations.", - "isDeprecated": false, - "name": "clientMutationId", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": "The \`User\` that was created by this mutation.", - "isDeprecated": false, - "name": "user", - "type": { - "kind": "OBJECT", - "name": "User", - "ofType": null, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": "Our root query field type. Allows us to run any query from our mutation payload.", - "isDeprecated": false, - "name": "query", - "type": { - "kind": "OBJECT", - "name": "Query", - "ofType": null, - }, - }, - { - "args": [ - { - "defaultValue": "[PRIMARY_KEY_ASC]", - "description": "The method to use when ordering \`User\`.", - "name": "orderBy", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "UserOrderBy", - "ofType": null, - }, - }, - }, - }, - }, - ], - "deprecationReason": null, - "description": "An edge for our \`User\`. May be used by Relay 1.", - "isDeprecated": false, - "name": "userEdge", - "type": { - "kind": "OBJECT", - "name": "UserEdge", - "ofType": null, - }, - }, - ], - "inputFields": null, - "interfaces": [], - "kind": "OBJECT", - "name": "CreateUserPayload", - "possibleTypes": null, - }, - { - "description": "All input for the create \`User\` mutation.", - "enumValues": null, - "fields": null, - "inputFields": [ - { - "defaultValue": null, - "description": "An arbitrary string value with no semantic meaning. Will be included in the -payload verbatim. May be used to track mutations by the client.", - "name": "clientMutationId", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": "The \`User\` to be created by this mutation.", - "name": "user", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "UserInput", - "ofType": null, - }, - }, - }, - ], - "interfaces": null, - "kind": "INPUT_OBJECT", - "name": "CreateUserInput", - "possibleTypes": null, - }, - { - "description": "An input for mutations affecting \`User\`", - "enumValues": null, - "fields": null, - "inputFields": [ - { - "defaultValue": null, - "description": null, - "name": "id", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": null, - "name": "username", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - }, - ], - "interfaces": null, - "kind": "INPUT_OBJECT", - "name": "UserInput", - "possibleTypes": null, - }, - { - "description": "The output of our update \`User\` mutation.", - "enumValues": null, - "fields": [ - { - "args": [], - "deprecationReason": null, - "description": "The exact same \`clientMutationId\` that was provided in the mutation input, -unchanged and unused. May be used by a client to track mutations.", - "isDeprecated": false, - "name": "clientMutationId", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": "The \`User\` that was updated by this mutation.", - "isDeprecated": false, - "name": "user", - "type": { - "kind": "OBJECT", - "name": "User", - "ofType": null, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": "Our root query field type. Allows us to run any query from our mutation payload.", - "isDeprecated": false, - "name": "query", - "type": { - "kind": "OBJECT", - "name": "Query", - "ofType": null, - }, - }, - { - "args": [ - { - "defaultValue": "[PRIMARY_KEY_ASC]", - "description": "The method to use when ordering \`User\`.", - "name": "orderBy", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "UserOrderBy", - "ofType": null, - }, - }, - }, - }, - }, - ], - "deprecationReason": null, - "description": "An edge for our \`User\`. May be used by Relay 1.", - "isDeprecated": false, - "name": "userEdge", - "type": { - "kind": "OBJECT", - "name": "UserEdge", - "ofType": null, - }, - }, - ], - "inputFields": null, - "interfaces": [], - "kind": "OBJECT", - "name": "UpdateUserPayload", - "possibleTypes": null, - }, - { - "description": "All input for the \`updateUser\` mutation.", - "enumValues": null, - "fields": null, - "inputFields": [ - { - "defaultValue": null, - "description": "An arbitrary string value with no semantic meaning. Will be included in the -payload verbatim. May be used to track mutations by the client.", - "name": "clientMutationId", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": null, - "name": "id", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null, - }, - }, - }, - { - "defaultValue": null, - "description": "An object where the defined keys will be set on the \`User\` being updated.", - "name": "userPatch", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "UserPatch", - "ofType": null, - }, - }, - }, - ], - "interfaces": null, - "kind": "INPUT_OBJECT", - "name": "UpdateUserInput", - "possibleTypes": null, - }, - { - "description": "Represents an update to a \`User\`. Fields that are set will be updated.", - "enumValues": null, - "fields": null, - "inputFields": [ - { - "defaultValue": null, - "description": null, - "name": "id", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": null, - "name": "username", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - ], - "interfaces": null, - "kind": "INPUT_OBJECT", - "name": "UserPatch", - "possibleTypes": null, - }, - { - "description": "The output of our delete \`User\` mutation.", - "enumValues": null, - "fields": [ - { - "args": [], - "deprecationReason": null, - "description": "The exact same \`clientMutationId\` that was provided in the mutation input, -unchanged and unused. May be used by a client to track mutations.", - "isDeprecated": false, - "name": "clientMutationId", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": "The \`User\` that was deleted by this mutation.", - "isDeprecated": false, - "name": "user", - "type": { - "kind": "OBJECT", - "name": "User", - "ofType": null, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": "Our root query field type. Allows us to run any query from our mutation payload.", - "isDeprecated": false, - "name": "query", - "type": { - "kind": "OBJECT", - "name": "Query", - "ofType": null, - }, - }, - { - "args": [ - { - "defaultValue": "[PRIMARY_KEY_ASC]", - "description": "The method to use when ordering \`User\`.", - "name": "orderBy", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "UserOrderBy", - "ofType": null, - }, - }, - }, - }, - }, - ], - "deprecationReason": null, - "description": "An edge for our \`User\`. May be used by Relay 1.", - "isDeprecated": false, - "name": "userEdge", - "type": { - "kind": "OBJECT", - "name": "UserEdge", - "ofType": null, - }, - }, - ], - "inputFields": null, - "interfaces": [], - "kind": "OBJECT", - "name": "DeleteUserPayload", - "possibleTypes": null, - }, - { - "description": "All input for the \`deleteUser\` mutation.", - "enumValues": null, - "fields": null, - "inputFields": [ - { - "defaultValue": null, - "description": "An arbitrary string value with no semantic meaning. Will be included in the -payload verbatim. May be used to track mutations by the client.", - "name": "clientMutationId", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": null, - "name": "id", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null, - }, - }, - }, - ], - "interfaces": null, - "kind": "INPUT_OBJECT", - "name": "DeleteUserInput", - "possibleTypes": null, - }, - { - "description": null, - "enumValues": null, - "fields": null, - "inputFields": [ - { - "defaultValue": null, - "description": "Bucket key (e.g., "public", "private")", - "name": "bucketKey", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - }, - { - "defaultValue": null, - "description": "Owner entity ID for entity-scoped uploads. -Omit for app-level (database-wide) storage. -When provided, resolves the storage module for the entity type -that owns this entity instance (e.g., a data room ID, team ID).", - "name": "ownerId", - "type": { - "kind": "SCALAR", - "name": "UUID", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": "SHA-256 content hash computed by the client (hex-encoded, 64 chars)", - "name": "contentHash", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - }, - { - "defaultValue": null, - "description": "MIME type of the file (e.g., "image/png")", - "name": "contentType", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - }, - { - "defaultValue": null, - "description": "File size in bytes", - "name": "size", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null, - }, - }, - }, - { - "defaultValue": null, - "description": "Original filename (optional, for display and Content-Disposition)", - "name": "filename", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": "Custom S3 key (e.g., "reports/2024/Q1.pdf"). -Only allowed when the bucket has allow_custom_keys=true. -When omitted, key defaults to contentHash (content-addressed dedup). -When provided, the file is stored at this key. -Re-uploading to an existing key auto-creates a new version.", - "name": "key", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - ], - "interfaces": null, - "kind": "INPUT_OBJECT", - "name": "RequestUploadUrlInput", - "possibleTypes": null, - }, - { - "description": "A universally unique identifier as defined by [RFC 4122](https://tools.ietf.org/html/rfc4122).", - "enumValues": null, - "fields": null, - "inputFields": null, - "interfaces": null, - "kind": "SCALAR", - "name": "UUID", - "possibleTypes": null, - }, - { - "description": null, - "enumValues": null, - "fields": [ - { - "args": [], - "deprecationReason": null, - "description": "Presigned PUT URL (null if file was deduplicated)", - "isDeprecated": false, - "name": "uploadUrl", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": "The file ID (existing if deduplicated, new if fresh upload)", - "isDeprecated": false, - "name": "fileId", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "UUID", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": "The S3 object key", - "isDeprecated": false, - "name": "key", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": "Whether this file was deduplicated (already exists with same hash)", - "isDeprecated": false, - "name": "deduplicated", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": "Presigned URL expiry time (null if deduplicated)", - "isDeprecated": false, - "name": "expiresAt", - "type": { - "kind": "SCALAR", - "name": "Datetime", - "ofType": null, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": "ID of the previous version (set when re-uploading to an existing custom key)", - "isDeprecated": false, - "name": "previousVersionId", - "type": { - "kind": "SCALAR", - "name": "UUID", - "ofType": null, - }, - }, - ], - "inputFields": null, - "interfaces": [], - "kind": "OBJECT", - "name": "RequestUploadUrlPayload", - "possibleTypes": null, - }, - { - "description": "A point in time as described by the [ISO -8601](https://en.wikipedia.org/wiki/ISO_8601) and, if it has a timezone, [RFC -3339](https://datatracker.ietf.org/doc/html/rfc3339) standards. Input values -that do not conform to both ISO 8601 and RFC 3339 may be coerced, which may lead -to unexpected results.", - "enumValues": null, - "fields": null, - "inputFields": null, - "interfaces": null, - "kind": "SCALAR", - "name": "Datetime", - "possibleTypes": null, - }, - { - "description": null, - "enumValues": null, - "fields": null, - "inputFields": [ - { - "defaultValue": null, - "description": "SHA-256 content hash computed by the client (hex-encoded, 64 chars)", - "name": "contentHash", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - }, - { - "defaultValue": null, - "description": "MIME type of the file (e.g., "image/png")", - "name": "contentType", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - }, - { - "defaultValue": null, - "description": "File size in bytes", - "name": "size", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null, - }, - }, - }, - { - "defaultValue": null, - "description": "Original filename (optional, for display and Content-Disposition)", - "name": "filename", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": "Custom S3 key (only when bucket has allow_custom_keys=true)", - "name": "key", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - ], - "interfaces": null, - "kind": "INPUT_OBJECT", - "name": "BulkUploadFileInput", - "possibleTypes": null, - }, - { - "description": null, - "enumValues": null, - "fields": null, - "inputFields": [ - { - "defaultValue": null, - "description": "Bucket key (e.g., "public", "private")", - "name": "bucketKey", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - }, - { - "defaultValue": null, - "description": "Owner entity ID for entity-scoped uploads", - "name": "ownerId", - "type": { - "kind": "SCALAR", - "name": "UUID", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": "Array of files to upload", - "name": "files", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "BulkUploadFileInput", - "ofType": null, - }, - }, - }, - }, - }, - ], - "interfaces": null, - "kind": "INPUT_OBJECT", - "name": "RequestBulkUploadUrlsInput", - "possibleTypes": null, - }, - { - "description": null, - "enumValues": null, - "fields": [ - { - "args": [], - "deprecationReason": null, - "description": "Presigned PUT URL (null if file was deduplicated)", - "isDeprecated": false, - "name": "uploadUrl", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": "The file ID", - "isDeprecated": false, - "name": "fileId", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "UUID", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": "The S3 object key", - "isDeprecated": false, - "name": "key", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": "Whether this file was deduplicated", - "isDeprecated": false, - "name": "deduplicated", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": "Presigned URL expiry time (null if deduplicated)", - "isDeprecated": false, - "name": "expiresAt", - "type": { - "kind": "SCALAR", - "name": "Datetime", - "ofType": null, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": "ID of the previous version (set when re-uploading to an existing custom key)", - "isDeprecated": false, - "name": "previousVersionId", - "type": { - "kind": "SCALAR", - "name": "UUID", - "ofType": null, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": "Index of this file in the input array (for client correlation)", - "isDeprecated": false, - "name": "index", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null, - }, - }, - }, - ], - "inputFields": null, - "interfaces": [], - "kind": "OBJECT", - "name": "BulkUploadFilePayload", - "possibleTypes": null, - }, - { - "description": null, - "enumValues": null, - "fields": [ - { - "args": [], - "deprecationReason": null, - "description": "Array of results, one per input file", - "isDeprecated": false, - "name": "files", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "BulkUploadFilePayload", - "ofType": null, - }, - }, - }, - }, - }, - ], - "inputFields": null, - "interfaces": [], - "kind": "OBJECT", - "name": "RequestBulkUploadUrlsPayload", - "possibleTypes": null, - }, - { - "description": "The root query type which gives access points into the data universe.", - "enumValues": null, - "fields": [ - { - "args": [ - { - "defaultValue": null, - "description": "Only read the first \`n\` values of the set.", - "name": "first", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": "Only read the last \`n\` values of the set.", - "name": "last", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": "Skip the first \`n\` values from our \`after\` cursor, an alternative to cursor -based pagination. May not be used with \`last\`.", - "name": "offset", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": "Read all values in the set before (above) this cursor.", - "name": "before", - "type": { - "kind": "SCALAR", - "name": "Cursor", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": "Read all values in the set after (below) this cursor.", - "name": "after", - "type": { - "kind": "SCALAR", - "name": "Cursor", - "ofType": null, - }, - }, - { - "defaultValue": null, - "description": "A filter to be used in determining which values should be returned by the collection.", - "name": "where", - "type": { - "kind": "INPUT_OBJECT", - "name": "UserFilter", - "ofType": null, - }, - }, - { - "defaultValue": "[PRIMARY_KEY_ASC]", - "description": "The method to use when ordering \`User\`.", - "name": "orderBy", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "UserOrderBy", - "ofType": null, - }, - }, - }, - }, - ], - "deprecationReason": null, - "description": "Reads and enables pagination through a set of \`User\`.", - "isDeprecated": false, - "name": "users", - "type": { - "kind": "OBJECT", - "name": "UserConnection", - "ofType": null, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": "Metadata about the database schema, including tables, fields, indexes, and constraints. Useful for code generation tools.", - "isDeprecated": false, - "name": "_meta", - "type": { - "kind": "OBJECT", - "name": "MetaSchema", - "ofType": null, - }, - }, - ], - "inputFields": null, - "interfaces": [], - "kind": "OBJECT", - "name": "Query", - "possibleTypes": null, - }, - { - "description": "The root mutation type which contains root level fields which mutate data.", - "enumValues": null, - "fields": [ - { - "args": [ - { - "defaultValue": null, - "description": "The exclusive input argument for this mutation. An object type, make sure to see documentation for this object’s fields.", - "name": "input", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "CreateUserInput", - "ofType": null, - }, - }, - }, - ], - "deprecationReason": null, - "description": "Creates a single \`User\`.", - "isDeprecated": false, - "name": "createUser", - "type": { - "kind": "OBJECT", - "name": "CreateUserPayload", - "ofType": null, - }, - }, - { - "args": [ - { - "defaultValue": null, - "description": "The exclusive input argument for this mutation. An object type, make sure to see documentation for this object’s fields.", - "name": "input", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "UpdateUserInput", - "ofType": null, - }, - }, - }, - ], - "deprecationReason": null, - "description": "Updates a single \`User\` using a unique key and a patch.", - "isDeprecated": false, - "name": "updateUser", - "type": { - "kind": "OBJECT", - "name": "UpdateUserPayload", - "ofType": null, - }, - }, - { - "args": [ - { - "defaultValue": null, - "description": "The exclusive input argument for this mutation. An object type, make sure to see documentation for this object’s fields.", - "name": "input", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "DeleteUserInput", - "ofType": null, - }, - }, - }, - ], - "deprecationReason": null, - "description": "Deletes a single \`User\` using a unique key.", - "isDeprecated": false, - "name": "deleteUser", - "type": { - "kind": "OBJECT", - "name": "DeleteUserPayload", - "ofType": null, - }, - }, - { - "args": [ - { - "defaultValue": null, - "description": "The exclusive input argument for this mutation. An object type, make sure to see documentation for this object’s fields.", - "name": "input", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "RequestUploadUrlInput", - "ofType": null, - }, - }, - }, - ], - "deprecationReason": null, - "description": "Request a presigned URL for uploading a file directly to S3. -Client computes SHA-256 of the file content and provides it here. -If a file with the same hash already exists (dedup), returns the -existing file ID and deduplicated=true with no uploadUrl.", - "isDeprecated": false, - "name": "requestUploadUrl", - "type": { - "kind": "OBJECT", - "name": "RequestUploadUrlPayload", - "ofType": null, - }, - }, - { - "args": [ - { - "defaultValue": null, - "description": "The exclusive input argument for this mutation. An object type, make sure to see documentation for this object’s fields.", - "name": "input", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "RequestBulkUploadUrlsInput", - "ofType": null, - }, - }, - }, - ], - "deprecationReason": null, - "description": "Request presigned URLs for uploading multiple files in a single batch. -Subject to per-storage-module limits (max_bulk_files, max_bulk_total_size). -Each file is processed independently — some may dedup while others get fresh URLs.", - "isDeprecated": false, - "name": "requestBulkUploadUrls", - "type": { - "kind": "OBJECT", - "name": "RequestBulkUploadUrlsPayload", - "ofType": null, - }, - }, - { - "args": [ - { - "defaultValue": null, - "description": "The exclusive input argument for this mutation. An object type, make sure to see documentation for this object’s fields.", - "name": "input", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "ProvisionBucketInput", - "ofType": null, - }, - }, - }, - ], - "deprecationReason": null, - "description": "Provision an S3 bucket for a logical bucket in the database. -Reads the bucket config via RLS, then creates and configures -the S3 bucket with the appropriate privacy policies, CORS rules, -and lifecycle settings.", - "isDeprecated": false, - "name": "provisionBucket", - "type": { - "kind": "OBJECT", - "name": "ProvisionBucketPayload", - "ofType": null, - }, - }, - ], - "inputFields": null, - "interfaces": [], - "kind": "OBJECT", - "name": "Mutation", - "possibleTypes": null, - }, - { - "description": null, - "enumValues": null, - "fields": null, - "inputFields": [ - { - "defaultValue": null, - "description": "The logical bucket key (e.g., "public", "private")", - "name": "bucketKey", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - }, - { - "defaultValue": null, - "description": "Owner entity ID for entity-scoped bucket provisioning. -Omit for app-level (database-wide) storage.", - "name": "ownerId", - "type": { - "kind": "SCALAR", - "name": "UUID", - "ofType": null, - }, - }, - ], - "interfaces": null, - "kind": "INPUT_OBJECT", - "name": "ProvisionBucketInput", - "possibleTypes": null, - }, - { - "description": null, - "enumValues": null, - "fields": [ - { - "args": [], - "deprecationReason": null, - "description": "Whether provisioning succeeded", - "isDeprecated": false, - "name": "success", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": "The S3 bucket name that was provisioned", - "isDeprecated": false, - "name": "bucketName", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": "The access type applied", - "isDeprecated": false, - "name": "accessType", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": "The storage provider used", - "isDeprecated": false, - "name": "provider", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": "The S3 endpoint (null for AWS S3 default)", - "isDeprecated": false, - "name": "endpoint", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": "Error message if provisioning failed", - "isDeprecated": false, - "name": "error", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - ], - "inputFields": null, - "interfaces": [], - "kind": "OBJECT", - "name": "ProvisionBucketPayload", - "possibleTypes": null, - }, - { - "description": "A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, as well as the entry points for query, mutation, and subscription operations.", - "enumValues": null, - "fields": [ - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "description", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": "A list of all types supported by this server.", - "isDeprecated": false, - "name": "types", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__Type", - "ofType": null, - }, - }, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": "The type that query operations will be rooted at.", - "isDeprecated": false, - "name": "queryType", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__Type", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": "If this server supports mutation, the type that mutation operations will be rooted at.", - "isDeprecated": false, - "name": "mutationType", - "type": { - "kind": "OBJECT", - "name": "__Type", - "ofType": null, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": "If this server support subscription, the type that subscription operations will be rooted at.", - "isDeprecated": false, - "name": "subscriptionType", - "type": { - "kind": "OBJECT", - "name": "__Type", - "ofType": null, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": "A list of all directives supported by this server.", - "isDeprecated": false, - "name": "directives", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__Directive", - "ofType": null, - }, - }, - }, - }, - }, - ], - "inputFields": null, - "interfaces": [], - "kind": "OBJECT", - "name": "__Schema", - "possibleTypes": null, - }, - { - "description": "The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in GraphQL as represented by the \`__TypeKind\` enum. - -Depending on the kind of a type, certain fields describe information about that type. Scalar types provide no information beyond a name, description and optional \`specifiedByURL\`, while Enum types provide their values. Object and Interface types provide the fields they describe. Abstract types, Union and Interface, provide the Object types possible at runtime. List and NonNull types compose other types.", - "enumValues": null, - "fields": [ - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "kind", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "__TypeKind", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "name", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "description", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "specifiedByURL", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "args": [ - { - "defaultValue": "false", - "description": null, - "name": "includeDeprecated", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null, - }, - }, - ], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "fields", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__Field", - "ofType": null, - }, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "interfaces", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__Type", - "ofType": null, - }, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "possibleTypes", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__Type", - "ofType": null, - }, - }, - }, - }, - { - "args": [ - { - "defaultValue": "false", - "description": null, - "name": "includeDeprecated", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null, - }, - }, - ], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "enumValues", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__EnumValue", - "ofType": null, - }, - }, - }, - }, - { - "args": [ - { - "defaultValue": "false", - "description": null, - "name": "includeDeprecated", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null, - }, - }, - ], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "inputFields", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__InputValue", - "ofType": null, - }, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "ofType", - "type": { - "kind": "OBJECT", - "name": "__Type", - "ofType": null, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "isOneOf", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null, - }, - }, - ], - "inputFields": null, - "interfaces": [], - "kind": "OBJECT", - "name": "__Type", - "possibleTypes": null, - }, - { - "description": "An enum describing what kind of type a given \`__Type\` is.", - "enumValues": [ - { - "deprecationReason": null, - "description": "Indicates this type is a scalar.", - "isDeprecated": false, - "name": "SCALAR", - }, - { - "deprecationReason": null, - "description": "Indicates this type is an object. \`fields\` and \`interfaces\` are valid fields.", - "isDeprecated": false, - "name": "OBJECT", - }, - { - "deprecationReason": null, - "description": "Indicates this type is an interface. \`fields\`, \`interfaces\`, and \`possibleTypes\` are valid fields.", - "isDeprecated": false, - "name": "INTERFACE", - }, - { - "deprecationReason": null, - "description": "Indicates this type is a union. \`possibleTypes\` is a valid field.", - "isDeprecated": false, - "name": "UNION", - }, - { - "deprecationReason": null, - "description": "Indicates this type is an enum. \`enumValues\` is a valid field.", - "isDeprecated": false, - "name": "ENUM", - }, - { - "deprecationReason": null, - "description": "Indicates this type is an input object. \`inputFields\` is a valid field.", - "isDeprecated": false, - "name": "INPUT_OBJECT", - }, - { - "deprecationReason": null, - "description": "Indicates this type is a list. \`ofType\` is a valid field.", - "isDeprecated": false, - "name": "LIST", - }, - { - "deprecationReason": null, - "description": "Indicates this type is a non-null. \`ofType\` is a valid field.", - "isDeprecated": false, - "name": "NON_NULL", - }, - ], - "fields": null, - "inputFields": null, - "interfaces": null, - "kind": "ENUM", - "name": "__TypeKind", - "possibleTypes": null, - }, - { - "description": "Object and Interface types are described by a list of Fields, each of which has a name, potentially a list of arguments, and a return type.", - "enumValues": null, - "fields": [ - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "name", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "description", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "args": [ - { - "defaultValue": "false", - "description": null, - "name": "includeDeprecated", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null, - }, - }, - ], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "args", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__InputValue", - "ofType": null, - }, - }, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "type", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__Type", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "isDeprecated", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "deprecationReason", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - ], - "inputFields": null, - "interfaces": [], - "kind": "OBJECT", - "name": "__Field", - "possibleTypes": null, - }, - { - "description": "Arguments provided to Fields or Directives and the input fields of an InputObject are represented as Input Values which describe their type and optionally a default value.", - "enumValues": null, - "fields": [ - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "name", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "description", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "type", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__Type", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": "A GraphQL-formatted string representing the default value for this input value.", - "isDeprecated": false, - "name": "defaultValue", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "isDeprecated", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "deprecationReason", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - ], - "inputFields": null, - "interfaces": [], - "kind": "OBJECT", - "name": "__InputValue", - "possibleTypes": null, - }, - { - "description": "One possible value for a given Enum. Enum values are unique values, not a placeholder for a string or numeric value. However an Enum value is returned in a JSON response as a string.", - "enumValues": null, - "fields": [ - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "name", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "description", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "isDeprecated", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "deprecationReason", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - ], - "inputFields": null, - "interfaces": [], - "kind": "OBJECT", - "name": "__EnumValue", - "possibleTypes": null, - }, - { - "description": "A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document. - -In some cases, you need to provide options to alter GraphQL's execution behavior in ways field arguments will not suffice, such as conditionally including or skipping a field. Directives provide this by describing additional information to the executor.", - "enumValues": null, - "fields": [ - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "name", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "description", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "isRepeatable", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null, - }, - }, - }, - { - "args": [], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "locations", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "__DirectiveLocation", - "ofType": null, - }, - }, - }, - }, - }, - { - "args": [ - { - "defaultValue": "false", - "description": null, - "name": "includeDeprecated", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null, - }, - }, - ], - "deprecationReason": null, - "description": null, - "isDeprecated": false, - "name": "args", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__InputValue", - "ofType": null, - }, - }, - }, - }, - }, - ], - "inputFields": null, - "interfaces": [], - "kind": "OBJECT", - "name": "__Directive", - "possibleTypes": null, - }, - { - "description": "A Directive can be adjacent to many parts of the GraphQL language, a __DirectiveLocation describes one such possible adjacencies.", - "enumValues": [ - { - "deprecationReason": null, - "description": "Location adjacent to a query operation.", - "isDeprecated": false, - "name": "QUERY", - }, - { - "deprecationReason": null, - "description": "Location adjacent to a mutation operation.", - "isDeprecated": false, - "name": "MUTATION", - }, - { - "deprecationReason": null, - "description": "Location adjacent to a subscription operation.", - "isDeprecated": false, - "name": "SUBSCRIPTION", - }, - { - "deprecationReason": null, - "description": "Location adjacent to a field.", - "isDeprecated": false, - "name": "FIELD", - }, - { - "deprecationReason": null, - "description": "Location adjacent to a fragment definition.", - "isDeprecated": false, - "name": "FRAGMENT_DEFINITION", - }, - { - "deprecationReason": null, - "description": "Location adjacent to a fragment spread.", - "isDeprecated": false, - "name": "FRAGMENT_SPREAD", - }, - { - "deprecationReason": null, - "description": "Location adjacent to an inline fragment.", - "isDeprecated": false, - "name": "INLINE_FRAGMENT", - }, - { - "deprecationReason": null, - "description": "Location adjacent to a variable definition.", - "isDeprecated": false, - "name": "VARIABLE_DEFINITION", - }, - { - "deprecationReason": null, - "description": "Location adjacent to a schema definition.", - "isDeprecated": false, - "name": "SCHEMA", - }, - { - "deprecationReason": null, - "description": "Location adjacent to a scalar definition.", - "isDeprecated": false, - "name": "SCALAR", - }, - { - "deprecationReason": null, - "description": "Location adjacent to an object type definition.", - "isDeprecated": false, - "name": "OBJECT", - }, - { - "deprecationReason": null, - "description": "Location adjacent to a field definition.", - "isDeprecated": false, - "name": "FIELD_DEFINITION", - }, - { - "deprecationReason": null, - "description": "Location adjacent to an argument definition.", - "isDeprecated": false, - "name": "ARGUMENT_DEFINITION", - }, - { - "deprecationReason": null, - "description": "Location adjacent to an interface definition.", - "isDeprecated": false, - "name": "INTERFACE", - }, - { - "deprecationReason": null, - "description": "Location adjacent to a union definition.", - "isDeprecated": false, - "name": "UNION", - }, - { - "deprecationReason": null, - "description": "Location adjacent to an enum definition.", - "isDeprecated": false, - "name": "ENUM", - }, - { - "deprecationReason": null, - "description": "Location adjacent to an enum value definition.", - "isDeprecated": false, - "name": "ENUM_VALUE", - }, - { - "deprecationReason": null, - "description": "Location adjacent to an input object type definition.", - "isDeprecated": false, - "name": "INPUT_OBJECT", - }, - { - "deprecationReason": null, - "description": "Location adjacent to an input object field definition.", - "isDeprecated": false, - "name": "INPUT_FIELD_DEFINITION", - }, - ], - "fields": null, - "inputFields": null, - "interfaces": null, - "kind": "ENUM", - "name": "__DirectiveLocation", - "possibleTypes": null, - }, - ], - }, - }, -} -`; From ab4a772a1c7d8b9141a53fdc084c24d9cf28b7b9 Mon Sep 17 00:00:00 2001 From: Dan Lynch Date: Thu, 7 May 2026 00:29:33 +0000 Subject: [PATCH 4/4] fix: use where filter in upload test, regenerate snapshots - Replace condition (not available) with where: { key: { equalTo: ... } } connection filter for bucket lookup in upload integration test - Regenerate schema-snapshot and graphile-test introspection snapshots (global mutations removed, per-table upload fields added) --- .../schema-snapshot.test.ts.snap | 2390 +++++++++ .../__tests__/upload.integration.test.ts | 2 +- .../__snapshots__/graphile-test.test.ts.snap | 4480 +++++++++++++++++ 3 files changed, 6871 insertions(+), 1 deletion(-) create mode 100644 graphql/server-test/__tests__/__snapshots__/schema-snapshot.test.ts.snap create mode 100644 graphql/test/__tests__/__snapshots__/graphile-test.test.ts.snap diff --git a/graphql/server-test/__tests__/__snapshots__/schema-snapshot.test.ts.snap b/graphql/server-test/__tests__/__snapshots__/schema-snapshot.test.ts.snap new file mode 100644 index 000000000..ea8384a7d --- /dev/null +++ b/graphql/server-test/__tests__/__snapshots__/schema-snapshot.test.ts.snap @@ -0,0 +1,2390 @@ +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`Schema Snapshot should generate consistent GraphQL SDL from the test schema 1`] = ` +""""The root query type which gives access points into the data universe.""" +type Query { + """Reads and enables pagination through a set of \`PostTag\`.""" + postTags( + """Only read the first \`n\` values of the set.""" + first: Int + + """Only read the last \`n\` values of the set.""" + last: Int + + """ + Skip the first \`n\` values from our \`after\` cursor, an alternative to cursor + based pagination. May not be used with \`last\`. + """ + offset: Int + + """Read all values in the set before (above) this cursor.""" + before: Cursor + + """Read all values in the set after (below) this cursor.""" + after: Cursor + + """ + A filter to be used in determining which values should be returned by the collection. + """ + where: PostTagFilter + + """The method to use when ordering \`PostTag\`.""" + orderBy: [PostTagOrderBy!] = [PRIMARY_KEY_ASC] + ): PostTagConnection + + """Reads and enables pagination through a set of \`Tag\`.""" + tags( + """Only read the first \`n\` values of the set.""" + first: Int + + """Only read the last \`n\` values of the set.""" + last: Int + + """ + Skip the first \`n\` values from our \`after\` cursor, an alternative to cursor + based pagination. May not be used with \`last\`. + """ + offset: Int + + """Read all values in the set before (above) this cursor.""" + before: Cursor + + """Read all values in the set after (below) this cursor.""" + after: Cursor + + """ + A filter to be used in determining which values should be returned by the collection. + """ + where: TagFilter + + """The method to use when ordering \`Tag\`.""" + orderBy: [TagOrderBy!] = [PRIMARY_KEY_ASC] + ): TagConnection + + """Reads and enables pagination through a set of \`User\`.""" + users( + """Only read the first \`n\` values of the set.""" + first: Int + + """Only read the last \`n\` values of the set.""" + last: Int + + """ + Skip the first \`n\` values from our \`after\` cursor, an alternative to cursor + based pagination. May not be used with \`last\`. + """ + offset: Int + + """Read all values in the set before (above) this cursor.""" + before: Cursor + + """Read all values in the set after (below) this cursor.""" + after: Cursor + + """ + A filter to be used in determining which values should be returned by the collection. + """ + where: UserFilter + + """The method to use when ordering \`User\`.""" + orderBy: [UserOrderBy!] = [PRIMARY_KEY_ASC] + ): UserConnection + + """Reads and enables pagination through a set of \`Comment\`.""" + comments( + """Only read the first \`n\` values of the set.""" + first: Int + + """Only read the last \`n\` values of the set.""" + last: Int + + """ + Skip the first \`n\` values from our \`after\` cursor, an alternative to cursor + based pagination. May not be used with \`last\`. + """ + offset: Int + + """Read all values in the set before (above) this cursor.""" + before: Cursor + + """Read all values in the set after (below) this cursor.""" + after: Cursor + + """ + A filter to be used in determining which values should be returned by the collection. + """ + where: CommentFilter + + """The method to use when ordering \`Comment\`.""" + orderBy: [CommentOrderBy!] = [PRIMARY_KEY_ASC] + ): CommentConnection + + """Reads and enables pagination through a set of \`Post\`.""" + posts( + """Only read the first \`n\` values of the set.""" + first: Int + + """Only read the last \`n\` values of the set.""" + last: Int + + """ + Skip the first \`n\` values from our \`after\` cursor, an alternative to cursor + based pagination. May not be used with \`last\`. + """ + offset: Int + + """Read all values in the set before (above) this cursor.""" + before: Cursor + + """Read all values in the set after (below) this cursor.""" + after: Cursor + + """ + A filter to be used in determining which values should be returned by the collection. + """ + where: PostFilter + + """The method to use when ordering \`Post\`.""" + orderBy: [PostOrderBy!] = [PRIMARY_KEY_ASC] + ): PostConnection + + """ + Metadata about the database schema, including tables, fields, indexes, and constraints. Useful for code generation tools. + """ + _meta: MetaSchema +} + +"""A connection to a list of \`PostTag\` values.""" +type PostTagConnection { + """A list of \`PostTag\` objects.""" + nodes: [PostTag]! + + """ + A list of edges which contains the \`PostTag\` and cursor to aid in pagination. + """ + edges: [PostTagEdge]! + + """Information to aid in pagination.""" + pageInfo: PageInfo! + + """The count of *all* \`PostTag\` you could get from the connection.""" + totalCount: Int! +} + +type PostTag { + id: UUID! + postId: UUID! + tagId: UUID! + createdAt: Datetime + + """Reads a single \`Post\` that is related to this \`PostTag\`.""" + post: Post + + """Reads a single \`Tag\` that is related to this \`PostTag\`.""" + tag: Tag +} + +""" +A universally unique identifier as defined by [RFC 4122](https://tools.ietf.org/html/rfc4122). +""" +scalar UUID + +""" +A point in time as described by the [ISO +8601](https://en.wikipedia.org/wiki/ISO_8601) and, if it has a timezone, [RFC +3339](https://datatracker.ietf.org/doc/html/rfc3339) standards. Input values +that do not conform to both ISO 8601 and RFC 3339 may be coerced, which may lead +to unexpected results. +""" +scalar Datetime + +type Post { + id: UUID! + authorId: UUID! + title: String! + slug: String! + content: String + excerpt: String + isPublished: Boolean + publishedAt: Datetime + viewCount: Int + createdAt: Datetime + updatedAt: Datetime + + """Reads and enables pagination through a set of \`Tag\`.""" + tags( + """Only read the first \`n\` values of the set.""" + first: Int + + """Only read the last \`n\` values of the set.""" + last: Int + + """ + Skip the first \`n\` values from our \`after\` cursor, an alternative to cursor + based pagination. May not be used with \`last\`. + """ + offset: Int + + """Read all values in the set before (above) this cursor.""" + before: Cursor + + """Read all values in the set after (below) this cursor.""" + after: Cursor + + """ + A filter to be used in determining which values should be returned by the collection. + """ + where: TagFilter + + """The method to use when ordering \`Tag\`.""" + orderBy: [TagOrderBy!] = [PRIMARY_KEY_ASC] + ): PostTagsManyToManyConnection! + + """Reads a single \`User\` that is related to this \`Post\`.""" + author: User + + """Reads and enables pagination through a set of \`PostTag\`.""" + postTags( + """Only read the first \`n\` values of the set.""" + first: Int + + """Only read the last \`n\` values of the set.""" + last: Int + + """ + Skip the first \`n\` values from our \`after\` cursor, an alternative to cursor + based pagination. May not be used with \`last\`. + """ + offset: Int + + """Read all values in the set before (above) this cursor.""" + before: Cursor + + """Read all values in the set after (below) this cursor.""" + after: Cursor + + """ + A filter to be used in determining which values should be returned by the collection. + """ + where: PostTagFilter + + """The method to use when ordering \`PostTag\`.""" + orderBy: [PostTagOrderBy!] = [PRIMARY_KEY_ASC] + ): PostTagConnection! + + """Reads and enables pagination through a set of \`Comment\`.""" + comments( + """Only read the first \`n\` values of the set.""" + first: Int + + """Only read the last \`n\` values of the set.""" + last: Int + + """ + Skip the first \`n\` values from our \`after\` cursor, an alternative to cursor + based pagination. May not be used with \`last\`. + """ + offset: Int + + """Read all values in the set before (above) this cursor.""" + before: Cursor + + """Read all values in the set after (below) this cursor.""" + after: Cursor + + """ + A filter to be used in determining which values should be returned by the collection. + """ + where: CommentFilter + + """The method to use when ordering \`Comment\`.""" + orderBy: [CommentOrderBy!] = [PRIMARY_KEY_ASC] + ): CommentConnection! +} + +"""A connection to a list of \`Tag\` values, with data from \`PostTag\`.""" +type PostTagsManyToManyConnection { + """A list of \`Tag\` objects.""" + nodes: [Tag]! + + """ + A list of edges which contains the \`Tag\`, info from the \`PostTag\`, and the cursor to aid in pagination. + """ + edges: [PostTagsManyToManyEdge!]! + + """Information to aid in pagination.""" + pageInfo: PageInfo! + + """The count of *all* \`Tag\` you could get from the connection.""" + totalCount: Int! +} + +type Tag { + id: UUID! + name: String! + slug: String! + description: String + color: String + createdAt: Datetime + + """Reads and enables pagination through a set of \`Post\`.""" + posts( + """Only read the first \`n\` values of the set.""" + first: Int + + """Only read the last \`n\` values of the set.""" + last: Int + + """ + Skip the first \`n\` values from our \`after\` cursor, an alternative to cursor + based pagination. May not be used with \`last\`. + """ + offset: Int + + """Read all values in the set before (above) this cursor.""" + before: Cursor + + """Read all values in the set after (below) this cursor.""" + after: Cursor + + """ + A filter to be used in determining which values should be returned by the collection. + """ + where: PostFilter + + """The method to use when ordering \`Post\`.""" + orderBy: [PostOrderBy!] = [PRIMARY_KEY_ASC] + ): TagPostsManyToManyConnection! + + """Reads and enables pagination through a set of \`PostTag\`.""" + postTags( + """Only read the first \`n\` values of the set.""" + first: Int + + """Only read the last \`n\` values of the set.""" + last: Int + + """ + Skip the first \`n\` values from our \`after\` cursor, an alternative to cursor + based pagination. May not be used with \`last\`. + """ + offset: Int + + """Read all values in the set before (above) this cursor.""" + before: Cursor + + """Read all values in the set after (below) this cursor.""" + after: Cursor + + """ + A filter to be used in determining which values should be returned by the collection. + """ + where: PostTagFilter + + """The method to use when ordering \`PostTag\`.""" + orderBy: [PostTagOrderBy!] = [PRIMARY_KEY_ASC] + ): PostTagConnection! +} + +"""A connection to a list of \`Post\` values, with data from \`PostTag\`.""" +type TagPostsManyToManyConnection { + """A list of \`Post\` objects.""" + nodes: [Post]! + + """ + A list of edges which contains the \`Post\`, info from the \`PostTag\`, and the cursor to aid in pagination. + """ + edges: [TagPostsManyToManyEdge!]! + + """Information to aid in pagination.""" + pageInfo: PageInfo! + + """The count of *all* \`Post\` you could get from the connection.""" + totalCount: Int! +} + +"""A \`Post\` edge in the connection, with data from \`PostTag\`.""" +type TagPostsManyToManyEdge { + """A cursor for use in pagination.""" + cursor: Cursor + + """The \`Post\` at the end of the edge.""" + node: Post + id: UUID! + createdAt: Datetime +} + +"""A location in a connection that can be used for resuming pagination.""" +scalar Cursor + +"""Information about pagination in a connection.""" +type PageInfo { + """When paginating forwards, are there more items?""" + hasNextPage: Boolean! + + """When paginating backwards, are there more items?""" + hasPreviousPage: Boolean! + + """When paginating backwards, the cursor to continue.""" + startCursor: Cursor + + """When paginating forwards, the cursor to continue.""" + endCursor: Cursor +} + +""" +A filter to be used against \`Post\` object types. All fields are combined with a logical ‘and.’ +""" +input PostFilter { + """Filter by the object’s \`id\` field.""" + id: UUIDFilter + + """Filter by the object’s \`authorId\` field.""" + authorId: UUIDFilter + + """Filter by the object’s \`title\` field.""" + title: StringFilter + + """Filter by the object’s \`slug\` field.""" + slug: StringFilter + + """Filter by the object’s \`content\` field.""" + content: StringFilter + + """Filter by the object’s \`excerpt\` field.""" + excerpt: StringFilter + + """Filter by the object’s \`isPublished\` field.""" + isPublished: BooleanFilter + + """Filter by the object’s \`publishedAt\` field.""" + publishedAt: DatetimeFilter + + """Filter by the object’s \`viewCount\` field.""" + viewCount: IntFilter + + """Filter by the object’s \`createdAt\` field.""" + createdAt: DatetimeFilter + + """Filter by the object’s \`updatedAt\` field.""" + updatedAt: DatetimeFilter + + """Checks for all expressions in this list.""" + and: [PostFilter!] + + """Checks for any expressions in this list.""" + or: [PostFilter!] + + """Negates the expression.""" + not: PostFilter + + """Filter by the object’s \`author\` relation.""" + author: UserFilter + + """Filter by the object’s \`postTags\` relation.""" + postTags: PostToManyPostTagFilter + + """\`postTags\` exist.""" + postTagsExist: Boolean + + """Filter by the object’s \`comments\` relation.""" + comments: PostToManyCommentFilter + + """\`comments\` exist.""" + commentsExist: Boolean +} + +""" +A filter to be used against UUID fields. All fields are combined with a logical ‘and.’ +""" +input UUIDFilter { + """ + Is null (if \`true\` is specified) or is not null (if \`false\` is specified). + """ + isNull: Boolean + + """Equal to the specified value.""" + equalTo: UUID + + """Not equal to the specified value.""" + notEqualTo: UUID + + """ + Not equal to the specified value, treating null like an ordinary value. + """ + distinctFrom: UUID + + """Equal to the specified value, treating null like an ordinary value.""" + notDistinctFrom: UUID + + """Included in the specified list.""" + in: [UUID!] + + """Not included in the specified list.""" + notIn: [UUID!] + + """Less than the specified value.""" + lessThan: UUID + + """Less than or equal to the specified value.""" + lessThanOrEqualTo: UUID + + """Greater than the specified value.""" + greaterThan: UUID + + """Greater than or equal to the specified value.""" + greaterThanOrEqualTo: UUID +} + +""" +A filter to be used against String fields. All fields are combined with a logical ‘and.’ +""" +input StringFilter { + """ + Is null (if \`true\` is specified) or is not null (if \`false\` is specified). + """ + isNull: Boolean + + """Equal to the specified value.""" + equalTo: String + + """Not equal to the specified value.""" + notEqualTo: String + + """ + Not equal to the specified value, treating null like an ordinary value. + """ + distinctFrom: String + + """Equal to the specified value, treating null like an ordinary value.""" + notDistinctFrom: String + + """Included in the specified list.""" + in: [String!] + + """Not included in the specified list.""" + notIn: [String!] + + """Less than the specified value.""" + lessThan: String + + """Less than or equal to the specified value.""" + lessThanOrEqualTo: String + + """Greater than the specified value.""" + greaterThan: String + + """Greater than or equal to the specified value.""" + greaterThanOrEqualTo: String + + """Contains the specified string (case-sensitive).""" + includes: String + + """Does not contain the specified string (case-sensitive).""" + notIncludes: String + + """Contains the specified string (case-insensitive).""" + includesInsensitive: String + + """Does not contain the specified string (case-insensitive).""" + notIncludesInsensitive: String + + """Starts with the specified string (case-sensitive).""" + startsWith: String + + """Does not start with the specified string (case-sensitive).""" + notStartsWith: String + + """Starts with the specified string (case-insensitive).""" + startsWithInsensitive: String + + """Does not start with the specified string (case-insensitive).""" + notStartsWithInsensitive: String + + """Ends with the specified string (case-sensitive).""" + endsWith: String + + """Does not end with the specified string (case-sensitive).""" + notEndsWith: String + + """Ends with the specified string (case-insensitive).""" + endsWithInsensitive: String + + """Does not end with the specified string (case-insensitive).""" + notEndsWithInsensitive: String + + """ + Matches the specified pattern (case-sensitive). An underscore (_) matches any single character; a percent sign (%) matches any sequence of zero or more characters. + """ + like: String + + """ + Does not match the specified pattern (case-sensitive). An underscore (_) matches any single character; a percent sign (%) matches any sequence of zero or more characters. + """ + notLike: String + + """ + Matches the specified pattern (case-insensitive). An underscore (_) matches any single character; a percent sign (%) matches any sequence of zero or more characters. + """ + likeInsensitive: String + + """ + Does not match the specified pattern (case-insensitive). An underscore (_) matches any single character; a percent sign (%) matches any sequence of zero or more characters. + """ + notLikeInsensitive: String + + """Equal to the specified value (case-insensitive).""" + equalToInsensitive: String + + """Not equal to the specified value (case-insensitive).""" + notEqualToInsensitive: String + + """ + Not equal to the specified value, treating null like an ordinary value (case-insensitive). + """ + distinctFromInsensitive: String + + """ + Equal to the specified value, treating null like an ordinary value (case-insensitive). + """ + notDistinctFromInsensitive: String + + """Included in the specified list (case-insensitive).""" + inInsensitive: [String!] + + """Not included in the specified list (case-insensitive).""" + notInInsensitive: [String!] + + """Less than the specified value (case-insensitive).""" + lessThanInsensitive: String + + """Less than or equal to the specified value (case-insensitive).""" + lessThanOrEqualToInsensitive: String + + """Greater than the specified value (case-insensitive).""" + greaterThanInsensitive: String + + """Greater than or equal to the specified value (case-insensitive).""" + greaterThanOrEqualToInsensitive: String +} + +""" +A filter to be used against Boolean fields. All fields are combined with a logical ‘and.’ +""" +input BooleanFilter { + """ + Is null (if \`true\` is specified) or is not null (if \`false\` is specified). + """ + isNull: Boolean + + """Equal to the specified value.""" + equalTo: Boolean + + """Not equal to the specified value.""" + notEqualTo: Boolean + + """ + Not equal to the specified value, treating null like an ordinary value. + """ + distinctFrom: Boolean + + """Equal to the specified value, treating null like an ordinary value.""" + notDistinctFrom: Boolean + + """Included in the specified list.""" + in: [Boolean!] + + """Not included in the specified list.""" + notIn: [Boolean!] + + """Less than the specified value.""" + lessThan: Boolean + + """Less than or equal to the specified value.""" + lessThanOrEqualTo: Boolean + + """Greater than the specified value.""" + greaterThan: Boolean + + """Greater than or equal to the specified value.""" + greaterThanOrEqualTo: Boolean +} + +""" +A filter to be used against Datetime fields. All fields are combined with a logical ‘and.’ +""" +input DatetimeFilter { + """ + Is null (if \`true\` is specified) or is not null (if \`false\` is specified). + """ + isNull: Boolean + + """Equal to the specified value.""" + equalTo: Datetime + + """Not equal to the specified value.""" + notEqualTo: Datetime + + """ + Not equal to the specified value, treating null like an ordinary value. + """ + distinctFrom: Datetime + + """Equal to the specified value, treating null like an ordinary value.""" + notDistinctFrom: Datetime + + """Included in the specified list.""" + in: [Datetime!] + + """Not included in the specified list.""" + notIn: [Datetime!] + + """Less than the specified value.""" + lessThan: Datetime + + """Less than or equal to the specified value.""" + lessThanOrEqualTo: Datetime + + """Greater than the specified value.""" + greaterThan: Datetime + + """Greater than or equal to the specified value.""" + greaterThanOrEqualTo: Datetime +} + +""" +A filter to be used against Int fields. All fields are combined with a logical ‘and.’ +""" +input IntFilter { + """ + Is null (if \`true\` is specified) or is not null (if \`false\` is specified). + """ + isNull: Boolean + + """Equal to the specified value.""" + equalTo: Int + + """Not equal to the specified value.""" + notEqualTo: Int + + """ + Not equal to the specified value, treating null like an ordinary value. + """ + distinctFrom: Int + + """Equal to the specified value, treating null like an ordinary value.""" + notDistinctFrom: Int + + """Included in the specified list.""" + in: [Int!] + + """Not included in the specified list.""" + notIn: [Int!] + + """Less than the specified value.""" + lessThan: Int + + """Less than or equal to the specified value.""" + lessThanOrEqualTo: Int + + """Greater than the specified value.""" + greaterThan: Int + + """Greater than or equal to the specified value.""" + greaterThanOrEqualTo: Int +} + +""" +A filter to be used against \`User\` object types. All fields are combined with a logical ‘and.’ +""" +input UserFilter { + """Filter by the object’s \`id\` field.""" + id: UUIDFilter + + """Filter by the object’s \`email\` field.""" + email: StringFilter + + """Filter by the object’s \`username\` field.""" + username: StringFilter + + """Filter by the object’s \`displayName\` field.""" + displayName: StringFilter + + """Filter by the object’s \`bio\` field.""" + bio: StringFilter + + """Filter by the object’s \`isActive\` field.""" + isActive: BooleanFilter + + """Filter by the object’s \`role\` field.""" + role: StringFilter + + """Filter by the object’s \`createdAt\` field.""" + createdAt: DatetimeFilter + + """Filter by the object’s \`updatedAt\` field.""" + updatedAt: DatetimeFilter + + """Checks for all expressions in this list.""" + and: [UserFilter!] + + """Checks for any expressions in this list.""" + or: [UserFilter!] + + """Negates the expression.""" + not: UserFilter + + """Filter by the object’s \`authoredPosts\` relation.""" + authoredPosts: UserToManyPostFilter + + """\`authoredPosts\` exist.""" + authoredPostsExist: Boolean + + """Filter by the object’s \`authoredComments\` relation.""" + authoredComments: UserToManyCommentFilter + + """\`authoredComments\` exist.""" + authoredCommentsExist: Boolean +} + +""" +A filter to be used against many \`Post\` object types. All fields are combined with a logical ‘and.’ +""" +input UserToManyPostFilter { + """Filters to entities where at least one related entity matches.""" + some: PostFilter + + """Filters to entities where every related entity matches.""" + every: PostFilter + + """Filters to entities where no related entity matches.""" + none: PostFilter +} + +""" +A filter to be used against many \`Comment\` object types. All fields are combined with a logical ‘and.’ +""" +input UserToManyCommentFilter { + """Filters to entities where at least one related entity matches.""" + some: CommentFilter + + """Filters to entities where every related entity matches.""" + every: CommentFilter + + """Filters to entities where no related entity matches.""" + none: CommentFilter +} + +""" +A filter to be used against \`Comment\` object types. All fields are combined with a logical ‘and.’ +""" +input CommentFilter { + """Filter by the object’s \`id\` field.""" + id: UUIDFilter + + """Filter by the object’s \`postId\` field.""" + postId: UUIDFilter + + """Filter by the object’s \`authorId\` field.""" + authorId: UUIDFilter + + """Filter by the object’s \`parentId\` field.""" + parentId: UUIDFilter + + """Filter by the object’s \`content\` field.""" + content: StringFilter + + """Filter by the object’s \`isApproved\` field.""" + isApproved: BooleanFilter + + """Filter by the object’s \`likesCount\` field.""" + likesCount: IntFilter + + """Filter by the object’s \`createdAt\` field.""" + createdAt: DatetimeFilter + + """Filter by the object’s \`updatedAt\` field.""" + updatedAt: DatetimeFilter + + """Checks for all expressions in this list.""" + and: [CommentFilter!] + + """Checks for any expressions in this list.""" + or: [CommentFilter!] + + """Negates the expression.""" + not: CommentFilter + + """Filter by the object’s \`author\` relation.""" + author: UserFilter + + """Filter by the object’s \`parent\` relation.""" + parent: CommentFilter + + """A related \`parent\` exists.""" + parentExists: Boolean + + """Filter by the object’s \`post\` relation.""" + post: PostFilter + + """Filter by the object’s \`childComments\` relation.""" + childComments: CommentToManyCommentFilter + + """\`childComments\` exist.""" + childCommentsExist: Boolean +} + +""" +A filter to be used against many \`Comment\` object types. All fields are combined with a logical ‘and.’ +""" +input CommentToManyCommentFilter { + """Filters to entities where at least one related entity matches.""" + some: CommentFilter + + """Filters to entities where every related entity matches.""" + every: CommentFilter + + """Filters to entities where no related entity matches.""" + none: CommentFilter +} + +""" +A filter to be used against many \`PostTag\` object types. All fields are combined with a logical ‘and.’ +""" +input PostToManyPostTagFilter { + """Filters to entities where at least one related entity matches.""" + some: PostTagFilter + + """Filters to entities where every related entity matches.""" + every: PostTagFilter + + """Filters to entities where no related entity matches.""" + none: PostTagFilter +} + +""" +A filter to be used against \`PostTag\` object types. All fields are combined with a logical ‘and.’ +""" +input PostTagFilter { + """Filter by the object’s \`id\` field.""" + id: UUIDFilter + + """Filter by the object’s \`postId\` field.""" + postId: UUIDFilter + + """Filter by the object’s \`tagId\` field.""" + tagId: UUIDFilter + + """Filter by the object’s \`createdAt\` field.""" + createdAt: DatetimeFilter + + """Checks for all expressions in this list.""" + and: [PostTagFilter!] + + """Checks for any expressions in this list.""" + or: [PostTagFilter!] + + """Negates the expression.""" + not: PostTagFilter + + """Filter by the object’s \`post\` relation.""" + post: PostFilter + + """Filter by the object’s \`tag\` relation.""" + tag: TagFilter +} + +""" +A filter to be used against \`Tag\` object types. All fields are combined with a logical ‘and.’ +""" +input TagFilter { + """Filter by the object’s \`id\` field.""" + id: UUIDFilter + + """Filter by the object’s \`name\` field.""" + name: StringFilter + + """Filter by the object’s \`slug\` field.""" + slug: StringFilter + + """Filter by the object’s \`description\` field.""" + description: StringFilter + + """Filter by the object’s \`color\` field.""" + color: StringFilter + + """Filter by the object’s \`createdAt\` field.""" + createdAt: DatetimeFilter + + """Checks for all expressions in this list.""" + and: [TagFilter!] + + """Checks for any expressions in this list.""" + or: [TagFilter!] + + """Negates the expression.""" + not: TagFilter + + """Filter by the object’s \`postTags\` relation.""" + postTags: TagToManyPostTagFilter + + """\`postTags\` exist.""" + postTagsExist: Boolean +} + +""" +A filter to be used against many \`PostTag\` object types. All fields are combined with a logical ‘and.’ +""" +input TagToManyPostTagFilter { + """Filters to entities where at least one related entity matches.""" + some: PostTagFilter + + """Filters to entities where every related entity matches.""" + every: PostTagFilter + + """Filters to entities where no related entity matches.""" + none: PostTagFilter +} + +""" +A filter to be used against many \`Comment\` object types. All fields are combined with a logical ‘and.’ +""" +input PostToManyCommentFilter { + """Filters to entities where at least one related entity matches.""" + some: CommentFilter + + """Filters to entities where every related entity matches.""" + every: CommentFilter + + """Filters to entities where no related entity matches.""" + none: CommentFilter +} + +"""Methods to use when ordering \`Post\`.""" +enum PostOrderBy { + NATURAL + PRIMARY_KEY_ASC + PRIMARY_KEY_DESC + ID_ASC + ID_DESC + AUTHOR_ID_ASC + AUTHOR_ID_DESC + TITLE_ASC + TITLE_DESC + SLUG_ASC + SLUG_DESC + CONTENT_ASC + CONTENT_DESC + EXCERPT_ASC + EXCERPT_DESC + IS_PUBLISHED_ASC + IS_PUBLISHED_DESC + PUBLISHED_AT_ASC + PUBLISHED_AT_DESC + VIEW_COUNT_ASC + VIEW_COUNT_DESC + CREATED_AT_ASC + CREATED_AT_DESC + UPDATED_AT_ASC + UPDATED_AT_DESC +} + +"""Methods to use when ordering \`PostTag\`.""" +enum PostTagOrderBy { + NATURAL + PRIMARY_KEY_ASC + PRIMARY_KEY_DESC + ID_ASC + ID_DESC + POST_ID_ASC + POST_ID_DESC + TAG_ID_ASC + TAG_ID_DESC + CREATED_AT_ASC + CREATED_AT_DESC +} + +"""A \`Tag\` edge in the connection, with data from \`PostTag\`.""" +type PostTagsManyToManyEdge { + """A cursor for use in pagination.""" + cursor: Cursor + + """The \`Tag\` at the end of the edge.""" + node: Tag + id: UUID! + createdAt: Datetime +} + +"""Methods to use when ordering \`Tag\`.""" +enum TagOrderBy { + NATURAL + PRIMARY_KEY_ASC + PRIMARY_KEY_DESC + ID_ASC + ID_DESC + NAME_ASC + NAME_DESC + SLUG_ASC + SLUG_DESC + DESCRIPTION_ASC + DESCRIPTION_DESC + COLOR_ASC + COLOR_DESC + CREATED_AT_ASC + CREATED_AT_DESC +} + +type User { + id: UUID! + email: String! + username: String! + displayName: String + bio: String + isActive: Boolean + role: String + createdAt: Datetime + updatedAt: Datetime + + """Reads and enables pagination through a set of \`Post\`.""" + authoredPosts( + """Only read the first \`n\` values of the set.""" + first: Int + + """Only read the last \`n\` values of the set.""" + last: Int + + """ + Skip the first \`n\` values from our \`after\` cursor, an alternative to cursor + based pagination. May not be used with \`last\`. + """ + offset: Int + + """Read all values in the set before (above) this cursor.""" + before: Cursor + + """Read all values in the set after (below) this cursor.""" + after: Cursor + + """ + A filter to be used in determining which values should be returned by the collection. + """ + where: PostFilter + + """The method to use when ordering \`Post\`.""" + orderBy: [PostOrderBy!] = [PRIMARY_KEY_ASC] + ): PostConnection! + + """Reads and enables pagination through a set of \`Comment\`.""" + authoredComments( + """Only read the first \`n\` values of the set.""" + first: Int + + """Only read the last \`n\` values of the set.""" + last: Int + + """ + Skip the first \`n\` values from our \`after\` cursor, an alternative to cursor + based pagination. May not be used with \`last\`. + """ + offset: Int + + """Read all values in the set before (above) this cursor.""" + before: Cursor + + """Read all values in the set after (below) this cursor.""" + after: Cursor + + """ + A filter to be used in determining which values should be returned by the collection. + """ + where: CommentFilter + + """The method to use when ordering \`Comment\`.""" + orderBy: [CommentOrderBy!] = [PRIMARY_KEY_ASC] + ): CommentConnection! +} + +"""A connection to a list of \`Post\` values.""" +type PostConnection { + """A list of \`Post\` objects.""" + nodes: [Post]! + + """ + A list of edges which contains the \`Post\` and cursor to aid in pagination. + """ + edges: [PostEdge]! + + """Information to aid in pagination.""" + pageInfo: PageInfo! + + """The count of *all* \`Post\` you could get from the connection.""" + totalCount: Int! +} + +"""A \`Post\` edge in the connection.""" +type PostEdge { + """A cursor for use in pagination.""" + cursor: Cursor + + """The \`Post\` at the end of the edge.""" + node: Post +} + +"""A connection to a list of \`Comment\` values.""" +type CommentConnection { + """A list of \`Comment\` objects.""" + nodes: [Comment]! + + """ + A list of edges which contains the \`Comment\` and cursor to aid in pagination. + """ + edges: [CommentEdge]! + + """Information to aid in pagination.""" + pageInfo: PageInfo! + + """The count of *all* \`Comment\` you could get from the connection.""" + totalCount: Int! +} + +type Comment { + id: UUID! + postId: UUID! + authorId: UUID! + parentId: UUID + content: String! + isApproved: Boolean + likesCount: Int + createdAt: Datetime + updatedAt: Datetime + + """Reads a single \`User\` that is related to this \`Comment\`.""" + author: User + + """Reads a single \`Comment\` that is related to this \`Comment\`.""" + parent: Comment + + """Reads a single \`Post\` that is related to this \`Comment\`.""" + post: Post + + """Reads and enables pagination through a set of \`Comment\`.""" + childComments( + """Only read the first \`n\` values of the set.""" + first: Int + + """Only read the last \`n\` values of the set.""" + last: Int + + """ + Skip the first \`n\` values from our \`after\` cursor, an alternative to cursor + based pagination. May not be used with \`last\`. + """ + offset: Int + + """Read all values in the set before (above) this cursor.""" + before: Cursor + + """Read all values in the set after (below) this cursor.""" + after: Cursor + + """ + A filter to be used in determining which values should be returned by the collection. + """ + where: CommentFilter + + """The method to use when ordering \`Comment\`.""" + orderBy: [CommentOrderBy!] = [PRIMARY_KEY_ASC] + ): CommentConnection! +} + +"""Methods to use when ordering \`Comment\`.""" +enum CommentOrderBy { + NATURAL + PRIMARY_KEY_ASC + PRIMARY_KEY_DESC + ID_ASC + ID_DESC + POST_ID_ASC + POST_ID_DESC + AUTHOR_ID_ASC + AUTHOR_ID_DESC + PARENT_ID_ASC + PARENT_ID_DESC + CONTENT_ASC + CONTENT_DESC + IS_APPROVED_ASC + IS_APPROVED_DESC + LIKES_COUNT_ASC + LIKES_COUNT_DESC + CREATED_AT_ASC + CREATED_AT_DESC + UPDATED_AT_ASC + UPDATED_AT_DESC +} + +"""A \`Comment\` edge in the connection.""" +type CommentEdge { + """A cursor for use in pagination.""" + cursor: Cursor + + """The \`Comment\` at the end of the edge.""" + node: Comment +} + +"""A \`PostTag\` edge in the connection.""" +type PostTagEdge { + """A cursor for use in pagination.""" + cursor: Cursor + + """The \`PostTag\` at the end of the edge.""" + node: PostTag +} + +"""A connection to a list of \`Tag\` values.""" +type TagConnection { + """A list of \`Tag\` objects.""" + nodes: [Tag]! + + """ + A list of edges which contains the \`Tag\` and cursor to aid in pagination. + """ + edges: [TagEdge]! + + """Information to aid in pagination.""" + pageInfo: PageInfo! + + """The count of *all* \`Tag\` you could get from the connection.""" + totalCount: Int! +} + +"""A \`Tag\` edge in the connection.""" +type TagEdge { + """A cursor for use in pagination.""" + cursor: Cursor + + """The \`Tag\` at the end of the edge.""" + node: Tag +} + +"""A connection to a list of \`User\` values.""" +type UserConnection { + """A list of \`User\` objects.""" + nodes: [User]! + + """ + A list of edges which contains the \`User\` and cursor to aid in pagination. + """ + edges: [UserEdge]! + + """Information to aid in pagination.""" + pageInfo: PageInfo! + + """The count of *all* \`User\` you could get from the connection.""" + totalCount: Int! +} + +"""A \`User\` edge in the connection.""" +type UserEdge { + """A cursor for use in pagination.""" + cursor: Cursor + + """The \`User\` at the end of the edge.""" + node: User +} + +"""Methods to use when ordering \`User\`.""" +enum UserOrderBy { + NATURAL + PRIMARY_KEY_ASC + PRIMARY_KEY_DESC + ID_ASC + ID_DESC + EMAIL_ASC + EMAIL_DESC + USERNAME_ASC + USERNAME_DESC + DISPLAY_NAME_ASC + DISPLAY_NAME_DESC + BIO_ASC + BIO_DESC + IS_ACTIVE_ASC + IS_ACTIVE_DESC + ROLE_ASC + ROLE_DESC + CREATED_AT_ASC + CREATED_AT_DESC + UPDATED_AT_ASC + UPDATED_AT_DESC +} + +"""Root meta schema type""" +type MetaSchema { + tables: [MetaTable!]! +} + +"""Information about a database table""" +type MetaTable { + name: String! + schemaName: String! + fields: [MetaField!]! + indexes: [MetaIndex!]! + constraints: MetaConstraints! + foreignKeyConstraints: [MetaForeignKeyConstraint!]! + primaryKeyConstraints: [MetaPrimaryKeyConstraint!]! + uniqueConstraints: [MetaUniqueConstraint!]! + relations: MetaRelations! + inflection: MetaInflection! + query: MetaQuery! +} + +"""Information about a table field/column""" +type MetaField { + name: String! + type: MetaType! + isNotNull: Boolean! + hasDefault: Boolean! + isPrimaryKey: Boolean! + isForeignKey: Boolean! + description: String +} + +"""Information about a PostgreSQL type""" +type MetaType { + pgType: String! + gqlType: String! + isArray: Boolean! + isNotNull: Boolean + hasDefault: Boolean + subtype: String +} + +"""Information about a database index""" +type MetaIndex { + name: String! + isUnique: Boolean! + isPrimary: Boolean! + columns: [String!]! + fields: [MetaField!] +} + +"""Table constraints""" +type MetaConstraints { + primaryKey: MetaPrimaryKeyConstraint + unique: [MetaUniqueConstraint!]! + foreignKey: [MetaForeignKeyConstraint!]! +} + +"""Information about a primary key constraint""" +type MetaPrimaryKeyConstraint { + name: String! + fields: [MetaField!]! +} + +"""Information about a unique constraint""" +type MetaUniqueConstraint { + name: String! + fields: [MetaField!]! +} + +"""Information about a foreign key constraint""" +type MetaForeignKeyConstraint { + name: String! + fields: [MetaField!]! + referencedTable: String! + referencedFields: [String!]! + refFields: [MetaField!] + refTable: MetaRefTable +} + +"""Reference to a related table""" +type MetaRefTable { + name: String! +} + +"""Table relations""" +type MetaRelations { + belongsTo: [MetaBelongsToRelation!]! + has: [MetaHasRelation!]! + hasOne: [MetaHasRelation!]! + hasMany: [MetaHasRelation!]! + manyToMany: [MetaManyToManyRelation!]! +} + +"""A belongs-to (forward FK) relation""" +type MetaBelongsToRelation { + fieldName: String + isUnique: Boolean! + type: String + keys: [MetaField!]! + references: MetaRefTable! +} + +"""A has-one or has-many (reverse FK) relation""" +type MetaHasRelation { + fieldName: String + isUnique: Boolean! + type: String + keys: [MetaField!]! + referencedBy: MetaRefTable! +} + +"""A many-to-many relation via junction table""" +type MetaManyToManyRelation { + fieldName: String + type: String + junctionTable: MetaRefTable! + junctionLeftConstraint: MetaForeignKeyConstraint! + junctionLeftKeyAttributes: [MetaField!]! + junctionRightConstraint: MetaForeignKeyConstraint! + junctionRightKeyAttributes: [MetaField!]! + leftKeyAttributes: [MetaField!]! + rightKeyAttributes: [MetaField!]! + rightTable: MetaRefTable! +} + +"""Table inflection names""" +type MetaInflection { + tableType: String! + allRows: String! + connection: String! + edge: String! + filterType: String + orderByType: String! + conditionType: String! + patchType: String + createInputType: String! + createPayloadType: String! + updatePayloadType: String + deletePayloadType: String! +} + +"""Table query/mutation names""" +type MetaQuery { + all: String! + one: String + create: String + update: String + delete: String +} + +""" +The root mutation type which contains root level fields which mutate data. +""" +type Mutation { + """Creates a single \`PostTag\`.""" + createPostTag( + """ + The exclusive input argument for this mutation. An object type, make sure to see documentation for this object’s fields. + """ + input: CreatePostTagInput! + ): CreatePostTagPayload + + """Creates a single \`Tag\`.""" + createTag( + """ + The exclusive input argument for this mutation. An object type, make sure to see documentation for this object’s fields. + """ + input: CreateTagInput! + ): CreateTagPayload + + """Creates a single \`User\`.""" + createUser( + """ + The exclusive input argument for this mutation. An object type, make sure to see documentation for this object’s fields. + """ + input: CreateUserInput! + ): CreateUserPayload + + """Creates a single \`Comment\`.""" + createComment( + """ + The exclusive input argument for this mutation. An object type, make sure to see documentation for this object’s fields. + """ + input: CreateCommentInput! + ): CreateCommentPayload + + """Creates a single \`Post\`.""" + createPost( + """ + The exclusive input argument for this mutation. An object type, make sure to see documentation for this object’s fields. + """ + input: CreatePostInput! + ): CreatePostPayload + + """Updates a single \`PostTag\` using a unique key and a patch.""" + updatePostTag( + """ + The exclusive input argument for this mutation. An object type, make sure to see documentation for this object’s fields. + """ + input: UpdatePostTagInput! + ): UpdatePostTagPayload + + """Updates a single \`Tag\` using a unique key and a patch.""" + updateTag( + """ + The exclusive input argument for this mutation. An object type, make sure to see documentation for this object’s fields. + """ + input: UpdateTagInput! + ): UpdateTagPayload + + """Updates a single \`User\` using a unique key and a patch.""" + updateUser( + """ + The exclusive input argument for this mutation. An object type, make sure to see documentation for this object’s fields. + """ + input: UpdateUserInput! + ): UpdateUserPayload + + """Updates a single \`Comment\` using a unique key and a patch.""" + updateComment( + """ + The exclusive input argument for this mutation. An object type, make sure to see documentation for this object’s fields. + """ + input: UpdateCommentInput! + ): UpdateCommentPayload + + """Updates a single \`Post\` using a unique key and a patch.""" + updatePost( + """ + The exclusive input argument for this mutation. An object type, make sure to see documentation for this object’s fields. + """ + input: UpdatePostInput! + ): UpdatePostPayload + + """Deletes a single \`PostTag\` using a unique key.""" + deletePostTag( + """ + The exclusive input argument for this mutation. An object type, make sure to see documentation for this object’s fields. + """ + input: DeletePostTagInput! + ): DeletePostTagPayload + + """Deletes a single \`Tag\` using a unique key.""" + deleteTag( + """ + The exclusive input argument for this mutation. An object type, make sure to see documentation for this object’s fields. + """ + input: DeleteTagInput! + ): DeleteTagPayload + + """Deletes a single \`User\` using a unique key.""" + deleteUser( + """ + The exclusive input argument for this mutation. An object type, make sure to see documentation for this object’s fields. + """ + input: DeleteUserInput! + ): DeleteUserPayload + + """Deletes a single \`Comment\` using a unique key.""" + deleteComment( + """ + The exclusive input argument for this mutation. An object type, make sure to see documentation for this object’s fields. + """ + input: DeleteCommentInput! + ): DeleteCommentPayload + + """Deletes a single \`Post\` using a unique key.""" + deletePost( + """ + The exclusive input argument for this mutation. An object type, make sure to see documentation for this object’s fields. + """ + input: DeletePostInput! + ): DeletePostPayload + + """ + Provision an S3 bucket for a logical bucket in the database. + Reads the bucket config via RLS, then creates and configures + the S3 bucket with the appropriate privacy policies, CORS rules, + and lifecycle settings. + """ + provisionBucket( + """ + The exclusive input argument for this mutation. An object type, make sure to see documentation for this object’s fields. + """ + input: ProvisionBucketInput! + ): ProvisionBucketPayload +} + +"""The output of our create \`PostTag\` mutation.""" +type CreatePostTagPayload { + """ + The exact same \`clientMutationId\` that was provided in the mutation input, + unchanged and unused. May be used by a client to track mutations. + """ + clientMutationId: String + + """The \`PostTag\` that was created by this mutation.""" + postTag: PostTag + + """ + Our root query field type. Allows us to run any query from our mutation payload. + """ + query: Query + + """An edge for our \`PostTag\`. May be used by Relay 1.""" + postTagEdge( + """The method to use when ordering \`PostTag\`.""" + orderBy: [PostTagOrderBy!]! = [PRIMARY_KEY_ASC] + ): PostTagEdge +} + +"""All input for the create \`PostTag\` mutation.""" +input CreatePostTagInput { + """ + An arbitrary string value with no semantic meaning. Will be included in the + payload verbatim. May be used to track mutations by the client. + """ + clientMutationId: String + + """The \`PostTag\` to be created by this mutation.""" + postTag: PostTagInput! +} + +"""An input for mutations affecting \`PostTag\`""" +input PostTagInput { + id: UUID + postId: UUID! + tagId: UUID! + createdAt: Datetime +} + +"""The output of our create \`Tag\` mutation.""" +type CreateTagPayload { + """ + The exact same \`clientMutationId\` that was provided in the mutation input, + unchanged and unused. May be used by a client to track mutations. + """ + clientMutationId: String + + """The \`Tag\` that was created by this mutation.""" + tag: Tag + + """ + Our root query field type. Allows us to run any query from our mutation payload. + """ + query: Query + + """An edge for our \`Tag\`. May be used by Relay 1.""" + tagEdge( + """The method to use when ordering \`Tag\`.""" + orderBy: [TagOrderBy!]! = [PRIMARY_KEY_ASC] + ): TagEdge +} + +"""All input for the create \`Tag\` mutation.""" +input CreateTagInput { + """ + An arbitrary string value with no semantic meaning. Will be included in the + payload verbatim. May be used to track mutations by the client. + """ + clientMutationId: String + + """The \`Tag\` to be created by this mutation.""" + tag: TagInput! +} + +"""An input for mutations affecting \`Tag\`""" +input TagInput { + id: UUID + name: String! + slug: String! + description: String + color: String + createdAt: Datetime +} + +"""The output of our create \`User\` mutation.""" +type CreateUserPayload { + """ + The exact same \`clientMutationId\` that was provided in the mutation input, + unchanged and unused. May be used by a client to track mutations. + """ + clientMutationId: String + + """The \`User\` that was created by this mutation.""" + user: User + + """ + Our root query field type. Allows us to run any query from our mutation payload. + """ + query: Query + + """An edge for our \`User\`. May be used by Relay 1.""" + userEdge( + """The method to use when ordering \`User\`.""" + orderBy: [UserOrderBy!]! = [PRIMARY_KEY_ASC] + ): UserEdge +} + +"""All input for the create \`User\` mutation.""" +input CreateUserInput { + """ + An arbitrary string value with no semantic meaning. Will be included in the + payload verbatim. May be used to track mutations by the client. + """ + clientMutationId: String + + """The \`User\` to be created by this mutation.""" + user: UserInput! +} + +"""An input for mutations affecting \`User\`""" +input UserInput { + id: UUID + email: String! + username: String! + displayName: String + bio: String + isActive: Boolean + role: String + createdAt: Datetime + updatedAt: Datetime +} + +"""The output of our create \`Comment\` mutation.""" +type CreateCommentPayload { + """ + The exact same \`clientMutationId\` that was provided in the mutation input, + unchanged and unused. May be used by a client to track mutations. + """ + clientMutationId: String + + """The \`Comment\` that was created by this mutation.""" + comment: Comment + + """ + Our root query field type. Allows us to run any query from our mutation payload. + """ + query: Query + + """An edge for our \`Comment\`. May be used by Relay 1.""" + commentEdge( + """The method to use when ordering \`Comment\`.""" + orderBy: [CommentOrderBy!]! = [PRIMARY_KEY_ASC] + ): CommentEdge +} + +"""All input for the create \`Comment\` mutation.""" +input CreateCommentInput { + """ + An arbitrary string value with no semantic meaning. Will be included in the + payload verbatim. May be used to track mutations by the client. + """ + clientMutationId: String + + """The \`Comment\` to be created by this mutation.""" + comment: CommentInput! +} + +"""An input for mutations affecting \`Comment\`""" +input CommentInput { + id: UUID + postId: UUID! + authorId: UUID! + parentId: UUID + content: String! + isApproved: Boolean + likesCount: Int + createdAt: Datetime + updatedAt: Datetime +} + +"""The output of our create \`Post\` mutation.""" +type CreatePostPayload { + """ + The exact same \`clientMutationId\` that was provided in the mutation input, + unchanged and unused. May be used by a client to track mutations. + """ + clientMutationId: String + + """The \`Post\` that was created by this mutation.""" + post: Post + + """ + Our root query field type. Allows us to run any query from our mutation payload. + """ + query: Query + + """An edge for our \`Post\`. May be used by Relay 1.""" + postEdge( + """The method to use when ordering \`Post\`.""" + orderBy: [PostOrderBy!]! = [PRIMARY_KEY_ASC] + ): PostEdge +} + +"""All input for the create \`Post\` mutation.""" +input CreatePostInput { + """ + An arbitrary string value with no semantic meaning. Will be included in the + payload verbatim. May be used to track mutations by the client. + """ + clientMutationId: String + + """The \`Post\` to be created by this mutation.""" + post: PostInput! +} + +"""An input for mutations affecting \`Post\`""" +input PostInput { + id: UUID + authorId: UUID! + title: String! + slug: String! + content: String + excerpt: String + isPublished: Boolean + publishedAt: Datetime + viewCount: Int + createdAt: Datetime + updatedAt: Datetime +} + +"""The output of our update \`PostTag\` mutation.""" +type UpdatePostTagPayload { + """ + The exact same \`clientMutationId\` that was provided in the mutation input, + unchanged and unused. May be used by a client to track mutations. + """ + clientMutationId: String + + """The \`PostTag\` that was updated by this mutation.""" + postTag: PostTag + + """ + Our root query field type. Allows us to run any query from our mutation payload. + """ + query: Query + + """An edge for our \`PostTag\`. May be used by Relay 1.""" + postTagEdge( + """The method to use when ordering \`PostTag\`.""" + orderBy: [PostTagOrderBy!]! = [PRIMARY_KEY_ASC] + ): PostTagEdge +} + +"""All input for the \`updatePostTag\` mutation.""" +input UpdatePostTagInput { + """ + An arbitrary string value with no semantic meaning. Will be included in the + payload verbatim. May be used to track mutations by the client. + """ + clientMutationId: String + id: UUID! + + """ + An object where the defined keys will be set on the \`PostTag\` being updated. + """ + postTagPatch: PostTagPatch! +} + +""" +Represents an update to a \`PostTag\`. Fields that are set will be updated. +""" +input PostTagPatch { + id: UUID + postId: UUID + tagId: UUID + createdAt: Datetime +} + +"""The output of our update \`Tag\` mutation.""" +type UpdateTagPayload { + """ + The exact same \`clientMutationId\` that was provided in the mutation input, + unchanged and unused. May be used by a client to track mutations. + """ + clientMutationId: String + + """The \`Tag\` that was updated by this mutation.""" + tag: Tag + + """ + Our root query field type. Allows us to run any query from our mutation payload. + """ + query: Query + + """An edge for our \`Tag\`. May be used by Relay 1.""" + tagEdge( + """The method to use when ordering \`Tag\`.""" + orderBy: [TagOrderBy!]! = [PRIMARY_KEY_ASC] + ): TagEdge +} + +"""All input for the \`updateTag\` mutation.""" +input UpdateTagInput { + """ + An arbitrary string value with no semantic meaning. Will be included in the + payload verbatim. May be used to track mutations by the client. + """ + clientMutationId: String + id: UUID! + + """ + An object where the defined keys will be set on the \`Tag\` being updated. + """ + tagPatch: TagPatch! +} + +"""Represents an update to a \`Tag\`. Fields that are set will be updated.""" +input TagPatch { + id: UUID + name: String + slug: String + description: String + color: String + createdAt: Datetime +} + +"""The output of our update \`User\` mutation.""" +type UpdateUserPayload { + """ + The exact same \`clientMutationId\` that was provided in the mutation input, + unchanged and unused. May be used by a client to track mutations. + """ + clientMutationId: String + + """The \`User\` that was updated by this mutation.""" + user: User + + """ + Our root query field type. Allows us to run any query from our mutation payload. + """ + query: Query + + """An edge for our \`User\`. May be used by Relay 1.""" + userEdge( + """The method to use when ordering \`User\`.""" + orderBy: [UserOrderBy!]! = [PRIMARY_KEY_ASC] + ): UserEdge +} + +"""All input for the \`updateUser\` mutation.""" +input UpdateUserInput { + """ + An arbitrary string value with no semantic meaning. Will be included in the + payload verbatim. May be used to track mutations by the client. + """ + clientMutationId: String + id: UUID! + + """ + An object where the defined keys will be set on the \`User\` being updated. + """ + userPatch: UserPatch! +} + +"""Represents an update to a \`User\`. Fields that are set will be updated.""" +input UserPatch { + id: UUID + email: String + username: String + displayName: String + bio: String + isActive: Boolean + role: String + createdAt: Datetime + updatedAt: Datetime +} + +"""The output of our update \`Comment\` mutation.""" +type UpdateCommentPayload { + """ + The exact same \`clientMutationId\` that was provided in the mutation input, + unchanged and unused. May be used by a client to track mutations. + """ + clientMutationId: String + + """The \`Comment\` that was updated by this mutation.""" + comment: Comment + + """ + Our root query field type. Allows us to run any query from our mutation payload. + """ + query: Query + + """An edge for our \`Comment\`. May be used by Relay 1.""" + commentEdge( + """The method to use when ordering \`Comment\`.""" + orderBy: [CommentOrderBy!]! = [PRIMARY_KEY_ASC] + ): CommentEdge +} + +"""All input for the \`updateComment\` mutation.""" +input UpdateCommentInput { + """ + An arbitrary string value with no semantic meaning. Will be included in the + payload verbatim. May be used to track mutations by the client. + """ + clientMutationId: String + id: UUID! + + """ + An object where the defined keys will be set on the \`Comment\` being updated. + """ + commentPatch: CommentPatch! +} + +""" +Represents an update to a \`Comment\`. Fields that are set will be updated. +""" +input CommentPatch { + id: UUID + postId: UUID + authorId: UUID + parentId: UUID + content: String + isApproved: Boolean + likesCount: Int + createdAt: Datetime + updatedAt: Datetime +} + +"""The output of our update \`Post\` mutation.""" +type UpdatePostPayload { + """ + The exact same \`clientMutationId\` that was provided in the mutation input, + unchanged and unused. May be used by a client to track mutations. + """ + clientMutationId: String + + """The \`Post\` that was updated by this mutation.""" + post: Post + + """ + Our root query field type. Allows us to run any query from our mutation payload. + """ + query: Query + + """An edge for our \`Post\`. May be used by Relay 1.""" + postEdge( + """The method to use when ordering \`Post\`.""" + orderBy: [PostOrderBy!]! = [PRIMARY_KEY_ASC] + ): PostEdge +} + +"""All input for the \`updatePost\` mutation.""" +input UpdatePostInput { + """ + An arbitrary string value with no semantic meaning. Will be included in the + payload verbatim. May be used to track mutations by the client. + """ + clientMutationId: String + id: UUID! + + """ + An object where the defined keys will be set on the \`Post\` being updated. + """ + postPatch: PostPatch! +} + +"""Represents an update to a \`Post\`. Fields that are set will be updated.""" +input PostPatch { + id: UUID + authorId: UUID + title: String + slug: String + content: String + excerpt: String + isPublished: Boolean + publishedAt: Datetime + viewCount: Int + createdAt: Datetime + updatedAt: Datetime +} + +"""The output of our delete \`PostTag\` mutation.""" +type DeletePostTagPayload { + """ + The exact same \`clientMutationId\` that was provided in the mutation input, + unchanged and unused. May be used by a client to track mutations. + """ + clientMutationId: String + + """The \`PostTag\` that was deleted by this mutation.""" + postTag: PostTag + + """ + Our root query field type. Allows us to run any query from our mutation payload. + """ + query: Query + + """An edge for our \`PostTag\`. May be used by Relay 1.""" + postTagEdge( + """The method to use when ordering \`PostTag\`.""" + orderBy: [PostTagOrderBy!]! = [PRIMARY_KEY_ASC] + ): PostTagEdge +} + +"""All input for the \`deletePostTag\` mutation.""" +input DeletePostTagInput { + """ + An arbitrary string value with no semantic meaning. Will be included in the + payload verbatim. May be used to track mutations by the client. + """ + clientMutationId: String + id: UUID! +} + +"""The output of our delete \`Tag\` mutation.""" +type DeleteTagPayload { + """ + The exact same \`clientMutationId\` that was provided in the mutation input, + unchanged and unused. May be used by a client to track mutations. + """ + clientMutationId: String + + """The \`Tag\` that was deleted by this mutation.""" + tag: Tag + + """ + Our root query field type. Allows us to run any query from our mutation payload. + """ + query: Query + + """An edge for our \`Tag\`. May be used by Relay 1.""" + tagEdge( + """The method to use when ordering \`Tag\`.""" + orderBy: [TagOrderBy!]! = [PRIMARY_KEY_ASC] + ): TagEdge +} + +"""All input for the \`deleteTag\` mutation.""" +input DeleteTagInput { + """ + An arbitrary string value with no semantic meaning. Will be included in the + payload verbatim. May be used to track mutations by the client. + """ + clientMutationId: String + id: UUID! +} + +"""The output of our delete \`User\` mutation.""" +type DeleteUserPayload { + """ + The exact same \`clientMutationId\` that was provided in the mutation input, + unchanged and unused. May be used by a client to track mutations. + """ + clientMutationId: String + + """The \`User\` that was deleted by this mutation.""" + user: User + + """ + Our root query field type. Allows us to run any query from our mutation payload. + """ + query: Query + + """An edge for our \`User\`. May be used by Relay 1.""" + userEdge( + """The method to use when ordering \`User\`.""" + orderBy: [UserOrderBy!]! = [PRIMARY_KEY_ASC] + ): UserEdge +} + +"""All input for the \`deleteUser\` mutation.""" +input DeleteUserInput { + """ + An arbitrary string value with no semantic meaning. Will be included in the + payload verbatim. May be used to track mutations by the client. + """ + clientMutationId: String + id: UUID! +} + +"""The output of our delete \`Comment\` mutation.""" +type DeleteCommentPayload { + """ + The exact same \`clientMutationId\` that was provided in the mutation input, + unchanged and unused. May be used by a client to track mutations. + """ + clientMutationId: String + + """The \`Comment\` that was deleted by this mutation.""" + comment: Comment + + """ + Our root query field type. Allows us to run any query from our mutation payload. + """ + query: Query + + """An edge for our \`Comment\`. May be used by Relay 1.""" + commentEdge( + """The method to use when ordering \`Comment\`.""" + orderBy: [CommentOrderBy!]! = [PRIMARY_KEY_ASC] + ): CommentEdge +} + +"""All input for the \`deleteComment\` mutation.""" +input DeleteCommentInput { + """ + An arbitrary string value with no semantic meaning. Will be included in the + payload verbatim. May be used to track mutations by the client. + """ + clientMutationId: String + id: UUID! +} + +"""The output of our delete \`Post\` mutation.""" +type DeletePostPayload { + """ + The exact same \`clientMutationId\` that was provided in the mutation input, + unchanged and unused. May be used by a client to track mutations. + """ + clientMutationId: String + + """The \`Post\` that was deleted by this mutation.""" + post: Post + + """ + Our root query field type. Allows us to run any query from our mutation payload. + """ + query: Query + + """An edge for our \`Post\`. May be used by Relay 1.""" + postEdge( + """The method to use when ordering \`Post\`.""" + orderBy: [PostOrderBy!]! = [PRIMARY_KEY_ASC] + ): PostEdge +} + +"""All input for the \`deletePost\` mutation.""" +input DeletePostInput { + """ + An arbitrary string value with no semantic meaning. Will be included in the + payload verbatim. May be used to track mutations by the client. + """ + clientMutationId: String + id: UUID! +} + +input ProvisionBucketInput { + """The logical bucket key (e.g., "public", "private")""" + bucketKey: String! + + """ + Owner entity ID for entity-scoped bucket provisioning. + Omit for app-level (database-wide) storage. + """ + ownerId: UUID +} + +type ProvisionBucketPayload { + """Whether provisioning succeeded""" + success: Boolean! + + """The S3 bucket name that was provisioned""" + bucketName: String! + + """The access type applied""" + accessType: String! + + """The storage provider used""" + provider: String! + + """The S3 endpoint (null for AWS S3 default)""" + endpoint: String + + """Error message if provisioning failed""" + error: String +}" +`; diff --git a/graphql/server-test/__tests__/upload.integration.test.ts b/graphql/server-test/__tests__/upload.integration.test.ts index 5668bad2b..71175077d 100644 --- a/graphql/server-test/__tests__/upload.integration.test.ts +++ b/graphql/server-test/__tests__/upload.integration.test.ts @@ -43,7 +43,7 @@ const seedFiles = [ const REQUEST_UPLOAD_URL = ` query RequestUploadUrl($key: String!, $contentHash: String!, $contentType: String!, $size: Int!, $filename: String) { - buckets(condition: { key: $key }) { + buckets(where: { key: { equalTo: $key } }) { nodes { id requestUploadUrl( diff --git a/graphql/test/__tests__/__snapshots__/graphile-test.test.ts.snap b/graphql/test/__tests__/__snapshots__/graphile-test.test.ts.snap new file mode 100644 index 000000000..e0c88e162 --- /dev/null +++ b/graphql/test/__tests__/__snapshots__/graphile-test.test.ts.snap @@ -0,0 +1,4480 @@ +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`introspection query snapshot: introspection 1`] = ` +{ + "data": { + "__schema": { + "directives": [ + { + "args": [ + { + "defaultValue": null, + "description": "Included when true.", + "name": "if", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null, + }, + }, + }, + ], + "description": "Directs the executor to include this field or fragment only when the \`if\` argument is true.", + "locations": [ + "FIELD", + "FRAGMENT_SPREAD", + "INLINE_FRAGMENT", + ], + "name": "include", + }, + { + "args": [ + { + "defaultValue": null, + "description": "Skipped when true.", + "name": "if", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null, + }, + }, + }, + ], + "description": "Directs the executor to skip this field or fragment when the \`if\` argument is true.", + "locations": [ + "FIELD", + "FRAGMENT_SPREAD", + "INLINE_FRAGMENT", + ], + "name": "skip", + }, + { + "args": [ + { + "defaultValue": ""No longer supported"", + "description": "Explains why this element was deprecated, usually also including a suggestion for how to access supported similar data. Formatted using the Markdown syntax, as specified by [CommonMark](https://commonmark.org/).", + "name": "reason", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + ], + "description": "Marks an element of a GraphQL schema as no longer supported.", + "locations": [ + "FIELD_DEFINITION", + "ARGUMENT_DEFINITION", + "INPUT_FIELD_DEFINITION", + "ENUM_VALUE", + ], + "name": "deprecated", + }, + { + "args": [ + { + "defaultValue": null, + "description": "The URL that specifies the behavior of this scalar.", + "name": "url", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + }, + ], + "description": "Exposes a URL that specifies the behavior of this scalar.", + "locations": [ + "SCALAR", + ], + "name": "specifiedBy", + }, + { + "args": [], + "description": "Indicates exactly one field must be supplied and this field must not be \`null\`.", + "locations": [ + "INPUT_OBJECT", + ], + "name": "oneOf", + }, + ], + "mutationType": { + "name": "Mutation", + }, + "queryType": { + "name": "Query", + }, + "subscriptionType": null, + "types": [ + { + "description": "The root query type which gives access points into the data universe.", + "enumValues": null, + "fields": [ + { + "args": [ + { + "defaultValue": null, + "description": "Only read the first \`n\` values of the set.", + "name": "first", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null, + }, + }, + { + "defaultValue": null, + "description": "Only read the last \`n\` values of the set.", + "name": "last", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null, + }, + }, + { + "defaultValue": null, + "description": "Skip the first \`n\` values from our \`after\` cursor, an alternative to cursor +based pagination. May not be used with \`last\`.", + "name": "offset", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null, + }, + }, + { + "defaultValue": null, + "description": "Read all values in the set before (above) this cursor.", + "name": "before", + "type": { + "kind": "SCALAR", + "name": "Cursor", + "ofType": null, + }, + }, + { + "defaultValue": null, + "description": "Read all values in the set after (below) this cursor.", + "name": "after", + "type": { + "kind": "SCALAR", + "name": "Cursor", + "ofType": null, + }, + }, + { + "defaultValue": null, + "description": "A filter to be used in determining which values should be returned by the collection.", + "name": "where", + "type": { + "kind": "INPUT_OBJECT", + "name": "UserFilter", + "ofType": null, + }, + }, + { + "defaultValue": "[PRIMARY_KEY_ASC]", + "description": "The method to use when ordering \`User\`.", + "name": "orderBy", + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "ENUM", + "name": "UserOrderBy", + "ofType": null, + }, + }, + }, + }, + ], + "deprecationReason": null, + "description": "Reads and enables pagination through a set of \`User\`.", + "isDeprecated": false, + "name": "users", + "type": { + "kind": "OBJECT", + "name": "UserConnection", + "ofType": null, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": "Metadata about the database schema, including tables, fields, indexes, and constraints. Useful for code generation tools.", + "isDeprecated": false, + "name": "_meta", + "type": { + "kind": "OBJECT", + "name": "MetaSchema", + "ofType": null, + }, + }, + ], + "inputFields": null, + "interfaces": [], + "kind": "OBJECT", + "name": "Query", + "possibleTypes": null, + }, + { + "description": "A connection to a list of \`User\` values.", + "enumValues": null, + "fields": [ + { + "args": [], + "deprecationReason": null, + "description": "A list of \`User\` objects.", + "isDeprecated": false, + "name": "nodes", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "User", + "ofType": null, + }, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": "A list of edges which contains the \`User\` and cursor to aid in pagination.", + "isDeprecated": false, + "name": "edges", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "UserEdge", + "ofType": null, + }, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": "Information to aid in pagination.", + "isDeprecated": false, + "name": "pageInfo", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "PageInfo", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": "The count of *all* \`User\` you could get from the connection.", + "isDeprecated": false, + "name": "totalCount", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Int", + "ofType": null, + }, + }, + }, + ], + "inputFields": null, + "interfaces": [], + "kind": "OBJECT", + "name": "UserConnection", + "possibleTypes": null, + }, + { + "description": null, + "enumValues": null, + "fields": [ + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "id", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Int", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "username", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + }, + ], + "inputFields": null, + "interfaces": [], + "kind": "OBJECT", + "name": "User", + "possibleTypes": null, + }, + { + "description": "The \`Int\` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.", + "enumValues": null, + "fields": null, + "inputFields": null, + "interfaces": null, + "kind": "SCALAR", + "name": "Int", + "possibleTypes": null, + }, + { + "description": "The \`String\` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.", + "enumValues": null, + "fields": null, + "inputFields": null, + "interfaces": null, + "kind": "SCALAR", + "name": "String", + "possibleTypes": null, + }, + { + "description": "A \`User\` edge in the connection.", + "enumValues": null, + "fields": [ + { + "args": [], + "deprecationReason": null, + "description": "A cursor for use in pagination.", + "isDeprecated": false, + "name": "cursor", + "type": { + "kind": "SCALAR", + "name": "Cursor", + "ofType": null, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": "The \`User\` at the end of the edge.", + "isDeprecated": false, + "name": "node", + "type": { + "kind": "OBJECT", + "name": "User", + "ofType": null, + }, + }, + ], + "inputFields": null, + "interfaces": [], + "kind": "OBJECT", + "name": "UserEdge", + "possibleTypes": null, + }, + { + "description": "A location in a connection that can be used for resuming pagination.", + "enumValues": null, + "fields": null, + "inputFields": null, + "interfaces": null, + "kind": "SCALAR", + "name": "Cursor", + "possibleTypes": null, + }, + { + "description": "Information about pagination in a connection.", + "enumValues": null, + "fields": [ + { + "args": [], + "deprecationReason": null, + "description": "When paginating forwards, are there more items?", + "isDeprecated": false, + "name": "hasNextPage", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": "When paginating backwards, are there more items?", + "isDeprecated": false, + "name": "hasPreviousPage", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": "When paginating backwards, the cursor to continue.", + "isDeprecated": false, + "name": "startCursor", + "type": { + "kind": "SCALAR", + "name": "Cursor", + "ofType": null, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": "When paginating forwards, the cursor to continue.", + "isDeprecated": false, + "name": "endCursor", + "type": { + "kind": "SCALAR", + "name": "Cursor", + "ofType": null, + }, + }, + ], + "inputFields": null, + "interfaces": [], + "kind": "OBJECT", + "name": "PageInfo", + "possibleTypes": null, + }, + { + "description": "The \`Boolean\` scalar type represents \`true\` or \`false\`.", + "enumValues": null, + "fields": null, + "inputFields": null, + "interfaces": null, + "kind": "SCALAR", + "name": "Boolean", + "possibleTypes": null, + }, + { + "description": "A filter to be used against \`User\` object types. All fields are combined with a logical ‘and.’", + "enumValues": null, + "fields": null, + "inputFields": [ + { + "defaultValue": null, + "description": "Filter by the object’s \`id\` field.", + "name": "id", + "type": { + "kind": "INPUT_OBJECT", + "name": "IntFilter", + "ofType": null, + }, + }, + { + "defaultValue": null, + "description": "Filter by the object’s \`username\` field.", + "name": "username", + "type": { + "kind": "INPUT_OBJECT", + "name": "StringFilter", + "ofType": null, + }, + }, + { + "defaultValue": null, + "description": "Checks for all expressions in this list.", + "name": "and", + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "INPUT_OBJECT", + "name": "UserFilter", + "ofType": null, + }, + }, + }, + }, + { + "defaultValue": null, + "description": "Checks for any expressions in this list.", + "name": "or", + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "INPUT_OBJECT", + "name": "UserFilter", + "ofType": null, + }, + }, + }, + }, + { + "defaultValue": null, + "description": "Negates the expression.", + "name": "not", + "type": { + "kind": "INPUT_OBJECT", + "name": "UserFilter", + "ofType": null, + }, + }, + ], + "interfaces": null, + "kind": "INPUT_OBJECT", + "name": "UserFilter", + "possibleTypes": null, + }, + { + "description": "A filter to be used against Int fields. All fields are combined with a logical ‘and.’", + "enumValues": null, + "fields": null, + "inputFields": [ + { + "defaultValue": null, + "description": "Is null (if \`true\` is specified) or is not null (if \`false\` is specified).", + "name": "isNull", + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null, + }, + }, + { + "defaultValue": null, + "description": "Equal to the specified value.", + "name": "equalTo", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null, + }, + }, + { + "defaultValue": null, + "description": "Not equal to the specified value.", + "name": "notEqualTo", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null, + }, + }, + { + "defaultValue": null, + "description": "Not equal to the specified value, treating null like an ordinary value.", + "name": "distinctFrom", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null, + }, + }, + { + "defaultValue": null, + "description": "Equal to the specified value, treating null like an ordinary value.", + "name": "notDistinctFrom", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null, + }, + }, + { + "defaultValue": null, + "description": "Included in the specified list.", + "name": "in", + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Int", + "ofType": null, + }, + }, + }, + }, + { + "defaultValue": null, + "description": "Not included in the specified list.", + "name": "notIn", + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Int", + "ofType": null, + }, + }, + }, + }, + { + "defaultValue": null, + "description": "Less than the specified value.", + "name": "lessThan", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null, + }, + }, + { + "defaultValue": null, + "description": "Less than or equal to the specified value.", + "name": "lessThanOrEqualTo", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null, + }, + }, + { + "defaultValue": null, + "description": "Greater than the specified value.", + "name": "greaterThan", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null, + }, + }, + { + "defaultValue": null, + "description": "Greater than or equal to the specified value.", + "name": "greaterThanOrEqualTo", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null, + }, + }, + ], + "interfaces": null, + "kind": "INPUT_OBJECT", + "name": "IntFilter", + "possibleTypes": null, + }, + { + "description": "A filter to be used against String fields. All fields are combined with a logical ‘and.’", + "enumValues": null, + "fields": null, + "inputFields": [ + { + "defaultValue": null, + "description": "Is null (if \`true\` is specified) or is not null (if \`false\` is specified).", + "name": "isNull", + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null, + }, + }, + { + "defaultValue": null, + "description": "Equal to the specified value.", + "name": "equalTo", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "defaultValue": null, + "description": "Not equal to the specified value.", + "name": "notEqualTo", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "defaultValue": null, + "description": "Not equal to the specified value, treating null like an ordinary value.", + "name": "distinctFrom", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "defaultValue": null, + "description": "Equal to the specified value, treating null like an ordinary value.", + "name": "notDistinctFrom", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "defaultValue": null, + "description": "Included in the specified list.", + "name": "in", + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + }, + }, + { + "defaultValue": null, + "description": "Not included in the specified list.", + "name": "notIn", + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + }, + }, + { + "defaultValue": null, + "description": "Less than the specified value.", + "name": "lessThan", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "defaultValue": null, + "description": "Less than or equal to the specified value.", + "name": "lessThanOrEqualTo", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "defaultValue": null, + "description": "Greater than the specified value.", + "name": "greaterThan", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "defaultValue": null, + "description": "Greater than or equal to the specified value.", + "name": "greaterThanOrEqualTo", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "defaultValue": null, + "description": "Contains the specified string (case-sensitive).", + "name": "includes", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "defaultValue": null, + "description": "Does not contain the specified string (case-sensitive).", + "name": "notIncludes", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "defaultValue": null, + "description": "Contains the specified string (case-insensitive).", + "name": "includesInsensitive", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "defaultValue": null, + "description": "Does not contain the specified string (case-insensitive).", + "name": "notIncludesInsensitive", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "defaultValue": null, + "description": "Starts with the specified string (case-sensitive).", + "name": "startsWith", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "defaultValue": null, + "description": "Does not start with the specified string (case-sensitive).", + "name": "notStartsWith", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "defaultValue": null, + "description": "Starts with the specified string (case-insensitive).", + "name": "startsWithInsensitive", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "defaultValue": null, + "description": "Does not start with the specified string (case-insensitive).", + "name": "notStartsWithInsensitive", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "defaultValue": null, + "description": "Ends with the specified string (case-sensitive).", + "name": "endsWith", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "defaultValue": null, + "description": "Does not end with the specified string (case-sensitive).", + "name": "notEndsWith", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "defaultValue": null, + "description": "Ends with the specified string (case-insensitive).", + "name": "endsWithInsensitive", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "defaultValue": null, + "description": "Does not end with the specified string (case-insensitive).", + "name": "notEndsWithInsensitive", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "defaultValue": null, + "description": "Matches the specified pattern (case-sensitive). An underscore (_) matches any single character; a percent sign (%) matches any sequence of zero or more characters.", + "name": "like", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "defaultValue": null, + "description": "Does not match the specified pattern (case-sensitive). An underscore (_) matches any single character; a percent sign (%) matches any sequence of zero or more characters.", + "name": "notLike", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "defaultValue": null, + "description": "Matches the specified pattern (case-insensitive). An underscore (_) matches any single character; a percent sign (%) matches any sequence of zero or more characters.", + "name": "likeInsensitive", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "defaultValue": null, + "description": "Does not match the specified pattern (case-insensitive). An underscore (_) matches any single character; a percent sign (%) matches any sequence of zero or more characters.", + "name": "notLikeInsensitive", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "defaultValue": null, + "description": "Equal to the specified value (case-insensitive).", + "name": "equalToInsensitive", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "defaultValue": null, + "description": "Not equal to the specified value (case-insensitive).", + "name": "notEqualToInsensitive", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "defaultValue": null, + "description": "Not equal to the specified value, treating null like an ordinary value (case-insensitive).", + "name": "distinctFromInsensitive", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "defaultValue": null, + "description": "Equal to the specified value, treating null like an ordinary value (case-insensitive).", + "name": "notDistinctFromInsensitive", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "defaultValue": null, + "description": "Included in the specified list (case-insensitive).", + "name": "inInsensitive", + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + }, + }, + { + "defaultValue": null, + "description": "Not included in the specified list (case-insensitive).", + "name": "notInInsensitive", + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + }, + }, + { + "defaultValue": null, + "description": "Less than the specified value (case-insensitive).", + "name": "lessThanInsensitive", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "defaultValue": null, + "description": "Less than or equal to the specified value (case-insensitive).", + "name": "lessThanOrEqualToInsensitive", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "defaultValue": null, + "description": "Greater than the specified value (case-insensitive).", + "name": "greaterThanInsensitive", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "defaultValue": null, + "description": "Greater than or equal to the specified value (case-insensitive).", + "name": "greaterThanOrEqualToInsensitive", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + ], + "interfaces": null, + "kind": "INPUT_OBJECT", + "name": "StringFilter", + "possibleTypes": null, + }, + { + "description": "Methods to use when ordering \`User\`.", + "enumValues": [ + { + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "NATURAL", + }, + { + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "PRIMARY_KEY_ASC", + }, + { + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "PRIMARY_KEY_DESC", + }, + { + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "ID_ASC", + }, + { + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "ID_DESC", + }, + { + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "USERNAME_ASC", + }, + { + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "USERNAME_DESC", + }, + ], + "fields": null, + "inputFields": null, + "interfaces": null, + "kind": "ENUM", + "name": "UserOrderBy", + "possibleTypes": null, + }, + { + "description": "Root meta schema type", + "enumValues": null, + "fields": [ + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "tables", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "MetaTable", + "ofType": null, + }, + }, + }, + }, + }, + ], + "inputFields": null, + "interfaces": [], + "kind": "OBJECT", + "name": "MetaSchema", + "possibleTypes": null, + }, + { + "description": "Information about a database table", + "enumValues": null, + "fields": [ + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "name", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "schemaName", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "fields", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "MetaField", + "ofType": null, + }, + }, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "indexes", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "MetaIndex", + "ofType": null, + }, + }, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "constraints", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "MetaConstraints", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "foreignKeyConstraints", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "MetaForeignKeyConstraint", + "ofType": null, + }, + }, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "primaryKeyConstraints", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "MetaPrimaryKeyConstraint", + "ofType": null, + }, + }, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "uniqueConstraints", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "MetaUniqueConstraint", + "ofType": null, + }, + }, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "relations", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "MetaRelations", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "inflection", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "MetaInflection", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "query", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "MetaQuery", + "ofType": null, + }, + }, + }, + ], + "inputFields": null, + "interfaces": [], + "kind": "OBJECT", + "name": "MetaTable", + "possibleTypes": null, + }, + { + "description": "Information about a table field/column", + "enumValues": null, + "fields": [ + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "name", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "type", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "MetaType", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "isNotNull", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "hasDefault", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "isPrimaryKey", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "isForeignKey", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "description", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + ], + "inputFields": null, + "interfaces": [], + "kind": "OBJECT", + "name": "MetaField", + "possibleTypes": null, + }, + { + "description": "Information about a PostgreSQL type", + "enumValues": null, + "fields": [ + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "pgType", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "gqlType", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "isArray", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "isNotNull", + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "hasDefault", + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "subtype", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + ], + "inputFields": null, + "interfaces": [], + "kind": "OBJECT", + "name": "MetaType", + "possibleTypes": null, + }, + { + "description": "Information about a database index", + "enumValues": null, + "fields": [ + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "name", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "isUnique", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "isPrimary", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "columns", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "fields", + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "MetaField", + "ofType": null, + }, + }, + }, + }, + ], + "inputFields": null, + "interfaces": [], + "kind": "OBJECT", + "name": "MetaIndex", + "possibleTypes": null, + }, + { + "description": "Table constraints", + "enumValues": null, + "fields": [ + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "primaryKey", + "type": { + "kind": "OBJECT", + "name": "MetaPrimaryKeyConstraint", + "ofType": null, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "unique", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "MetaUniqueConstraint", + "ofType": null, + }, + }, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "foreignKey", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "MetaForeignKeyConstraint", + "ofType": null, + }, + }, + }, + }, + }, + ], + "inputFields": null, + "interfaces": [], + "kind": "OBJECT", + "name": "MetaConstraints", + "possibleTypes": null, + }, + { + "description": "Information about a primary key constraint", + "enumValues": null, + "fields": [ + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "name", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "fields", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "MetaField", + "ofType": null, + }, + }, + }, + }, + }, + ], + "inputFields": null, + "interfaces": [], + "kind": "OBJECT", + "name": "MetaPrimaryKeyConstraint", + "possibleTypes": null, + }, + { + "description": "Information about a unique constraint", + "enumValues": null, + "fields": [ + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "name", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "fields", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "MetaField", + "ofType": null, + }, + }, + }, + }, + }, + ], + "inputFields": null, + "interfaces": [], + "kind": "OBJECT", + "name": "MetaUniqueConstraint", + "possibleTypes": null, + }, + { + "description": "Information about a foreign key constraint", + "enumValues": null, + "fields": [ + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "name", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "fields", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "MetaField", + "ofType": null, + }, + }, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "referencedTable", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "referencedFields", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "refFields", + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "MetaField", + "ofType": null, + }, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "refTable", + "type": { + "kind": "OBJECT", + "name": "MetaRefTable", + "ofType": null, + }, + }, + ], + "inputFields": null, + "interfaces": [], + "kind": "OBJECT", + "name": "MetaForeignKeyConstraint", + "possibleTypes": null, + }, + { + "description": "Reference to a related table", + "enumValues": null, + "fields": [ + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "name", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + }, + ], + "inputFields": null, + "interfaces": [], + "kind": "OBJECT", + "name": "MetaRefTable", + "possibleTypes": null, + }, + { + "description": "Table relations", + "enumValues": null, + "fields": [ + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "belongsTo", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "MetaBelongsToRelation", + "ofType": null, + }, + }, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "has", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "MetaHasRelation", + "ofType": null, + }, + }, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "hasOne", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "MetaHasRelation", + "ofType": null, + }, + }, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "hasMany", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "MetaHasRelation", + "ofType": null, + }, + }, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "manyToMany", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "MetaManyToManyRelation", + "ofType": null, + }, + }, + }, + }, + }, + ], + "inputFields": null, + "interfaces": [], + "kind": "OBJECT", + "name": "MetaRelations", + "possibleTypes": null, + }, + { + "description": "A belongs-to (forward FK) relation", + "enumValues": null, + "fields": [ + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "fieldName", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "isUnique", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "type", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "keys", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "MetaField", + "ofType": null, + }, + }, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "references", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "MetaRefTable", + "ofType": null, + }, + }, + }, + ], + "inputFields": null, + "interfaces": [], + "kind": "OBJECT", + "name": "MetaBelongsToRelation", + "possibleTypes": null, + }, + { + "description": "A has-one or has-many (reverse FK) relation", + "enumValues": null, + "fields": [ + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "fieldName", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "isUnique", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "type", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "keys", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "MetaField", + "ofType": null, + }, + }, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "referencedBy", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "MetaRefTable", + "ofType": null, + }, + }, + }, + ], + "inputFields": null, + "interfaces": [], + "kind": "OBJECT", + "name": "MetaHasRelation", + "possibleTypes": null, + }, + { + "description": "A many-to-many relation via junction table", + "enumValues": null, + "fields": [ + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "fieldName", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "type", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "junctionTable", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "MetaRefTable", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "junctionLeftConstraint", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "MetaForeignKeyConstraint", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "junctionLeftKeyAttributes", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "MetaField", + "ofType": null, + }, + }, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "junctionRightConstraint", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "MetaForeignKeyConstraint", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "junctionRightKeyAttributes", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "MetaField", + "ofType": null, + }, + }, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "leftKeyAttributes", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "MetaField", + "ofType": null, + }, + }, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "rightKeyAttributes", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "MetaField", + "ofType": null, + }, + }, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "rightTable", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "MetaRefTable", + "ofType": null, + }, + }, + }, + ], + "inputFields": null, + "interfaces": [], + "kind": "OBJECT", + "name": "MetaManyToManyRelation", + "possibleTypes": null, + }, + { + "description": "Table inflection names", + "enumValues": null, + "fields": [ + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "tableType", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "allRows", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "connection", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "edge", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "filterType", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "orderByType", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "conditionType", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "patchType", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "createInputType", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "createPayloadType", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "updatePayloadType", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "deletePayloadType", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + }, + ], + "inputFields": null, + "interfaces": [], + "kind": "OBJECT", + "name": "MetaInflection", + "possibleTypes": null, + }, + { + "description": "Table query/mutation names", + "enumValues": null, + "fields": [ + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "all", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "one", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "create", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "update", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "delete", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + ], + "inputFields": null, + "interfaces": [], + "kind": "OBJECT", + "name": "MetaQuery", + "possibleTypes": null, + }, + { + "description": "The root mutation type which contains root level fields which mutate data.", + "enumValues": null, + "fields": [ + { + "args": [ + { + "defaultValue": null, + "description": "The exclusive input argument for this mutation. An object type, make sure to see documentation for this object’s fields.", + "name": "input", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "INPUT_OBJECT", + "name": "CreateUserInput", + "ofType": null, + }, + }, + }, + ], + "deprecationReason": null, + "description": "Creates a single \`User\`.", + "isDeprecated": false, + "name": "createUser", + "type": { + "kind": "OBJECT", + "name": "CreateUserPayload", + "ofType": null, + }, + }, + { + "args": [ + { + "defaultValue": null, + "description": "The exclusive input argument for this mutation. An object type, make sure to see documentation for this object’s fields.", + "name": "input", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "INPUT_OBJECT", + "name": "UpdateUserInput", + "ofType": null, + }, + }, + }, + ], + "deprecationReason": null, + "description": "Updates a single \`User\` using a unique key and a patch.", + "isDeprecated": false, + "name": "updateUser", + "type": { + "kind": "OBJECT", + "name": "UpdateUserPayload", + "ofType": null, + }, + }, + { + "args": [ + { + "defaultValue": null, + "description": "The exclusive input argument for this mutation. An object type, make sure to see documentation for this object’s fields.", + "name": "input", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "INPUT_OBJECT", + "name": "DeleteUserInput", + "ofType": null, + }, + }, + }, + ], + "deprecationReason": null, + "description": "Deletes a single \`User\` using a unique key.", + "isDeprecated": false, + "name": "deleteUser", + "type": { + "kind": "OBJECT", + "name": "DeleteUserPayload", + "ofType": null, + }, + }, + { + "args": [ + { + "defaultValue": null, + "description": "The exclusive input argument for this mutation. An object type, make sure to see documentation for this object’s fields.", + "name": "input", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "INPUT_OBJECT", + "name": "ProvisionBucketInput", + "ofType": null, + }, + }, + }, + ], + "deprecationReason": null, + "description": "Provision an S3 bucket for a logical bucket in the database. +Reads the bucket config via RLS, then creates and configures +the S3 bucket with the appropriate privacy policies, CORS rules, +and lifecycle settings.", + "isDeprecated": false, + "name": "provisionBucket", + "type": { + "kind": "OBJECT", + "name": "ProvisionBucketPayload", + "ofType": null, + }, + }, + ], + "inputFields": null, + "interfaces": [], + "kind": "OBJECT", + "name": "Mutation", + "possibleTypes": null, + }, + { + "description": "The output of our create \`User\` mutation.", + "enumValues": null, + "fields": [ + { + "args": [], + "deprecationReason": null, + "description": "The exact same \`clientMutationId\` that was provided in the mutation input, +unchanged and unused. May be used by a client to track mutations.", + "isDeprecated": false, + "name": "clientMutationId", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": "The \`User\` that was created by this mutation.", + "isDeprecated": false, + "name": "user", + "type": { + "kind": "OBJECT", + "name": "User", + "ofType": null, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": "Our root query field type. Allows us to run any query from our mutation payload.", + "isDeprecated": false, + "name": "query", + "type": { + "kind": "OBJECT", + "name": "Query", + "ofType": null, + }, + }, + { + "args": [ + { + "defaultValue": "[PRIMARY_KEY_ASC]", + "description": "The method to use when ordering \`User\`.", + "name": "orderBy", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "ENUM", + "name": "UserOrderBy", + "ofType": null, + }, + }, + }, + }, + }, + ], + "deprecationReason": null, + "description": "An edge for our \`User\`. May be used by Relay 1.", + "isDeprecated": false, + "name": "userEdge", + "type": { + "kind": "OBJECT", + "name": "UserEdge", + "ofType": null, + }, + }, + ], + "inputFields": null, + "interfaces": [], + "kind": "OBJECT", + "name": "CreateUserPayload", + "possibleTypes": null, + }, + { + "description": "All input for the create \`User\` mutation.", + "enumValues": null, + "fields": null, + "inputFields": [ + { + "defaultValue": null, + "description": "An arbitrary string value with no semantic meaning. Will be included in the +payload verbatim. May be used to track mutations by the client.", + "name": "clientMutationId", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "defaultValue": null, + "description": "The \`User\` to be created by this mutation.", + "name": "user", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "INPUT_OBJECT", + "name": "UserInput", + "ofType": null, + }, + }, + }, + ], + "interfaces": null, + "kind": "INPUT_OBJECT", + "name": "CreateUserInput", + "possibleTypes": null, + }, + { + "description": "An input for mutations affecting \`User\`", + "enumValues": null, + "fields": null, + "inputFields": [ + { + "defaultValue": null, + "description": null, + "name": "id", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null, + }, + }, + { + "defaultValue": null, + "description": null, + "name": "username", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + }, + ], + "interfaces": null, + "kind": "INPUT_OBJECT", + "name": "UserInput", + "possibleTypes": null, + }, + { + "description": "The output of our update \`User\` mutation.", + "enumValues": null, + "fields": [ + { + "args": [], + "deprecationReason": null, + "description": "The exact same \`clientMutationId\` that was provided in the mutation input, +unchanged and unused. May be used by a client to track mutations.", + "isDeprecated": false, + "name": "clientMutationId", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": "The \`User\` that was updated by this mutation.", + "isDeprecated": false, + "name": "user", + "type": { + "kind": "OBJECT", + "name": "User", + "ofType": null, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": "Our root query field type. Allows us to run any query from our mutation payload.", + "isDeprecated": false, + "name": "query", + "type": { + "kind": "OBJECT", + "name": "Query", + "ofType": null, + }, + }, + { + "args": [ + { + "defaultValue": "[PRIMARY_KEY_ASC]", + "description": "The method to use when ordering \`User\`.", + "name": "orderBy", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "ENUM", + "name": "UserOrderBy", + "ofType": null, + }, + }, + }, + }, + }, + ], + "deprecationReason": null, + "description": "An edge for our \`User\`. May be used by Relay 1.", + "isDeprecated": false, + "name": "userEdge", + "type": { + "kind": "OBJECT", + "name": "UserEdge", + "ofType": null, + }, + }, + ], + "inputFields": null, + "interfaces": [], + "kind": "OBJECT", + "name": "UpdateUserPayload", + "possibleTypes": null, + }, + { + "description": "All input for the \`updateUser\` mutation.", + "enumValues": null, + "fields": null, + "inputFields": [ + { + "defaultValue": null, + "description": "An arbitrary string value with no semantic meaning. Will be included in the +payload verbatim. May be used to track mutations by the client.", + "name": "clientMutationId", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "defaultValue": null, + "description": null, + "name": "id", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Int", + "ofType": null, + }, + }, + }, + { + "defaultValue": null, + "description": "An object where the defined keys will be set on the \`User\` being updated.", + "name": "userPatch", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "INPUT_OBJECT", + "name": "UserPatch", + "ofType": null, + }, + }, + }, + ], + "interfaces": null, + "kind": "INPUT_OBJECT", + "name": "UpdateUserInput", + "possibleTypes": null, + }, + { + "description": "Represents an update to a \`User\`. Fields that are set will be updated.", + "enumValues": null, + "fields": null, + "inputFields": [ + { + "defaultValue": null, + "description": null, + "name": "id", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null, + }, + }, + { + "defaultValue": null, + "description": null, + "name": "username", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + ], + "interfaces": null, + "kind": "INPUT_OBJECT", + "name": "UserPatch", + "possibleTypes": null, + }, + { + "description": "The output of our delete \`User\` mutation.", + "enumValues": null, + "fields": [ + { + "args": [], + "deprecationReason": null, + "description": "The exact same \`clientMutationId\` that was provided in the mutation input, +unchanged and unused. May be used by a client to track mutations.", + "isDeprecated": false, + "name": "clientMutationId", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": "The \`User\` that was deleted by this mutation.", + "isDeprecated": false, + "name": "user", + "type": { + "kind": "OBJECT", + "name": "User", + "ofType": null, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": "Our root query field type. Allows us to run any query from our mutation payload.", + "isDeprecated": false, + "name": "query", + "type": { + "kind": "OBJECT", + "name": "Query", + "ofType": null, + }, + }, + { + "args": [ + { + "defaultValue": "[PRIMARY_KEY_ASC]", + "description": "The method to use when ordering \`User\`.", + "name": "orderBy", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "ENUM", + "name": "UserOrderBy", + "ofType": null, + }, + }, + }, + }, + }, + ], + "deprecationReason": null, + "description": "An edge for our \`User\`. May be used by Relay 1.", + "isDeprecated": false, + "name": "userEdge", + "type": { + "kind": "OBJECT", + "name": "UserEdge", + "ofType": null, + }, + }, + ], + "inputFields": null, + "interfaces": [], + "kind": "OBJECT", + "name": "DeleteUserPayload", + "possibleTypes": null, + }, + { + "description": "All input for the \`deleteUser\` mutation.", + "enumValues": null, + "fields": null, + "inputFields": [ + { + "defaultValue": null, + "description": "An arbitrary string value with no semantic meaning. Will be included in the +payload verbatim. May be used to track mutations by the client.", + "name": "clientMutationId", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "defaultValue": null, + "description": null, + "name": "id", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Int", + "ofType": null, + }, + }, + }, + ], + "interfaces": null, + "kind": "INPUT_OBJECT", + "name": "DeleteUserInput", + "possibleTypes": null, + }, + { + "description": null, + "enumValues": null, + "fields": null, + "inputFields": [ + { + "defaultValue": null, + "description": "The logical bucket key (e.g., "public", "private")", + "name": "bucketKey", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + }, + { + "defaultValue": null, + "description": "Owner entity ID for entity-scoped bucket provisioning. +Omit for app-level (database-wide) storage.", + "name": "ownerId", + "type": { + "kind": "SCALAR", + "name": "UUID", + "ofType": null, + }, + }, + ], + "interfaces": null, + "kind": "INPUT_OBJECT", + "name": "ProvisionBucketInput", + "possibleTypes": null, + }, + { + "description": "A universally unique identifier as defined by [RFC 4122](https://tools.ietf.org/html/rfc4122).", + "enumValues": null, + "fields": null, + "inputFields": null, + "interfaces": null, + "kind": "SCALAR", + "name": "UUID", + "possibleTypes": null, + }, + { + "description": null, + "enumValues": null, + "fields": [ + { + "args": [], + "deprecationReason": null, + "description": "Whether provisioning succeeded", + "isDeprecated": false, + "name": "success", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": "The S3 bucket name that was provisioned", + "isDeprecated": false, + "name": "bucketName", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": "The access type applied", + "isDeprecated": false, + "name": "accessType", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": "The storage provider used", + "isDeprecated": false, + "name": "provider", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": "The S3 endpoint (null for AWS S3 default)", + "isDeprecated": false, + "name": "endpoint", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": "Error message if provisioning failed", + "isDeprecated": false, + "name": "error", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + ], + "inputFields": null, + "interfaces": [], + "kind": "OBJECT", + "name": "ProvisionBucketPayload", + "possibleTypes": null, + }, + { + "description": "A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, as well as the entry points for query, mutation, and subscription operations.", + "enumValues": null, + "fields": [ + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "description", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": "A list of all types supported by this server.", + "isDeprecated": false, + "name": "types", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null, + }, + }, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": "The type that query operations will be rooted at.", + "isDeprecated": false, + "name": "queryType", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": "If this server supports mutation, the type that mutation operations will be rooted at.", + "isDeprecated": false, + "name": "mutationType", + "type": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": "If this server support subscription, the type that subscription operations will be rooted at.", + "isDeprecated": false, + "name": "subscriptionType", + "type": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": "A list of all directives supported by this server.", + "isDeprecated": false, + "name": "directives", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Directive", + "ofType": null, + }, + }, + }, + }, + }, + ], + "inputFields": null, + "interfaces": [], + "kind": "OBJECT", + "name": "__Schema", + "possibleTypes": null, + }, + { + "description": "The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in GraphQL as represented by the \`__TypeKind\` enum. + +Depending on the kind of a type, certain fields describe information about that type. Scalar types provide no information beyond a name, description and optional \`specifiedByURL\`, while Enum types provide their values. Object and Interface types provide the fields they describe. Abstract types, Union and Interface, provide the Object types possible at runtime. List and NonNull types compose other types.", + "enumValues": null, + "fields": [ + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "kind", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "ENUM", + "name": "__TypeKind", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "name", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "description", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "specifiedByURL", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "args": [ + { + "defaultValue": "false", + "description": null, + "name": "includeDeprecated", + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null, + }, + }, + ], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "fields", + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Field", + "ofType": null, + }, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "interfaces", + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null, + }, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "possibleTypes", + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null, + }, + }, + }, + }, + { + "args": [ + { + "defaultValue": "false", + "description": null, + "name": "includeDeprecated", + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null, + }, + }, + ], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "enumValues", + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__EnumValue", + "ofType": null, + }, + }, + }, + }, + { + "args": [ + { + "defaultValue": "false", + "description": null, + "name": "includeDeprecated", + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null, + }, + }, + ], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "inputFields", + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__InputValue", + "ofType": null, + }, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "ofType", + "type": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "isOneOf", + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null, + }, + }, + ], + "inputFields": null, + "interfaces": [], + "kind": "OBJECT", + "name": "__Type", + "possibleTypes": null, + }, + { + "description": "An enum describing what kind of type a given \`__Type\` is.", + "enumValues": [ + { + "deprecationReason": null, + "description": "Indicates this type is a scalar.", + "isDeprecated": false, + "name": "SCALAR", + }, + { + "deprecationReason": null, + "description": "Indicates this type is an object. \`fields\` and \`interfaces\` are valid fields.", + "isDeprecated": false, + "name": "OBJECT", + }, + { + "deprecationReason": null, + "description": "Indicates this type is an interface. \`fields\`, \`interfaces\`, and \`possibleTypes\` are valid fields.", + "isDeprecated": false, + "name": "INTERFACE", + }, + { + "deprecationReason": null, + "description": "Indicates this type is a union. \`possibleTypes\` is a valid field.", + "isDeprecated": false, + "name": "UNION", + }, + { + "deprecationReason": null, + "description": "Indicates this type is an enum. \`enumValues\` is a valid field.", + "isDeprecated": false, + "name": "ENUM", + }, + { + "deprecationReason": null, + "description": "Indicates this type is an input object. \`inputFields\` is a valid field.", + "isDeprecated": false, + "name": "INPUT_OBJECT", + }, + { + "deprecationReason": null, + "description": "Indicates this type is a list. \`ofType\` is a valid field.", + "isDeprecated": false, + "name": "LIST", + }, + { + "deprecationReason": null, + "description": "Indicates this type is a non-null. \`ofType\` is a valid field.", + "isDeprecated": false, + "name": "NON_NULL", + }, + ], + "fields": null, + "inputFields": null, + "interfaces": null, + "kind": "ENUM", + "name": "__TypeKind", + "possibleTypes": null, + }, + { + "description": "Object and Interface types are described by a list of Fields, each of which has a name, potentially a list of arguments, and a return type.", + "enumValues": null, + "fields": [ + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "name", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "description", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "args": [ + { + "defaultValue": "false", + "description": null, + "name": "includeDeprecated", + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null, + }, + }, + ], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "args", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__InputValue", + "ofType": null, + }, + }, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "type", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "isDeprecated", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "deprecationReason", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + ], + "inputFields": null, + "interfaces": [], + "kind": "OBJECT", + "name": "__Field", + "possibleTypes": null, + }, + { + "description": "Arguments provided to Fields or Directives and the input fields of an InputObject are represented as Input Values which describe their type and optionally a default value.", + "enumValues": null, + "fields": [ + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "name", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "description", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "type", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": "A GraphQL-formatted string representing the default value for this input value.", + "isDeprecated": false, + "name": "defaultValue", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "isDeprecated", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "deprecationReason", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + ], + "inputFields": null, + "interfaces": [], + "kind": "OBJECT", + "name": "__InputValue", + "possibleTypes": null, + }, + { + "description": "One possible value for a given Enum. Enum values are unique values, not a placeholder for a string or numeric value. However an Enum value is returned in a JSON response as a string.", + "enumValues": null, + "fields": [ + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "name", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "description", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "isDeprecated", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "deprecationReason", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + ], + "inputFields": null, + "interfaces": [], + "kind": "OBJECT", + "name": "__EnumValue", + "possibleTypes": null, + }, + { + "description": "A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document. + +In some cases, you need to provide options to alter GraphQL's execution behavior in ways field arguments will not suffice, such as conditionally including or skipping a field. Directives provide this by describing additional information to the executor.", + "enumValues": null, + "fields": [ + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "name", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "description", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "isRepeatable", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null, + }, + }, + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "locations", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "ENUM", + "name": "__DirectiveLocation", + "ofType": null, + }, + }, + }, + }, + }, + { + "args": [ + { + "defaultValue": "false", + "description": null, + "name": "includeDeprecated", + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null, + }, + }, + ], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "args", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__InputValue", + "ofType": null, + }, + }, + }, + }, + }, + ], + "inputFields": null, + "interfaces": [], + "kind": "OBJECT", + "name": "__Directive", + "possibleTypes": null, + }, + { + "description": "A Directive can be adjacent to many parts of the GraphQL language, a __DirectiveLocation describes one such possible adjacencies.", + "enumValues": [ + { + "deprecationReason": null, + "description": "Location adjacent to a query operation.", + "isDeprecated": false, + "name": "QUERY", + }, + { + "deprecationReason": null, + "description": "Location adjacent to a mutation operation.", + "isDeprecated": false, + "name": "MUTATION", + }, + { + "deprecationReason": null, + "description": "Location adjacent to a subscription operation.", + "isDeprecated": false, + "name": "SUBSCRIPTION", + }, + { + "deprecationReason": null, + "description": "Location adjacent to a field.", + "isDeprecated": false, + "name": "FIELD", + }, + { + "deprecationReason": null, + "description": "Location adjacent to a fragment definition.", + "isDeprecated": false, + "name": "FRAGMENT_DEFINITION", + }, + { + "deprecationReason": null, + "description": "Location adjacent to a fragment spread.", + "isDeprecated": false, + "name": "FRAGMENT_SPREAD", + }, + { + "deprecationReason": null, + "description": "Location adjacent to an inline fragment.", + "isDeprecated": false, + "name": "INLINE_FRAGMENT", + }, + { + "deprecationReason": null, + "description": "Location adjacent to a variable definition.", + "isDeprecated": false, + "name": "VARIABLE_DEFINITION", + }, + { + "deprecationReason": null, + "description": "Location adjacent to a schema definition.", + "isDeprecated": false, + "name": "SCHEMA", + }, + { + "deprecationReason": null, + "description": "Location adjacent to a scalar definition.", + "isDeprecated": false, + "name": "SCALAR", + }, + { + "deprecationReason": null, + "description": "Location adjacent to an object type definition.", + "isDeprecated": false, + "name": "OBJECT", + }, + { + "deprecationReason": null, + "description": "Location adjacent to a field definition.", + "isDeprecated": false, + "name": "FIELD_DEFINITION", + }, + { + "deprecationReason": null, + "description": "Location adjacent to an argument definition.", + "isDeprecated": false, + "name": "ARGUMENT_DEFINITION", + }, + { + "deprecationReason": null, + "description": "Location adjacent to an interface definition.", + "isDeprecated": false, + "name": "INTERFACE", + }, + { + "deprecationReason": null, + "description": "Location adjacent to a union definition.", + "isDeprecated": false, + "name": "UNION", + }, + { + "deprecationReason": null, + "description": "Location adjacent to an enum definition.", + "isDeprecated": false, + "name": "ENUM", + }, + { + "deprecationReason": null, + "description": "Location adjacent to an enum value definition.", + "isDeprecated": false, + "name": "ENUM_VALUE", + }, + { + "deprecationReason": null, + "description": "Location adjacent to an input object type definition.", + "isDeprecated": false, + "name": "INPUT_OBJECT", + }, + { + "deprecationReason": null, + "description": "Location adjacent to an input object field definition.", + "isDeprecated": false, + "name": "INPUT_FIELD_DEFINITION", + }, + ], + "fields": null, + "inputFields": null, + "interfaces": null, + "kind": "ENUM", + "name": "__DirectiveLocation", + "possibleTypes": null, + }, + ], + }, + }, +} +`;