feat(db-*): allow to thread id to create operation data without custom IDs (#11709)

Fixes https://github.com/payloadcms/payload/issues/6884

Adds a new flag `acceptIDOnCreate` that allows you to thread your own
`id` to `payload.create` `data`, for example:

```ts
// doc created with id 1
const doc = await payload.create({ collection: 'posts', data: {id: 1, title: "my title"}})
```

```ts
import { Types } from 'mongoose'
const id = new Types.ObjectId().toHexString()
const doc = await payload.create({ collection: 'posts', data: {id, title: "my title"}})
```
This commit is contained in:
Sasha
2025-03-18 05:48:35 +02:00
committed by GitHub
parent 95821c6136
commit f442d22237
17 changed files with 173 additions and 18 deletions

View File

@@ -40,6 +40,7 @@ export default buildConfig({
| `transactionOptions` | An object with configuration properties used in [transactions](https://www.mongodb.com/docs/manual/core/transactions/) or `false` which will disable the use of transactions. | | `transactionOptions` | An object with configuration properties used in [transactions](https://www.mongodb.com/docs/manual/core/transactions/) or `false` which will disable the use of transactions. |
| `collation` | Enable language-specific string comparison with customizable options. Available on MongoDB 3.4+. Defaults locale to "en". Example: `{ strength: 3 }`. For a full list of collation options and their definitions, see the [MongoDB documentation](https://www.mongodb.com/docs/manual/reference/collation/). | | `collation` | Enable language-specific string comparison with customizable options. Available on MongoDB 3.4+. Defaults locale to "en". Example: `{ strength: 3 }`. For a full list of collation options and their definitions, see the [MongoDB documentation](https://www.mongodb.com/docs/manual/reference/collation/). |
| `allowAdditionalKeys` | By default, Payload strips all additional keys from MongoDB data that don't exist in the Payload schema. If you have some data that you want to include to the result but it doesn't exist in Payload, you can set this to `true`. Be careful as Payload access control _won't_ work for this data. | | `allowAdditionalKeys` | By default, Payload strips all additional keys from MongoDB data that don't exist in the Payload schema. If you have some data that you want to include to the result but it doesn't exist in Payload, you can set this to `true`. Be careful as Payload access control _won't_ work for this data. |
| `allowIDOnCreate` | Set to `true` to use the `id` passed in data on the create API operations without using a custom ID field. |
## Access to Mongoose models ## Access to Mongoose models

View File

@@ -79,6 +79,7 @@ export default buildConfig({
| `beforeSchemaInit` | Drizzle schema hook. Runs before the schema is built. [More Details](#beforeschemainit) | | `beforeSchemaInit` | Drizzle schema hook. Runs before the schema is built. [More Details](#beforeschemainit) |
| `afterSchemaInit` | Drizzle schema hook. Runs after the schema is built. [More Details](#afterschemainit) | | `afterSchemaInit` | Drizzle schema hook. Runs after the schema is built. [More Details](#afterschemainit) |
| `generateSchemaOutputFile` | Override generated schema from `payload generate:db-schema` file path. Defaults to `{CWD}/src/payload-generated.schema.ts` | | `generateSchemaOutputFile` | Override generated schema from `payload generate:db-schema` file path. Defaults to `{CWD}/src/payload-generated.schema.ts` |
| `allowIDOnCreate` | Set to `true` to use the `id` passed in data on the create API operations without using a custom ID field. |
## Access to Drizzle ## Access to Drizzle

View File

@@ -49,6 +49,7 @@ export default buildConfig({
| `afterSchemaInit` | Drizzle schema hook. Runs after the schema is built. [More Details](#afterschemainit) | | `afterSchemaInit` | Drizzle schema hook. Runs after the schema is built. [More Details](#afterschemainit) |
| `generateSchemaOutputFile` | Override generated schema from `payload generate:db-schema` file path. Defaults to `{CWD}/src/payload-generated.schema.ts` | | `generateSchemaOutputFile` | Override generated schema from `payload generate:db-schema` file path. Defaults to `{CWD}/src/payload-generated.schema.ts` |
| `autoIncrement` | Pass `true` to enable SQLite [AUTOINCREMENT](https://www.sqlite.org/autoinc.html) for primary keys to ensure the same ID cannot be reused from deleted rows | | `autoIncrement` | Pass `true` to enable SQLite [AUTOINCREMENT](https://www.sqlite.org/autoinc.html) for primary keys to ensure the same ID cannot be reused from deleted rows |
| `allowIDOnCreate` | Set to `true` to use the `id` passed in data on the create API operations without using a custom ID field. |
## Access to Drizzle ## Access to Drizzle

View File

@@ -1,6 +1,7 @@
import type { CreateOptions } from 'mongoose'
import type { Create } from 'payload' import type { Create } from 'payload'
import { type CreateOptions, Types } from 'mongoose'
import type { MongooseAdapter } from './index.js' import type { MongooseAdapter } from './index.js'
import { getCollection } from './utilities/getEntity.js' import { getCollection } from './utilities/getEntity.js'
@@ -29,6 +30,15 @@ export const create: Create = async function create(
if (customIDType) { if (customIDType) {
data._id = data.id data._id = data.id
} else if (this.allowIDOnCreate && data.id) {
try {
data._id = new Types.ObjectId(data.id as string)
} catch (error) {
this.payload.logger.error(
`It appears you passed ID to create operation data but it cannot be sanitized to ObjectID, value - ${JSON.stringify(data.id)}`,
)
throw error
}
} }
try { try {

View File

@@ -70,8 +70,20 @@ export interface Args {
* @default false * @default false
*/ */
allowAdditionalKeys?: boolean allowAdditionalKeys?: boolean
/**
* Enable this flag if you want to thread your own ID to create operation data, for example:
* ```ts
* import { Types } from 'mongoose'
*
* const id = new Types.ObjectId().toHexString()
* const doc = await payload.create({ collection: 'posts', data: {id, title: "my title"}})
* assertEq(doc.id, id)
* ```
*/
allowIDOnCreate?: boolean
/** Set to false to disable auto-pluralization of collection names, Defaults to true */ /** Set to false to disable auto-pluralization of collection names, Defaults to true */
autoPluralization?: boolean autoPluralization?: boolean
/** /**
* If enabled, collation allows for language-specific rules for string comparison. * If enabled, collation allows for language-specific rules for string comparison.
* This configuration can include the following options: * This configuration can include the following options:
@@ -98,7 +110,6 @@ export interface Args {
collation?: Omit<CollationOptions, 'locale'> collation?: Omit<CollationOptions, 'locale'>
collectionsSchemaOptions?: Partial<Record<CollectionSlug, SchemaOptions>> collectionsSchemaOptions?: Partial<Record<CollectionSlug, SchemaOptions>>
/** Extra configuration options */ /** Extra configuration options */
connectOptions?: { connectOptions?: {
/** /**
@@ -183,6 +194,7 @@ declare module 'payload' {
export function mongooseAdapter({ export function mongooseAdapter({
allowAdditionalKeys = false, allowAdditionalKeys = false,
allowIDOnCreate = false,
autoPluralization = true, autoPluralization = true,
collectionsSchemaOptions = {}, collectionsSchemaOptions = {},
connectOptions, connectOptions,
@@ -220,6 +232,7 @@ export function mongooseAdapter({
versions: {}, versions: {},
// DatabaseAdapter // DatabaseAdapter
allowAdditionalKeys, allowAdditionalKeys,
allowIDOnCreate,
beginTransaction: transactionOptions === false ? defaultBeginTransaction() : beginTransaction, beginTransaction: transactionOptions === false ? defaultBeginTransaction() : beginTransaction,
collectionsSchemaOptions, collectionsSchemaOptions,
commitTransaction, commitTransaction,
@@ -259,6 +272,7 @@ export function mongooseAdapter({
} }
return { return {
allowIDOnCreate,
defaultIDType: 'text', defaultIDType: 'text',
init: adapter, init: adapter,
} }

View File

@@ -64,6 +64,7 @@ const filename = fileURLToPath(import.meta.url)
export function postgresAdapter(args: Args): DatabaseAdapterObj<PostgresAdapter> { export function postgresAdapter(args: Args): DatabaseAdapterObj<PostgresAdapter> {
const postgresIDType = args.idType || 'serial' const postgresIDType = args.idType || 'serial'
const payloadIDType = postgresIDType === 'serial' ? 'number' : 'text' const payloadIDType = postgresIDType === 'serial' ? 'number' : 'text'
const allowIDOnCreate = args.allowIDOnCreate ?? false
function adapter({ payload }: { payload: Payload }) { function adapter({ payload }: { payload: Payload }) {
const migrationDir = findMigrationDir(args.migrationDir) const migrationDir = findMigrationDir(args.migrationDir)
@@ -94,6 +95,7 @@ export function postgresAdapter(args: Args): DatabaseAdapterObj<PostgresAdapter>
return createDatabaseAdapter<PostgresAdapter>({ return createDatabaseAdapter<PostgresAdapter>({
name: 'postgres', name: 'postgres',
afterSchemaInit: args.afterSchemaInit ?? [], afterSchemaInit: args.afterSchemaInit ?? [],
allowIDOnCreate,
beforeSchemaInit: args.beforeSchemaInit ?? [], beforeSchemaInit: args.beforeSchemaInit ?? [],
createDatabase, createDatabase,
createExtensions, createExtensions,
@@ -204,6 +206,7 @@ export function postgresAdapter(args: Args): DatabaseAdapterObj<PostgresAdapter>
} }
return { return {
allowIDOnCreate,
defaultIDType: payloadIDType, defaultIDType: payloadIDType,
init: adapter, init: adapter,
} }

View File

@@ -19,6 +19,14 @@ export type Args = {
* Examples may include: composite indices, generated columns, vectors * Examples may include: composite indices, generated columns, vectors
*/ */
afterSchemaInit?: PostgresSchemaHook[] afterSchemaInit?: PostgresSchemaHook[]
/**
* Enable this flag if you want to thread your own ID to create operation data, for example:
* ```ts
* // doc created with id 1
* const doc = await payload.create({ collection: 'posts', data: {id: 1, title: "my title"}})
* ```
*/
allowIDOnCreate?: boolean
/** /**
* Transform the schema before it's built. * Transform the schema before it's built.
* You can use it to preserve an existing database schema and if there are any collissions Payload will override them. * You can use it to preserve an existing database schema and if there are any collissions Payload will override them.

View File

@@ -66,6 +66,7 @@ const filename = fileURLToPath(import.meta.url)
export function sqliteAdapter(args: Args): DatabaseAdapterObj<SQLiteAdapter> { export function sqliteAdapter(args: Args): DatabaseAdapterObj<SQLiteAdapter> {
const sqliteIDType = args.idType || 'number' const sqliteIDType = args.idType || 'number'
const payloadIDType = sqliteIDType === 'uuid' ? 'text' : 'number' const payloadIDType = sqliteIDType === 'uuid' ? 'text' : 'number'
const allowIDOnCreate = args.allowIDOnCreate ?? false
function adapter({ payload }: { payload: Payload }) { function adapter({ payload }: { payload: Payload }) {
const migrationDir = findMigrationDir(args.migrationDir) const migrationDir = findMigrationDir(args.migrationDir)
@@ -88,6 +89,7 @@ export function sqliteAdapter(args: Args): DatabaseAdapterObj<SQLiteAdapter> {
return createDatabaseAdapter<SQLiteAdapter>({ return createDatabaseAdapter<SQLiteAdapter>({
name: 'sqlite', name: 'sqlite',
afterSchemaInit: args.afterSchemaInit ?? [], afterSchemaInit: args.afterSchemaInit ?? [],
allowIDOnCreate,
autoIncrement: args.autoIncrement ?? false, autoIncrement: args.autoIncrement ?? false,
beforeSchemaInit: args.beforeSchemaInit ?? [], beforeSchemaInit: args.beforeSchemaInit ?? [],
client: undefined, client: undefined,
@@ -186,6 +188,7 @@ export function sqliteAdapter(args: Args): DatabaseAdapterObj<SQLiteAdapter> {
} }
return { return {
allowIDOnCreate,
defaultIDType: payloadIDType, defaultIDType: payloadIDType,
init: adapter, init: adapter,
} }

View File

@@ -31,6 +31,14 @@ export type Args = {
* Examples may include: composite indices, generated columns, vectors * Examples may include: composite indices, generated columns, vectors
*/ */
afterSchemaInit?: SQLiteSchemaHook[] afterSchemaInit?: SQLiteSchemaHook[]
/**
* Enable this flag if you want to thread your own ID to create operation data, for example:
* ```ts
* // doc created with id 1
* const doc = await payload.create({ collection: 'posts', data: {id: 1, title: "my title"}})
* ```
*/
allowIDOnCreate?: boolean
/** /**
* Enable [AUTOINCREMENT](https://www.sqlite.org/autoinc.html) for Primary Keys. * Enable [AUTOINCREMENT](https://www.sqlite.org/autoinc.html) for Primary Keys.
* This ensures that the same ID cannot be reused from previously deleted rows. * This ensures that the same ID cannot be reused from previously deleted rows.

View File

@@ -64,6 +64,7 @@ const filename = fileURLToPath(import.meta.url)
export function vercelPostgresAdapter(args: Args = {}): DatabaseAdapterObj<VercelPostgresAdapter> { export function vercelPostgresAdapter(args: Args = {}): DatabaseAdapterObj<VercelPostgresAdapter> {
const postgresIDType = args.idType || 'serial' const postgresIDType = args.idType || 'serial'
const payloadIDType = postgresIDType === 'serial' ? 'number' : 'text' const payloadIDType = postgresIDType === 'serial' ? 'number' : 'text'
const allowIDOnCreate = args.allowIDOnCreate ?? false
function adapter({ payload }: { payload: Payload }) { function adapter({ payload }: { payload: Payload }) {
const migrationDir = findMigrationDir(args.migrationDir) const migrationDir = findMigrationDir(args.migrationDir)
@@ -90,6 +91,7 @@ export function vercelPostgresAdapter(args: Args = {}): DatabaseAdapterObj<Verce
return createDatabaseAdapter<VercelPostgresAdapter>({ return createDatabaseAdapter<VercelPostgresAdapter>({
name: 'postgres', name: 'postgres',
afterSchemaInit: args.afterSchemaInit ?? [], afterSchemaInit: args.afterSchemaInit ?? [],
allowIDOnCreate,
beforeSchemaInit: args.beforeSchemaInit ?? [], beforeSchemaInit: args.beforeSchemaInit ?? [],
createDatabase, createDatabase,
createExtensions, createExtensions,
@@ -195,6 +197,7 @@ export function vercelPostgresAdapter(args: Args = {}): DatabaseAdapterObj<Verce
} }
return { return {
allowIDOnCreate,
defaultIDType: payloadIDType, defaultIDType: payloadIDType,
init: adapter, init: adapter,
} }

View File

@@ -19,6 +19,14 @@ export type Args = {
* Examples may include: composite indices, generated columns, vectors * Examples may include: composite indices, generated columns, vectors
*/ */
afterSchemaInit?: PostgresSchemaHook[] afterSchemaInit?: PostgresSchemaHook[]
/**
* Enable this flag if you want to thread your own ID to create operation data, for example:
* ```ts
* // doc created with id 1
* const doc = await payload.create({ collection: 'posts', data: {id: 1, title: "my title"}})
* ```
*/
allowIDOnCreate?: boolean
/** /**
* Transform the schema before it's built. * Transform the schema before it's built.
* You can use it to preserve an existing database schema and if there are any collissions Payload will override them. * You can use it to preserve an existing database schema and if there are any collissions Payload will override them.

View File

@@ -9,7 +9,7 @@ import { getTransaction } from './utilities/getTransaction.js'
export const create: Create = async function create( export const create: Create = async function create(
this: DrizzleAdapter, this: DrizzleAdapter,
{ collection: collectionSlug, data, req, select, returning }, { collection: collectionSlug, data, req, returning, select },
) { ) {
const db = await getTransaction(this, req) const db = await getTransaction(this, req)
const collection = this.payload.collections[collectionSlug].config const collection = this.payload.collections[collectionSlug].config
@@ -21,11 +21,11 @@ export const create: Create = async function create(
data, data,
db, db,
fields: collection.flattenedFields, fields: collection.flattenedFields,
ignoreResult: returning === false,
operation: 'create', operation: 'create',
req, req,
select, select,
tableName, tableName,
ignoreResult: returning === false,
}) })
if (returning === false) { if (returning === false) {

View File

@@ -66,6 +66,9 @@ export const upsertRow = async <T extends Record<string, unknown> | TypeWithID>(
}) })
} }
} else { } else {
if (adapter.allowIDOnCreate && data.id) {
rowToInsert.row.id = data.id
}
;[insertedRow] = await adapter.insert({ ;[insertedRow] = await adapter.insert({
db, db,
tableName, tableName,

View File

@@ -145,10 +145,25 @@ export function initCollections({ config, graphqlResult }: InitCollectionsGraphQ
}) })
} }
let mutationCreateInputFields = mutationInputFields
if (
config.db.allowIDOnCreate &&
!collectionConfig.flattenedFields.some((field) => field.name === 'id')
) {
mutationCreateInputFields = [
...mutationCreateInputFields,
{
name: 'id',
type: config.db.defaultIDType,
} as Field,
]
}
const createMutationInputType = buildMutationInputType({ const createMutationInputType = buildMutationInputType({
name: singularName, name: singularName,
config, config,
fields: mutationInputFields, fields: mutationCreateInputFields,
graphqlResult, graphqlResult,
parentIsLocalized: false, parentIsLocalized: false,
parentName: singularName, parentName: singularName,

View File

@@ -15,13 +15,14 @@ import { migrateRefresh } from './migrations/migrateRefresh.js'
import { migrateReset } from './migrations/migrateReset.js' import { migrateReset } from './migrations/migrateReset.js'
import { migrateStatus } from './migrations/migrateStatus.js' import { migrateStatus } from './migrations/migrateStatus.js'
const beginTransaction: BeginTransaction = async () => null const beginTransaction: BeginTransaction = () => Promise.resolve(null)
const rollbackTransaction: RollbackTransaction = async () => null const rollbackTransaction: RollbackTransaction = () => Promise.resolve(null)
const commitTransaction: CommitTransaction = async () => null const commitTransaction: CommitTransaction = () => Promise.resolve(null)
export function createDatabaseAdapter<T extends BaseDatabaseAdapter>( export function createDatabaseAdapter<T extends BaseDatabaseAdapter>(
args: MarkOptional< args: MarkOptional<
T, T,
| 'allowIDOnCreate'
| 'createMigration' | 'createMigration'
| 'migrate' | 'migrate'
| 'migrateDown' | 'migrateDown'
@@ -39,14 +40,13 @@ export function createDatabaseAdapter<T extends BaseDatabaseAdapter>(
createMigration, createMigration,
migrate, migrate,
migrateDown, migrateDown,
migrateFresh: async ({ forceAcceptWarning = null }) => null, migrateFresh: () => Promise.resolve(null),
migrateRefresh, migrateRefresh,
migrateReset, migrateReset,
migrateStatus, migrateStatus,
rollbackTransaction, rollbackTransaction,
...args, ...args,
// Ensure migrationDir is set // Ensure migrationDir is set
migrationDir: args.migrationDir || 'migrations', migrationDir: args.migrationDir || 'migrations',
} as T } as T

View File

@@ -14,11 +14,13 @@ import type { TypeWithVersion } from '../versions/types.js'
export type { TypeWithVersion } export type { TypeWithVersion }
export interface BaseDatabaseAdapter { export interface BaseDatabaseAdapter {
allowIDOnCreate?: boolean
/** /**
* Start a transaction, requiring commitTransaction() to be called for any changes to be made. * Start a transaction, requiring commitTransaction() to be called for any changes to be made.
* @returns an identifier for the transaction or null if one cannot be established * @returns an identifier for the transaction or null if one cannot be established
*/ */
beginTransaction: BeginTransaction beginTransaction: BeginTransaction
/** /**
* Persist the changes made since the start of the transaction. * Persist the changes made since the start of the transaction.
*/ */
@@ -28,16 +30,16 @@ export interface BaseDatabaseAdapter {
* Open the connection to the database * Open the connection to the database
*/ */
connect?: Connect connect?: Connect
count: Count count: Count
countGlobalVersions: CountGlobalVersions countGlobalVersions: CountGlobalVersions
countVersions: CountVersions countVersions: CountVersions
create: Create create: Create
createGlobal: CreateGlobal createGlobal: CreateGlobal
createGlobalVersion: CreateGlobalVersion createGlobalVersion: CreateGlobalVersion
/** /**
* Output a migration file * Output a migration file
*/ */
@@ -53,8 +55,8 @@ export interface BaseDatabaseAdapter {
deleteMany: DeleteMany deleteMany: DeleteMany
deleteOne: DeleteOne deleteOne: DeleteOne
deleteVersions: DeleteVersions deleteVersions: DeleteVersions
/** /**
* Terminate the connection with the database * Terminate the connection with the database
*/ */
@@ -86,16 +88,15 @@ export interface BaseDatabaseAdapter {
* Run any migration down functions that have been performed * Run any migration down functions that have been performed
*/ */
migrateDown: () => Promise<void> migrateDown: () => Promise<void>
/** /**
* Drop the current database and run all migrate up functions * Drop the current database and run all migrate up functions
*/ */
migrateFresh: (args: { forceAcceptWarning?: boolean }) => Promise<void> migrateFresh: (args: { forceAcceptWarning?: boolean }) => Promise<void>
/** /**
* Run all migration down functions before running up * Run all migration down functions before running up
*/ */
migrateRefresh: () => Promise<void> migrateRefresh: () => Promise<void>
/** /**
* Run all migrate down functions * Run all migrate down functions
*/ */
@@ -108,6 +109,7 @@ export interface BaseDatabaseAdapter {
* Path to read and write migration files from * Path to read and write migration files from
*/ */
migrationDir: string migrationDir: string
/** /**
* The name of the database adapter * The name of the database adapter
*/ */
@@ -119,12 +121,12 @@ export interface BaseDatabaseAdapter {
* @example @payloadcms/db-postgres * @example @payloadcms/db-postgres
*/ */
packageName: string packageName: string
/** /**
* reference to the instance of payload * reference to the instance of payload
*/ */
payload: Payload payload: Payload
queryDrafts: QueryDrafts queryDrafts: QueryDrafts
/** /**
* Abort any changes since the start of the transaction. * Abort any changes since the start of the transaction.
*/ */
@@ -150,7 +152,6 @@ export interface BaseDatabaseAdapter {
updateOne: UpdateOne updateOne: UpdateOne
updateVersion: UpdateVersion updateVersion: UpdateVersion
upsert: Upsert upsert: Upsert
} }
@@ -607,6 +608,7 @@ export type PaginatedDocs<T = any> = {
} }
export type DatabaseAdapterResult<T = BaseDatabaseAdapter> = { export type DatabaseAdapterResult<T = BaseDatabaseAdapter> = {
allowIDOnCreate?: boolean
defaultIDType: 'number' | 'text' defaultIDType: 'number' | 'text'
init: (args: { payload: Payload }) => T init: (args: { payload: Payload }) => T
} }

View File

@@ -12,7 +12,7 @@ import { type Table } from 'drizzle-orm'
import * as drizzlePg from 'drizzle-orm/pg-core' import * as drizzlePg from 'drizzle-orm/pg-core'
import * as drizzleSqlite from 'drizzle-orm/sqlite-core' import * as drizzleSqlite from 'drizzle-orm/sqlite-core'
import fs from 'fs' import fs from 'fs'
import { Types } from 'mongoose' import mongoose, { Types } from 'mongoose'
import path from 'path' import path from 'path'
import { import {
commitTransaction, commitTransaction,
@@ -306,6 +306,81 @@ describe('database', () => {
}) })
}) })
describe('allow ID on create', () => {
beforeAll(() => {
payload.db.allowIDOnCreate = true
payload.config.db.allowIDOnCreate = true
})
afterAll(() => {
payload.db.allowIDOnCreate = false
payload.config.db.allowIDOnCreate = false
})
it('Local API - accepts ID on create', async () => {
let id: any = null
if (payload.db.name === 'mongoose') {
id = new mongoose.Types.ObjectId().toHexString()
} else if (payload.db.idType === 'uuid') {
id = randomUUID()
} else {
id = 9999
}
const post = await payload.create({ collection: 'posts', data: { id, title: 'created' } })
expect(post.id).toBe(id)
})
it('REST API - accepts ID on create', async () => {
let id: any = null
if (payload.db.name === 'mongoose') {
id = new mongoose.Types.ObjectId().toHexString()
} else if (payload.db.idType === 'uuid') {
id = randomUUID()
} else {
id = 99999
}
const response = await restClient.POST(`/posts`, {
body: JSON.stringify({
id,
title: 'created',
}),
})
const post = await response.json()
expect(post.doc.id).toBe(id)
})
it('GraphQL - accepts ID on create', async () => {
let id: any = null
if (payload.db.name === 'mongoose') {
id = new mongoose.Types.ObjectId().toHexString()
} else if (payload.db.idType === 'uuid') {
id = randomUUID()
} else {
id = 999999
}
const query = `mutation {
createPost(data: {title: "created", id: ${typeof id === 'string' ? `"${id}"` : id}}) {
id
title
}
}`
const res = await restClient
.GRAPHQL_POST({ body: JSON.stringify({ query }) })
.then((res) => res.json())
const doc = res.data.createPost
expect(doc).toMatchObject({ title: 'created', id })
expect(doc.id).toBe(id)
})
})
describe('Compound Indexes', () => { describe('Compound Indexes', () => {
beforeEach(async () => { beforeEach(async () => {
await payload.delete({ collection: 'compound-indexes', where: {} }) await payload.delete({ collection: 'compound-indexes', where: {} })