chore: move db-example to examples (#6532)

- Moved to examples
- Removed unnecessary dependencies
- Improved the readme with instructions for writing the db adapter
This commit is contained in:
Dan Ribbens
2024-05-28 10:28:18 -04:00
committed by GitHub
parent eeddeceda9
commit f07783a279
34 changed files with 11 additions and 23 deletions

View File

@@ -0,0 +1,10 @@
.tmp
**/.git
**/.hg
**/.pnp.*
**/.svn
**/.yarn/**
**/build
**/dist/**
**/node_modules
**/temp

View File

@@ -0,0 +1,37 @@
/** @type {import('prettier').Config} */
module.exports = {
extends: ['@payloadcms'],
overrides: [
{
extends: ['plugin:@typescript-eslint/disable-type-checked'],
files: ['*.js', '*.cjs', '*.json', '*.md', '*.yml', '*.yaml'],
},
{
files: ['package.json', 'tsconfig.json'],
rules: {
'perfectionist/sort-array-includes': 'off',
'perfectionist/sort-astro-attributes': 'off',
'perfectionist/sort-classes': 'off',
'perfectionist/sort-enums': 'off',
'perfectionist/sort-exports': 'off',
'perfectionist/sort-imports': 'off',
'perfectionist/sort-interfaces': 'off',
'perfectionist/sort-jsx-props': 'off',
'perfectionist/sort-keys': 'off',
'perfectionist/sort-maps': 'off',
'perfectionist/sort-named-exports': 'off',
'perfectionist/sort-named-imports': 'off',
'perfectionist/sort-object-types': 'off',
'perfectionist/sort-objects': 'off',
'perfectionist/sort-svelte-attributes': 'off',
'perfectionist/sort-union-types': 'off',
'perfectionist/sort-vue-attributes': 'off',
},
},
],
parserOptions: {
project: ['./tsconfig.json'],
tsconfigRootDir: __dirname,
},
root: true,
}

1
examples/db-example/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/migrations

View File

@@ -0,0 +1,10 @@
.tmp
**/.git
**/.hg
**/.pnp.*
**/.svn
**/.yarn/**
**/build
**/dist/**
**/node_modules
**/temp

View File

@@ -0,0 +1,15 @@
{
"$schema": "https://json.schemastore.org/swcrc",
"sourceMaps": "inline",
"jsc": {
"target": "esnext",
"parser": {
"syntax": "typescript",
"tsx": true,
"dts": true
}
},
"module": {
"type": "commonjs"
}
}

View File

@@ -0,0 +1,32 @@
# Example Database Adapter for Payload
- [Main Repository](https://github.com/payloadcms/payload)
- [Payload Docs](https://payloadcms.com/docs)
To build a fully working database adapter for Payload you must implement the database adapter interface. There is a mix
of required and not required methods depending on the areas you need to support. Payload will call the adapter's `init`
function followed by the `connect` method if it exists. The adapter must create any schema necessary on the target
database in the init function. The adapter can be extended as needed to keep track of models for collections and other
artifacts necessary to perform all the needed operations.
## Installation
```bash
npm install @payloadcms/db-example
```
## Usage
```ts
import { buildConfig } from 'payload/config'
import { exampleAdapter } from '@payloadcms/db-example'
export default buildConfig({
db: exampleAdapter({
url: process.env.DATABASE_URI,
}),
// ...rest of config
})
```
More detailed usage can be found in the [Payload Docs](https://payloadcms.com/docs/configuration/overview).

View File

@@ -0,0 +1,40 @@
{
"name": "@payloadcms/db-example",
"private": true,
"version": "0.0.1",
"description": "A sample implementation of a Payload database adapter",
"repository": {
"type": "git",
"url": "https://github.com/payloadcms/payload.git",
"directory": "examples/db-example"
},
"license": "MIT",
"homepage": "https://payloadcms.com",
"author": {
"email": "info@payloadcms.com",
"name": "Payload",
"url": "https://payloadcms.com"
},
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"scripts": {
"build": "pnpm build:swc && pnpm build:types",
"build:swc": "swc ./src -d ./dist --config-file .swcrc",
"build:types": "tsc --emitDeclarationOnly --outDir dist",
"clean": "rimraf {dist,*.tsbuildinfo}",
"prepublishOnly": "pnpm clean && pnpm build"
},
"dependencies": {
},
"devDependencies": {
"@payloadcms/eslint-config": "^1.1.1",
"payload": "^2.18.3",
"rimraf": "^4.1.2"
},
"peerDependencies": {
"payload": "^2.0.0"
},
"files": [
"dist"
]
}

View File

@@ -0,0 +1,26 @@
import type { Connect } from 'payload/database'
import type { ExampleAdapter } from '.'
/**
* Implement the connect feature here. This will connect to the underlying resource and set the this.connection property.
*
* Optional - this method is not required
*
* @param {ExampleAdapter} this - The ExampleAdapter instance.
* @param {Payload} payload
* @returns {Promise<void>} A promise that resolves when the connection is established.
*
* @example
* ```ts
* this.connection = await myUnderlyingStore.connect(this.url)
* ```
*/
export const connect: Connect = async function connect(this: ExampleAdapter, payload) {
try {
// this.connection = await myUnderlyingStore.connect(this.url)
} catch (err) {
this.payload.logger.error(`Error: cannot connect to DB. Details: ${err.message}`, err)
process.exit(1)
}
}

View File

@@ -0,0 +1,26 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import type { Count } from 'payload/database'
import type { PayloadRequest, Where } from 'payload/types'
import type { ExampleAdapter } from '.'
/**
* Counts the total number of documents that match the query in the specified collection.
*
* @param {ExampleAdapter} this - The ExampleAdapter instance.
* @param {string} collection - The name of the collection to reference for counting documents.
* @param {string} locale - The locale being used - can be one locale or "all" (locale="all").
* @param {PayloadRequest} req - The Express request object containing the currently authenticated user.
* @param {Where} where - The specific query used to find the documents for counting.
* @returns {Promise<{ totalDocs: number }>} A promise resolving to an object containing the total number of documents.
*
* Implement the count function here for the specified collection and return the total number of documents that match the query.
*/
export const count: Count = async function count(
this: ExampleAdapter,
{ collection, locale, req = {} as PayloadRequest, where },
): Promise<{ totalDocs: number }> {
return {
totalDocs: 0,
}
}

View File

@@ -0,0 +1,51 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import type { Create } from 'payload/database'
import type { Document, PayloadRequest } from 'payload/types'
import type { ExampleAdapter } from '.'
import handleError from './errors/handleError'
/**
* Creates a new document in the specified collection.
*
* @param {ExampleAdapter} this - The ExampleAdapter instance.
* @param {string} collection - The name of the collection to reference for creating documents.
* @param {object} data - The full data passed to create (data will have all locales and depth 0).
* @param {boolean} draft - Determine whether or not to create as a draft or not.
* @param {string} locale - The locale being used - can be one locale or "all" (locale="all").
* @param {PayloadRequest} req - The Express request object containing the currently authenticated user.
* @returns {Promise<Document>} A promise resolving to the created document.
*/
export const create: Create = async function create(
this: ExampleAdapter,
{ collection, data, draft, locale, req = {} as PayloadRequest },
) {
let doc
try {
/**
* Here you would send your data to where ever it needs to go
*
* Implement the logic to create the document in your database.
*
* @example
* ```ts
* doc = await adapterSpecificModel.create(data, options)
* ```
*/
} catch (error) {
handleError(error, req)
}
/**
* This should be the shape of the data that gets returned in Payload when you do:
*
* ?depth=0&locale=all&fallbackLocale=null
*
* The result of the outgoing data is always going to be the same shape that Payload expects
*
*/
const result: Document = doc
return result
}

View File

@@ -0,0 +1,40 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import type { CreateGlobal } from 'payload/database'
import type { PayloadRequest } from 'payload/types'
import type { ExampleAdapter } from '.'
/**
* Creates a global document in the database.
*
* @param {ExampleAdapter} this - The ExampleAdapter instance.
* @param {string} slug - The specified slug of the global.
* @param {object} data - The full data passed to create (data will have all locales and depth 0).
* @param {PayloadRequest} req - The Express request object containing the currently authenticated user.
* @returns {Promise<T>} A promise that resolves with the created global document.
*/
export const createGlobal: CreateGlobal = async function createGlobal(
this: ExampleAdapter,
{ slug, data, req = {} as PayloadRequest },
) {
let result
/**
* Implement the logic to create the global document in your database.
*
* @example
* ```ts
* result = await adapterSpecificModel.create(global, options)
* ```
*/
/**
* This should be the shape of the data that gets returned in Payload when you do:
*
* ?depth=0&locale=all&fallbackLocale=null
*
* The result of the outgoing data is always going to be the same shape that Payload expects
*
*/
return result
}

View File

@@ -0,0 +1,53 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import type { CreateGlobalVersion } from 'payload/database'
import type { PayloadRequest } from 'payload/types'
import type { Document } from 'payload/types'
import type { ExampleAdapter } from '.'
/**
* Creates a global version document in the database.
*
* @param {ExampleAdapter} this - The ExampleAdapter instance.
* @param {boolean} autosave - Indicates if autosave is enabled.
* @param {Date} createdAt - Created-At date of the document.
* @param {string} globalSlug - The global slug of the document.
* @param {string} parent - ID of the parent document for which the version should be created for.
* @param {PayloadRequest} req - The Express request object containing the currently authenticated user.
* @param {Date} updatedAt - Updated-At date of the document.
* @param {object} versionData - Full version data passed to create the global version.
* @returns {Promise<TypeWithVersion<T>>} A promise that resolves with the created global version document.
*/
export const createGlobalVersion: CreateGlobalVersion = async function createGlobalVersion(
this: ExampleAdapter,
{ autosave, createdAt, globalSlug, parent, req = {} as PayloadRequest, updatedAt, versionData },
) {
let doc
/**
* Implement the logic to create the global version document in your database.
*
* @example
* ```ts
* doc = await adapterSpecificVersionModel.create({
* autosave,
* createdAt,
* latest: true,
* parent,
* updatedAt,
* version: versionData,
* }, options, req)
* ```
*/
/**
* This should be the shape of the data that gets returned in Payload when you do:
*
* ?depth=0&locale=all&fallbackLocale=null
*
* The result of the outgoing data is always going to be the same shape that Payload expects
*
*/
const result: Document = doc
return result
}

View File

@@ -0,0 +1,61 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import type { CreateVersion, TypeWithVersion } from 'payload/database'
import type { PayloadRequest } from 'payload/types'
import type { Document } from 'payload/types'
import type { ExampleAdapter } from '.'
/**
* Creates a version document in the database.
*
* @param {ExampleAdapter} this - The ExampleAdapter instance.
* @param {boolean} autosave - Indicates if autosave is enabled.
* @param {string} collectionSlug - The collection slug of the document.
* @param {Date} createdAt - Created-At date of the document.
* @param {string} parent - ID of the parent document for which the version should be created for.
* @param {PayloadRequest} req - The Express request object containing the currently authenticated user.
* @param {Date} updatedAt - Updated-At date of the document.
* @param {object} versionData - Full version data passed to create the version.
* @returns {Promise<TypeWithVersion<T>>} A promise that resolves with the created version document.
*
*/
export const createVersion: CreateVersion = async function createVersion(
this: ExampleAdapter,
{
autosave,
collectionSlug,
createdAt,
parent,
req = {} as PayloadRequest,
updatedAt,
versionData,
},
) {
let doc
/**
* Implement the logic to create the version document in your database.
*
* @example
* ```ts
* doc = await adapterSpecificVersionModel.create({
* autosave,
* createdAt,
* latest: true,
* parent,
* updatedAt,
* version: versionData,
* }, options, req)
* ```
*/
/**
* This should be the shape of the data that gets returned in Payload when you do:
*
* ?depth=0&locale=all&fallbackLocale=null
*
* The result of the outgoing data is always going to be the same shape that Payload expects
*
*/
const result: Document = doc
return result
}

View File

@@ -0,0 +1,28 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import type { DeleteMany } from 'payload/database'
import type { PayloadRequest, Where } from 'payload/types'
import type { ExampleAdapter } from '.'
/**
* Deletes multiple documents from the specified collection in the database.
*
* @param {ExampleAdapter} this - The ExampleAdapter instance.
* @param {string} collection - The name of the collection to reference for deleting documents.
* @param {PayloadRequest} req - The Express request object containing the currently authenticated user.
* @param {Where} where - The specific query used to find the documents for deleting.
* @returns {Promise<void>} A promise that resolves when the documents are deleted.
*/
export const deleteMany: DeleteMany = async function deleteMany(
this: ExampleAdapter,
{ collection, req = {} as PayloadRequest, where },
) {
/**
* Implement the logic to delete many documents from your database.
*
* @example
* ```ts
* await adapterSpecificModel.deleteMany(query, options)
* ```
*/
}

View File

@@ -0,0 +1,43 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import type { DeleteOne } from 'payload/database'
import type { PayloadRequest, Where } from 'payload/types'
import type { Document } from 'payload/types'
import type { ExampleAdapter } from '.'
/**
* Deletes a single document from the specified collection in the database.
*
* @param {ExampleAdapter} this - The ExampleAdapter instance.
* @param {string} collection - The name of the collection to reference for deleting a document.
* @param {PayloadRequest} req - The Express request object containing the currently authenticated user.
* @param {Where} where - The specific query used to find the document for deleting.
* @returns {Promise<Document>} A promise that resolves with the deleted document.
*/
export const deleteOne: DeleteOne = async function deleteOne(
this: ExampleAdapter,
{ collection, req = {} as PayloadRequest, where },
) {
let doc
/**
* Need to go delete your document through the API
*
* Implement the logic to delete the document from your database.
*
* @example
* ```ts
* doc = await adapterSpecificModel.delete(query, options)
* ```
*/
/**
* This should be the shape of the data that gets returned in Payload when you do:
*
* ?depth=0&locale=all&fallbackLocale=null
*
* The result of the outgoing data is always going to be the same shape that Payload expects
*
*/
const result: Document = doc
return result
}

View File

@@ -0,0 +1,29 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import type { DeleteVersions } from 'payload/database'
import type { PayloadRequest, Where } from 'payload/types'
import type { ExampleAdapter } from '.'
/**
* Deletes many version documents from your database.
*
* @param {ExampleAdapter} this - The ExampleAdapter instance.
* @param {string} collection - The name of the collection to reference for deleting versions.
* @param {string} locale - The locale being used - can be one locale or "all" (locale="all").
* @param {PayloadRequest} req - The Express request object containing the currently authenticated user.
* @param {Where} where - The specific query used to find the documents for deleting versions.
* @returns {Promise<void>} A promise that resolves with the created global document.
*/
export const deleteVersions: DeleteVersions = async function deleteVersions(
this: ExampleAdapter,
{ collection, locale, req = {} as PayloadRequest, where },
) {
/**
* Implement the logic to delete many version documents from your database.
*
* @example
* ```ts
* await adapterSpecificVersionsModel.deleteMany(query, options)
* ```
*/
}

View File

@@ -0,0 +1,33 @@
import type { Destroy } from 'payload/database'
import type { ExampleAdapter } from './index'
/**
* Closes the database connection and cleans up resources used by the adapter.
*
* This function is typically used to gracefully shutdown the database connections
* when the application is closing or when the adapter is no longer needed.
*
* Optional - this method is not required
*
* @param {ExampleAdapter} - The ExampleAdapter instance.
* @returns {Promise<void>}
*/
export const destroy: Destroy = async function destroy(this: ExampleAdapter) {
/**
* If using an in-memory database or a similar service, add the specific steps to drop the database and stop the server.
*
* @example
* ```ts
* if (this.inMemoryDatabase) {
* await this.connection.dropDatabase()
*
* await this.connection.close()
*
* await this.inMemoryDatabase.stop()
* } else {
* await this.connection.close()
* }
* ```
*/
}

View File

@@ -0,0 +1,18 @@
/**
* Handle uniqueness error
*
* If the error is from a unique or required field - return the expected format using validation error
*/
const handleError = (error, req) => {
// throw new ValidationError(
// [
// {
// field: field.name,
// message: req.t('error:valueMustBeUnique'),
// },
// ],
// req.t,
// )
}
export default handleError

View File

@@ -0,0 +1,45 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import type { Find, PaginatedDocs } from 'payload/database'
import type { PayloadRequest, Where } from 'payload/types'
import type { ExampleAdapter } from '.'
/**
* Queries for documents in the specified collection based on the provided criteria using the incoming where,
* sort, page query and then only return the correct documents in the format Payload expects.
*
* @param {ExampleAdapter} this - The ExampleAdapter instance.
* @param {string} collection - The name of the collection to query for documents.
* @param {number} limit - The maximum number of documents to return.
* @param {string} locale - The locale being used - can be one locale or "all" (locale="all").
* @param {number} page - The page number of the results to return.
* @param {boolean} pagination - Determines whether pagination is enabled.
* @param {PayloadRequest} req - The Express request object containing the currently authenticated user.
* @param {string} sort - The top-level field to sort the results by.
* @param {Where} where - The specific query used to filter documents.
* @returns {Promise<PaginatedDocs<T>>} A promise resolving to the paginated documents matching the query criteria.
*/
export const find: Find = async function find(
this: ExampleAdapter,
{ collection, limit, locale, page, pagination, req = {} as PayloadRequest, sort: sortArg, where },
) {
let result
/**
* Implement the logic to paginate the query results according to your database's methods.
*
* @example
* ```ts
* const result = await adapterSpecificModel.paginate(query, paginationOptions)
* ```
*/
/**
* This should be the shape of the data that gets returned in Payload when you do:
*
* ?depth=0&locale=all&fallbackLocale=null
*
* The result of the outgoing data is always going to be the same shape that Payload expects
*
*/
return result
}

View File

@@ -0,0 +1,44 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import type { FindGlobal } from 'payload/database'
import type { PayloadRequest, Where } from 'payload/types'
import type { ExampleAdapter } from '.'
/**
* Finds a global document based on the specified criteria using the incoming slug, locale, and
* where query, then returns it in the format expected by Payload.
*
* @param {ExampleAdapter} this - The ExampleAdapter instance.
* @param {string} slug - The specified slug of the global document.
* @param {string} locale - The locale being used - can be one locale or "all" (locale="all").
* @param {PayloadRequest} req - The Express request object containing the currently authenticated user.
* @param {Where} where - The specific query used to find the global document.
* @returns {Promise<T>} A promise resolving to the found global document or null if not found.
*/
export const findGlobal: FindGlobal = async function findGlobal(
this: ExampleAdapter,
{ slug, locale, req = {} as PayloadRequest, where },
) {
let doc
/**
* Implement the logic to find a global in your database.
*
* @example
* ```ts
* let doc = await adapterSpecificModel.findOne(query, {}, options)
* ```
*/
if (!doc) {
return null
}
/**
* This should be the shape of the data that gets returned in Payload when you do:
*
* ?depth=0&locale=all&fallbackLocale=null
*
*/
return doc
}

View File

@@ -0,0 +1,57 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import type { FindGlobalVersions, PaginatedDocs, TypeWithVersion } from 'payload/database'
import type { PayloadRequest, Where } from 'payload/types'
import type { ExampleAdapter } from '.'
/**
* Finds versions of a global document based on the specified criteria using the incoming global, limit, locale, page,
* pagination, req, skip, sort, and where parameters, and returns them in the format expected by Payload.
*
* @param {ExampleAdapter} this - The ExampleAdapter instance.
* @param {string} global - The name of the global document to reference for finding versions.
* @param {number} limit - The maximum number of versions to return.
* @param {string} locale - The locale being used - can be one locale or "all" (locale="all").
* @param {number} page - The page number of the results to return.
* @param {boolean} pagination - Determines whether pagination is enabled.
* @param {PayloadRequest} req - The Express request object containing the currently authenticated user.
* @param {boolean} skip - Middleware function that can bypass the limit if it returns true.
* @param {string} sort - The top-level field to sort the results by.
* @param {Where} where - The specific query used to filter global versions.
* @returns {Promise<PaginatedDocs<TypeWithVersion<T>>>} A promise resolving to the paginated versions matching the query criteria.
*/
export const findGlobalVersions: FindGlobalVersions = async function findGlobalVersions(
this: ExampleAdapter,
{
global,
limit,
locale,
page,
pagination,
req = {} as PayloadRequest,
skip,
sort: sortArg,
where,
},
) {
let result
/**
* Implement the logic to paginate the query results according to your database's methods.
*
* @example
* ```ts
* const result = await adapterSpecificModel.paginate(query, paginationOptions)
* ```
*/
/**
* This should be the shape of the data that gets returned in Payload when you do:
*
* ?depth=0&locale=all&fallbackLocale=null
*
* The result of the outgoing data is always going to be the same shape that Payload expects
*
*/
return result
}

View File

@@ -0,0 +1,47 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import type { FindOne } from 'payload/database'
import type { PayloadRequest, Where } from 'payload/types'
import type { Document } from 'payload/types'
import type { ExampleAdapter } from '.'
/**
* Finds a single document in the specified collection based on the provided criteria using
* the incoming locale and where query, and returns it in the format expected by Payload.
*
* @param {ExampleAdapter} this - The ExampleAdapter instance.
* @param {string} collection - The name of the collection to reference for finding the document.
* @param {string} locale - The locale being used - can be one locale or "all" (locale="all").
* @param {PayloadRequest} req - The Express request object containing the currently authenticated user.
* @param {Where} where - The specific query used to find the document.
* @returns {Promise<T>} A promise resolving to the found document or null if not found.
*/
export const findOne: FindOne = async function findOne(
this: ExampleAdapter,
{ collection, locale, req = {} as PayloadRequest, where },
) {
let doc
/**
* Implement the logic to find one document in your database.
*
* @example
* ```ts
* const doc = await adapterSpecificModel.findOne(query, {}, options)
* ```
*/
if (!doc) {
return null
}
/**
* This should be the shape of the data that gets returned in Payload when you do:
*
* ?depth=0&locale=all&fallbackLocale=null
*
* The result of the outgoing data is always going to be the same shape that Payload expects
*
*/
const result: Document = doc
return result
}

View File

@@ -0,0 +1,56 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import type { FindVersions, PaginatedDocs } from 'payload/database'
import type { PayloadRequest, Where } from 'payload/types'
import type { ExampleAdapter } from '.'
/**
* Queries for versions of documents in the specified collection based on the provided criteria using the incoming where,
* sort, page query and then only returns the correct document versions in the format Payload expects.
*
* @param {ExampleAdapter} this - The ExampleAdapter instance.
* @param {string} collection - The name of the collection to reference for finding versions.
* @param {number} limit - The maximum number of versions to return.
* @param {string} locale - The locale being used - can be one locale or "all" (locale="all").
* @param {number} page - The page number of the results to return.
* @param {boolean} pagination - Determines whether pagination is enabled.
* @param {PayloadRequest} req - The Express request object containing the currently authenticated user.
* @param {boolean} skip - Middleware function that can bypass the limit if it returns true.
* @param {string} sort - The top-level field to sort the results by.
* @param {Where} where - The specific query used to filter document versions.
* @returns {Promise<PaginatedDocs<TypeWithVersion<T>>>} A promise resolving to the paginated document versions matching the query criteria.
*/
export const findVersions: FindVersions = async function findVersions(
this: ExampleAdapter,
{
collection,
limit,
locale,
page,
pagination,
req = {} as PayloadRequest,
skip,
sort: sortArg,
where,
},
) {
let result
/**
* Implement the logic to paginate the query results according to your database's methods.
*
* @example
* ```ts
* const result = await adapterSpecificModel.paginate(query, paginationOptions)
* ```
*/
/**
* This should be the shape of the data that gets returned in Payload when you do:
*
* ?depth=0&locale=all&fallbackLocale=null
*
* The result of the outgoing data is always going to be the same shape that Payload expects
*/
return result
}

View File

@@ -0,0 +1,130 @@
import type { Payload } from 'payload'
import type { BaseDatabaseAdapter } from 'payload/database'
import { createDatabaseAdapter } from 'payload/database'
import { connect } from './connect'
import { count } from './count'
import { create } from './create'
import { createGlobal } from './createGlobal'
import { createGlobalVersion } from './createGlobalVersion'
import { createVersion } from './createVersion'
import { deleteMany } from './deleteMany'
import { deleteOne } from './deleteOne'
import { deleteVersions } from './deleteVersions'
import { destroy } from './destroy'
import { find } from './find'
import { findGlobal } from './findGlobal'
import { findGlobalVersions } from './findGlobalVersions'
import { findOne } from './findOne'
import { findVersions } from './findVersions'
import { init } from './init'
import { queryDrafts } from './queryDrafts'
import { beginTransaction } from './transactions/beginTransaction'
import { commitTransaction } from './transactions/commitTransaction'
import { rollbackTransaction } from './transactions/rollbackTransaction'
import { updateGlobal } from './updateGlobal'
import { updateGlobalVersion } from './updateGlobalVersion'
import { updateOne } from './updateOne'
import { updateVersion } from './updateVersion'
/**
* Configure any adapter-specific options here
*
* For example: connection options, transaction options, etc.
*/
export interface Args {
url: string
}
/**
* The exported adapter Type
*
* _Optionally_, expose any adapter-specific methods here. How much you expose here relies on your underlying implementation.
*/
export type ExampleAdapter = BaseDatabaseAdapter &
Args & {
/**
* This will allow access to the underlying model via `payload.db.collections.<slug>.find()
*
* This optional
*/
collections: {
[slug: string]: unknown
}
/**
* Access to underlying global model via `payload.db.globals`
*/
globals: {
[slug: string]: unknown
}
}
type ExampleAdapterResult = (args: { payload: Payload }) => ExampleAdapter
/**
* This declaration injects the proper types for the DB Adapter into Payload when accessing the adapter in code
*
* Optional
*/
declare module 'payload' {
export interface DatabaseAdapter extends BaseDatabaseAdapter {
collections: {
[slug: string]: unknown
}
globals: {
[slug: string]: unknown
}
versions: {
[slug: string]: unknown
}
}
}
export function exampleAdapter({ url }: Args): ExampleAdapterResult {
function adapter({ payload }: { payload: Payload }) {
return createDatabaseAdapter<ExampleAdapter>({
name: 'example',
// Example adapter-specific
collections: {},
count,
globals: undefined,
url,
/**
* Configure DatabaseAdapter
*
* Many of these are optional and will fallback on some default functionality if not defined.
*/
beginTransaction,
commitTransaction,
connect,
create,
createGlobal,
createGlobalVersion,
createVersion,
defaultIDType: 'text',
deleteMany,
deleteOne,
deleteVersions,
destroy,
find,
findGlobal,
findGlobalVersions,
findOne,
findVersions,
init,
payload,
queryDrafts,
rollbackTransaction,
updateGlobal,
updateGlobalVersion,
updateOne,
updateVersion,
})
}
return adapter
}

View File

@@ -0,0 +1,40 @@
/* eslint-disable no-param-reassign */
import type { Init } from 'payload/database'
import type { ExampleAdapter } from '.'
/**
* Perform any initialization actions here.
* This will run immediately when the DB adapter is initialized and will take place before the connect method.
* If your implementation needs models created from Payload collections and globals, you would do this here.
* If your implementation needs to maintain a persistent connection, you should call this.connect here.
*
* Your DB adapter needs to be able to handle all the different Payload field types found in collections & globals:
*
* - Fields containing subfields:
* - 'array'
* - 'blocks'
* - 'collapsible'
* - 'group'
* - 'row'
* - 'tabs'
*
* - Other fields:
* - 'checkbox'
* - 'code'
* - 'date'
* - 'email'
* - 'json'
* - 'number'
* - 'point'
* - 'radio'
* - 'relationship'
* - 'richText'
* - 'select'
* - 'text'
* - 'textarea'
* - 'upload'
*
* @returns {Promise<void>}
*/
export const init: Init = async function init(this: ExampleAdapter) {}

View File

@@ -0,0 +1,46 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import type { PaginatedDocs, QueryDrafts } from 'payload/database'
import type { PayloadRequest, Where } from 'payload/types'
import type { ExampleAdapter } from '.'
/**
* Queries for drafts in the specified collection based on the provided criteria using
* the incoming where, sort, page query and then only returns the correct drafts in the format Payload expects.
*
* @param {ExampleAdapter} this - The ExampleAdapter instance.
* @param {string} collection - The name of the collection to reference for querying drafts.
* @param {number} limit - The maximum number of drafts to return.
* @param {string} locale - The locale being used - can be one locale or "all" (locale="all").
* @param {number} page - The page number of the results to return.
* @param {boolean} pagination - Determines whether pagination is enabled.
* @param {PayloadRequest} req - The Express request object containing the currently authenticated user.
* @param {string} sort - The top-level field to sort the results by.
* @param {Where} where - The specific query used to filter drafts.
* @returns {Promise<PaginatedDocs<T>>} A promise resolving to the paginated drafts matching the query criteria.
*/
export const queryDrafts: QueryDrafts = async function queryDrafts(
this: ExampleAdapter,
{ collection, limit, locale, page, pagination, req = {} as PayloadRequest, sort: sortArg, where },
) {
let result
/**
* Implement the logic to paginate the query results according to your database's methods.
*
* @example
* ```ts
* const result = await adapterSpecificModel.paginate(versionQuery, paginationOptions)
* ```
*/
/**
* This should be the shape of the data that gets returned in Payload when you do:
*
* ?depth=0&locale=all&fallbackLocale=null
*
* The result of the outgoing data is always going to be the same shape that Payload expects
*
*/
return result
}

View File

@@ -0,0 +1,24 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import type { TransactionOptions } from 'mongodb'
import type { BeginTransaction } from 'payload/database'
import type { ExampleAdapter } from '../index'
/**
* Begins a new transaction with the provided options.
*
* If you want to support database transactions, you would initialize them within this function.
* Alternatively, if transactions are not supported or not needed, this function can do nothing and return null.
*
* @param {ExampleAdapter} this - The ExampleAdapter instance.
* @param {TransactionOptions} options - The options for the transaction.
* @returns {Promise<null>} A promise resolving to null.
*
* This function is optional and can be implemented as needed for database adapters that support transactions.
*/
export const beginTransaction: BeginTransaction = async function beginTransaction(
this: ExampleAdapter,
options: TransactionOptions,
) {
return null
}

View File

@@ -0,0 +1,14 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import type { CommitTransaction } from 'payload/database'
/**
* Commits a transaction identified by its ID.
*
* Optional - this method is not required
*
* @param {string} id - The ID of the transaction to commit.
* @returns {Promise<void>}
*
* This function is optional and can be implemented as needed for database adapters that support transactions.
*/
export const commitTransaction: CommitTransaction = async function commitTransaction(id) {}

View File

@@ -0,0 +1,14 @@
import type { RollbackTransaction } from 'payload/database'
/**
* Rolls back a transaction identified by its ID.
*
* @param {string} id - The ID of the transaction to rollback.
* @returns {Promise<void>}
*
* This function is optional and can be implemented as needed for database adapters that support transactions.
*/
export const rollbackTransaction: RollbackTransaction = async function rollbackTransaction(
// eslint-disable-next-line @typescript-eslint/no-unused-vars
id = '',
) {}

View File

@@ -0,0 +1,40 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import type { UpdateGlobal } from 'payload/database'
import type { PayloadRequest } from 'payload/types'
import type { ExampleAdapter } from '.'
/**
* Updates a global document in the specified collection based on the provided criteria.
*
* @param {ExampleAdapter} this - The ExampleAdapter instance.
* @param {string} slug - The specified slug of the global.
* @param {object} data - The full data passed to create (data will have all locales and depth 0).
* @param {PayloadRequest} req - The Express request object containing the currently authenticated user.
* @returns {Promise<T>} A promise resolving to the updated global document.
*/
export const updateGlobal: UpdateGlobal = async function updateGlobal(
this: ExampleAdapter,
{ slug, data, req = {} as PayloadRequest },
) {
/**
* Implement the logic to find one and update the document in your database.
*
* @example
* ```ts
* result = await adapterSpecificModel.findOneAndUpdate({ globalType: slug }, data, options)
* ```
*/
let result
/**
* This should be the shape of the data that gets returned in Payload when you do:
*
* ?depth=0&locale=all&fallbackLocale=null
*
* The result of the outgoing data is always going to be the same shape that Payload expects
*
*/
return result
}

View File

@@ -0,0 +1,52 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import type { UpdateGlobalVersionArgs } from 'payload/database'
import type { PayloadRequest, TypeWithID, Where } from 'payload/types'
import type { ExampleAdapter } from '.'
/**
* Updates a global version document in the specified collection based on the provided criteria using
* the incoming ID, global, locale, and versionData, then returns the updated global version document in the format Payload expects.
*
* @param {ExampleAdapter} this - The ExampleAdapter instance.
* @param {string} id - The ID of the global version.
* @param {string} global - The name of the global to reference for updating a global's version.
* @param {string} locale - The locale being used - can be one locale or "all" (locale="all").
* @param {PayloadRequest} req - The Express request object containing the currently authenticated user.
* @param {object} versionData - Full version data passed to update the global version.
* @param {Where} where - The specific query for querying the global version documents in question to update.
* @returns {Promise<any>} A promise resolving to the updated global version document.
*/
export async function updateGlobalVersion<T extends TypeWithID>(
this: ExampleAdapter,
{
id,
global,
locale,
req = {} as PayloadRequest,
versionData,
where,
}: UpdateGlobalVersionArgs<T>,
) {
let doc
/**
* Implement the logic to find one and update the document in your database.
*
* @example
* ```ts
* const doc = await adapterSpecificModel.findOneAndUpdate(query, versionData, options)
* ```
*/
/**
* This should be the shape of the data that gets returned in Payload when you do:
*
* ?depth=0&locale=all&fallbackLocale=null
*
* The result of the outgoing data is always going to be the same shape that Payload expects
*
*/
const result = doc
return result
}

View File

@@ -0,0 +1,44 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import type { UpdateOne } from 'payload/database'
import type { PayloadRequest, Where } from 'payload/types'
import type { ExampleAdapter } from '.'
/**
* Updates a single document in the specified collection based on the provided criteria using
* the incoming ID, collection, locale, and data, then returns the updated document in the format Payload expects.
*
* @param {ExampleAdapter} this - The ExampleAdapter instance.
* @param {string} id - The ID of the collection document.
* @param {string} collection - The name of the collection to reference for updating one.
* @param {object} data - The full data passed to create (data will have all locales and depth 0).
* @param {string} locale - The locale being used - can be one locale or "all" (locale="all").
* @param {PayloadRequest} req - The Express request object containing the currently authenticated user.
* @param {Where} where - The specific query used to find the documents for updating.
* @returns {Promise<Document>} A promise resolving to the updated document.
*/
export const updateOne: UpdateOne = async function updateOne(
this: ExampleAdapter,
{ id, collection, data, locale, req = {} as PayloadRequest, where },
) {
let result
/**
* Implement the logic to update one document in your database.
*
* @example
* ```ts
* const result = await adapterSpecificModel.findOneAndUpdate(query, data, options)
* ```
*/
/**
* This should be the shape of the data that gets returned in Payload when you do:
*
* ?depth=0&locale=all&fallbackLocale=null
*
* The result of the outgoing data is always going to be the same shape that Payload expects
*
*/
return result
}

View File

@@ -0,0 +1,45 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import type { UpdateVersion } from 'payload/database'
import type { PayloadRequest, Where } from 'payload/types'
import type { ExampleAdapter } from '.'
/**
* Updates a version of a document in the specified collection based on the provided criteria using
* the incoming ID, collection, locale, and versionData, then returns the updated version in the format Payload expects.
*
* @param {ExampleAdapter} this - The ExampleAdapter instance.
* @param {string} id - The ID of the collection document.
* @param {string} collection - The name of the collection to reference for updating a document's version.
* @param {string} locale - The locale being used - can be one locale or "all" (locale="all").
* @param {PayloadRequest} req - The Express request object containing the currently authenticated user.
* @param {object} versionData - Full version data passed to create the version.
* @param {Where} where - The specific query used to find the documents for updating its versions.
* @returns {Promise<TypeWithVersion<T>>} A promise resolving to the updated version document.
*/
export const updateVersion: UpdateVersion = async function updateVersion(
this: ExampleAdapter,
{ id, collection, locale, req = {} as PayloadRequest, versionData, where },
) {
let doc
/**
* Implement the logic to update a document's version in your database.
*
* @example
* ```ts
* const doc = await adapterSpecificModel.findOneAndUpdate(query, versionData, options)
* ```
*/
/**
* This should be the shape of the data that gets returned in Payload when you do:
*
* ?depth=0&locale=all&fallbackLocale=null
*
* The result of the outgoing data is always going to be the same shape that Payload expects
*
*/
const result = doc
return result
}

View File

@@ -0,0 +1,24 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"composite": true, // Make sure typescript knows that this module depends on their references
"noEmit": false /* Do not emit outputs. */,
"emitDeclarationOnly": true,
"outDir": "./dist" /* Specify an output folder for all emitted files. */,
"rootDir": "./src" /* Specify the root folder within your source files. */
},
"exclude": [
"dist",
"build",
"tests",
"test",
"node_modules",
".eslintrc.js",
"src/**/*.spec.js",
"src/**/*.spec.jsx",
"src/**/*.spec.ts",
"src/**/*.spec.tsx"
],
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.d.ts", "src/**/*.json"],
"references": [{ "path": "../payload" }] // db-mongodb depends on payload
}