Skip to content

Commit f442d22

Browse files
authored
feat(db-*): allow to thread id to create operation data without custom IDs (#11709)
Fixes #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"}}) ```
1 parent 95821c6 commit f442d22

File tree

17 files changed

+173
-18
lines changed

17 files changed

+173
-18
lines changed

docs/database/mongodb.mdx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ export default buildConfig({
4040
| `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. |
4141
| `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/). |
4242
| `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. |
43+
| `allowIDOnCreate` | Set to `true` to use the `id` passed in data on the create API operations without using a custom ID field. |
4344

4445
## Access to Mongoose models
4546

docs/database/postgres.mdx

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

8384
## Access to Drizzle
8485

docs/database/sqlite.mdx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ export default buildConfig({
4949
| `afterSchemaInit` | Drizzle schema hook. Runs after the schema is built. [More Details](#afterschemainit) |
5050
| `generateSchemaOutputFile` | Override generated schema from `payload generate:db-schema` file path. Defaults to `{CWD}/src/payload-generated.schema.ts` |
5151
| `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 |
52+
| `allowIDOnCreate` | Set to `true` to use the `id` passed in data on the create API operations without using a custom ID field. |
5253

5354
## Access to Drizzle
5455

packages/db-mongodb/src/create.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
import type { CreateOptions } from 'mongoose'
21
import type { Create } from 'payload'
32

3+
import { type CreateOptions, Types } from 'mongoose'
4+
45
import type { MongooseAdapter } from './index.js'
56

67
import { getCollection } from './utilities/getEntity.js'
@@ -29,6 +30,15 @@ export const create: Create = async function create(
2930

3031
if (customIDType) {
3132
data._id = data.id
33+
} else if (this.allowIDOnCreate && data.id) {
34+
try {
35+
data._id = new Types.ObjectId(data.id as string)
36+
} catch (error) {
37+
this.payload.logger.error(
38+
`It appears you passed ID to create operation data but it cannot be sanitized to ObjectID, value - ${JSON.stringify(data.id)}`,
39+
)
40+
throw error
41+
}
3242
}
3343

3444
try {

packages/db-mongodb/src/index.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,20 @@ export interface Args {
7070
* @default false
7171
*/
7272
allowAdditionalKeys?: boolean
73+
/**
74+
* Enable this flag if you want to thread your own ID to create operation data, for example:
75+
* ```ts
76+
* import { Types } from 'mongoose'
77+
*
78+
* const id = new Types.ObjectId().toHexString()
79+
* const doc = await payload.create({ collection: 'posts', data: {id, title: "my title"}})
80+
* assertEq(doc.id, id)
81+
* ```
82+
*/
83+
allowIDOnCreate?: boolean
7384
/** Set to false to disable auto-pluralization of collection names, Defaults to true */
7485
autoPluralization?: boolean
86+
7587
/**
7688
* If enabled, collation allows for language-specific rules for string comparison.
7789
* This configuration can include the following options:
@@ -98,7 +110,6 @@ export interface Args {
98110
collation?: Omit<CollationOptions, 'locale'>
99111

100112
collectionsSchemaOptions?: Partial<Record<CollectionSlug, SchemaOptions>>
101-
102113
/** Extra configuration options */
103114
connectOptions?: {
104115
/**
@@ -183,6 +194,7 @@ declare module 'payload' {
183194

184195
export function mongooseAdapter({
185196
allowAdditionalKeys = false,
197+
allowIDOnCreate = false,
186198
autoPluralization = true,
187199
collectionsSchemaOptions = {},
188200
connectOptions,
@@ -220,6 +232,7 @@ export function mongooseAdapter({
220232
versions: {},
221233
// DatabaseAdapter
222234
allowAdditionalKeys,
235+
allowIDOnCreate,
223236
beginTransaction: transactionOptions === false ? defaultBeginTransaction() : beginTransaction,
224237
collectionsSchemaOptions,
225238
commitTransaction,
@@ -259,6 +272,7 @@ export function mongooseAdapter({
259272
}
260273

261274
return {
275+
allowIDOnCreate,
262276
defaultIDType: 'text',
263277
init: adapter,
264278
}

packages/db-postgres/src/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ const filename = fileURLToPath(import.meta.url)
6464
export function postgresAdapter(args: Args): DatabaseAdapterObj<PostgresAdapter> {
6565
const postgresIDType = args.idType || 'serial'
6666
const payloadIDType = postgresIDType === 'serial' ? 'number' : 'text'
67+
const allowIDOnCreate = args.allowIDOnCreate ?? false
6768

6869
function adapter({ payload }: { payload: Payload }) {
6970
const migrationDir = findMigrationDir(args.migrationDir)
@@ -94,6 +95,7 @@ export function postgresAdapter(args: Args): DatabaseAdapterObj<PostgresAdapter>
9495
return createDatabaseAdapter<PostgresAdapter>({
9596
name: 'postgres',
9697
afterSchemaInit: args.afterSchemaInit ?? [],
98+
allowIDOnCreate,
9799
beforeSchemaInit: args.beforeSchemaInit ?? [],
98100
createDatabase,
99101
createExtensions,
@@ -204,6 +206,7 @@ export function postgresAdapter(args: Args): DatabaseAdapterObj<PostgresAdapter>
204206
}
205207

206208
return {
209+
allowIDOnCreate,
207210
defaultIDType: payloadIDType,
208211
init: adapter,
209212
}

packages/db-postgres/src/types.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,14 @@ export type Args = {
1919
* Examples may include: composite indices, generated columns, vectors
2020
*/
2121
afterSchemaInit?: PostgresSchemaHook[]
22+
/**
23+
* Enable this flag if you want to thread your own ID to create operation data, for example:
24+
* ```ts
25+
* // doc created with id 1
26+
* const doc = await payload.create({ collection: 'posts', data: {id: 1, title: "my title"}})
27+
* ```
28+
*/
29+
allowIDOnCreate?: boolean
2230
/**
2331
* Transform the schema before it's built.
2432
* You can use it to preserve an existing database schema and if there are any collissions Payload will override them.

packages/db-sqlite/src/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ const filename = fileURLToPath(import.meta.url)
6666
export function sqliteAdapter(args: Args): DatabaseAdapterObj<SQLiteAdapter> {
6767
const sqliteIDType = args.idType || 'number'
6868
const payloadIDType = sqliteIDType === 'uuid' ? 'text' : 'number'
69+
const allowIDOnCreate = args.allowIDOnCreate ?? false
6970

7071
function adapter({ payload }: { payload: Payload }) {
7172
const migrationDir = findMigrationDir(args.migrationDir)
@@ -88,6 +89,7 @@ export function sqliteAdapter(args: Args): DatabaseAdapterObj<SQLiteAdapter> {
8889
return createDatabaseAdapter<SQLiteAdapter>({
8990
name: 'sqlite',
9091
afterSchemaInit: args.afterSchemaInit ?? [],
92+
allowIDOnCreate,
9193
autoIncrement: args.autoIncrement ?? false,
9294
beforeSchemaInit: args.beforeSchemaInit ?? [],
9395
client: undefined,
@@ -186,6 +188,7 @@ export function sqliteAdapter(args: Args): DatabaseAdapterObj<SQLiteAdapter> {
186188
}
187189

188190
return {
191+
allowIDOnCreate,
189192
defaultIDType: payloadIDType,
190193
init: adapter,
191194
}

packages/db-sqlite/src/types.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,14 @@ export type Args = {
3131
* Examples may include: composite indices, generated columns, vectors
3232
*/
3333
afterSchemaInit?: SQLiteSchemaHook[]
34+
/**
35+
* Enable this flag if you want to thread your own ID to create operation data, for example:
36+
* ```ts
37+
* // doc created with id 1
38+
* const doc = await payload.create({ collection: 'posts', data: {id: 1, title: "my title"}})
39+
* ```
40+
*/
41+
allowIDOnCreate?: boolean
3442
/**
3543
* Enable [AUTOINCREMENT](https://www.sqlite.org/autoinc.html) for Primary Keys.
3644
* This ensures that the same ID cannot be reused from previously deleted rows.

packages/db-vercel-postgres/src/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ const filename = fileURLToPath(import.meta.url)
6464
export function vercelPostgresAdapter(args: Args = {}): DatabaseAdapterObj<VercelPostgresAdapter> {
6565
const postgresIDType = args.idType || 'serial'
6666
const payloadIDType = postgresIDType === 'serial' ? 'number' : 'text'
67+
const allowIDOnCreate = args.allowIDOnCreate ?? false
6768

6869
function adapter({ payload }: { payload: Payload }) {
6970
const migrationDir = findMigrationDir(args.migrationDir)
@@ -90,6 +91,7 @@ export function vercelPostgresAdapter(args: Args = {}): DatabaseAdapterObj<Verce
9091
return createDatabaseAdapter<VercelPostgresAdapter>({
9192
name: 'postgres',
9293
afterSchemaInit: args.afterSchemaInit ?? [],
94+
allowIDOnCreate,
9395
beforeSchemaInit: args.beforeSchemaInit ?? [],
9496
createDatabase,
9597
createExtensions,
@@ -195,6 +197,7 @@ export function vercelPostgresAdapter(args: Args = {}): DatabaseAdapterObj<Verce
195197
}
196198

197199
return {
200+
allowIDOnCreate,
198201
defaultIDType: payloadIDType,
199202
init: adapter,
200203
}

0 commit comments

Comments
 (0)