Files
payloadcms/packages/db-vercel-postgres/src/index.ts
Sasha a20b43624b feat: add findDistinct operation (#13102)
Adds a new operation findDistinct that can give you distinct values of a
field for a given collection
Example:
Assume you have a collection posts with multiple documents, and some of
them share the same title:
```js
// Example dataset (some titles appear multiple times)
[
  { title: 'title-1' },
  { title: 'title-2' },
  { title: 'title-1' },
  { title: 'title-3' },
  { title: 'title-2' },
  { title: 'title-4' },
  { title: 'title-5' },
  { title: 'title-6' },
  { title: 'title-7' },
  { title: 'title-8' },
  { title: 'title-9' },
]
```
You can now retrieve all unique title values using findDistinct:
```js
const result = await payload.findDistinct({
  collection: 'posts',
  field: 'title',
})

console.log(result.values)
// Output:
// [
//   'title-1',
//   'title-2',
//   'title-3',
//   'title-4',
//   'title-5',
//   'title-6',
//   'title-7',
//   'title-8',
//   'title-9'
// ]
```
You can also limit the number of distinct results:
```js
const limitedResult = await payload.findDistinct({
  collection: 'posts',
  field: 'title',
  sortOrder: 'desc',
  limit: 3,
})

console.log(limitedResult.values)
// Output:
// [
//   'title-1',
//   'title-2',
//   'title-3'
// ]
```

You can also pass a `where` query to filter the documents.
2025-07-16 17:18:14 -04:00

231 lines
6.2 KiB
TypeScript

import type { PgTableFn } from 'drizzle-orm/pg-core'
import type { DatabaseAdapterObj, Payload } from 'payload'
import {
beginTransaction,
buildCreateMigration,
commitTransaction,
count,
countGlobalVersions,
countVersions,
create,
createGlobal,
createGlobalVersion,
createSchemaGenerator,
createVersion,
deleteMany,
deleteOne,
deleteVersions,
destroy,
find,
findDistinct,
findGlobal,
findGlobalVersions,
findMigrationDir,
findOne,
findVersions,
migrate,
migrateDown,
migrateFresh,
migrateRefresh,
migrateReset,
migrateStatus,
operatorMap,
queryDrafts,
rollbackTransaction,
updateGlobal,
updateGlobalVersion,
updateJobs,
updateMany,
updateOne,
updateVersion,
upsert,
} from '@payloadcms/drizzle'
import {
columnToCodeConverter,
countDistinct,
createDatabase,
createExtensions,
createJSONQuery,
defaultDrizzleSnapshot,
deleteWhere,
dropDatabase,
execute,
init,
insert,
requireDrizzleKit,
} from '@payloadcms/drizzle/postgres'
import { pgEnum, pgSchema, pgTable } from 'drizzle-orm/pg-core'
import { createDatabaseAdapter, defaultBeginTransaction } from 'payload'
import { fileURLToPath } from 'url'
import type { Args, VercelPostgresAdapter } from './types.js'
import { connect } from './connect.js'
const filename = fileURLToPath(import.meta.url)
export function vercelPostgresAdapter(args: Args = {}): DatabaseAdapterObj<VercelPostgresAdapter> {
const postgresIDType = args.idType || 'serial'
const payloadIDType = postgresIDType === 'serial' ? 'number' : 'text'
const allowIDOnCreate = args.allowIDOnCreate ?? false
function adapter({ payload }: { payload: Payload }) {
const migrationDir = findMigrationDir(args.migrationDir)
let resolveInitializing
let rejectInitializing
let adapterSchema: VercelPostgresAdapter['pgSchema']
const initializing = new Promise<void>((res, rej) => {
resolveInitializing = res
rejectInitializing = rej
})
if (args.schemaName) {
adapterSchema = pgSchema(args.schemaName)
} else {
adapterSchema = { enum: pgEnum, table: pgTable as unknown as PgTableFn<string> }
}
const extensions = (args.extensions ?? []).reduce<Record<string, boolean>>((acc, name) => {
acc[name] = true
return acc
}, {})
return createDatabaseAdapter<VercelPostgresAdapter>({
name: 'postgres',
afterSchemaInit: args.afterSchemaInit ?? [],
allowIDOnCreate,
beforeSchemaInit: args.beforeSchemaInit ?? [],
blocksAsJSON: args.blocksAsJSON ?? false,
createDatabase,
createExtensions,
defaultDrizzleSnapshot,
disableCreateDatabase: args.disableCreateDatabase ?? false,
// @ts-expect-error - vestiges of when tsconfig was not strict. Feel free to improve
drizzle: undefined,
enums: {},
extensions,
features: {
json: true,
},
fieldConstraints: {},
forceUseVercelPostgres: args.forceUseVercelPostgres ?? false,
generateSchema: createSchemaGenerator({
columnToCodeConverter,
corePackageSuffix: 'pg-core',
defaultOutputFile: args.generateSchemaOutputFile,
enumImport: 'pgEnum',
schemaImport: 'pgSchema',
tableImport: 'pgTable',
}),
idType: postgresIDType,
indexes: new Set<string>(),
initializing,
localesSuffix: args.localesSuffix || '_locales',
logger: args.logger,
operators: operatorMap,
pgSchema: adapterSchema,
pool: undefined,
poolOptions: args.pool,
prodMigrations: args.prodMigrations,
// @ts-expect-error - vestiges of when tsconfig was not strict. Feel free to improve
push: args.push,
rawRelations: {},
rawTables: {},
relations: {},
relationshipsSuffix: args.relationshipsSuffix || '_rels',
schema: {},
schemaName: args.schemaName,
sessions: {},
tableNameMap: new Map<string, string>(),
tables: {},
tablesFilter: args.tablesFilter,
transactionOptions: args.transactionOptions || undefined,
updateJobs,
versionsSuffix: args.versionsSuffix || '_v',
// DatabaseAdapter
beginTransaction:
args.transactionOptions === false ? defaultBeginTransaction() : beginTransaction,
commitTransaction,
connect,
count,
countDistinct,
countGlobalVersions,
countVersions,
create,
createGlobal,
createGlobalVersion,
createJSONQuery,
createMigration: buildCreateMigration({
executeMethod: 'execute',
filename,
sanitizeStatements({ sqlExecute, statements }) {
return `${sqlExecute}\n ${statements.join('\n')}\`)`
},
}),
createVersion,
defaultIDType: payloadIDType,
deleteMany,
deleteOne,
deleteVersions,
deleteWhere,
destroy,
dropDatabase,
execute,
find,
findDistinct,
findGlobal,
findGlobalVersions,
readReplicaOptions: args.readReplicas,
// @ts-expect-error - vestiges of when tsconfig was not strict. Feel free to improve
findOne,
findVersions,
init,
insert,
migrate,
migrateDown,
migrateFresh,
migrateRefresh,
migrateReset,
migrateStatus,
migrationDir,
packageName: '@payloadcms/db-vercel-postgres',
payload,
queryDrafts,
// @ts-expect-error - vestiges of when tsconfig was not strict. Feel free to improve
rejectInitializing,
requireDrizzleKit,
// @ts-expect-error - vestiges of when tsconfig was not strict. Feel free to improve
resolveInitializing,
rollbackTransaction,
updateGlobal,
updateGlobalVersion,
updateMany,
updateOne,
updateVersion,
upsert,
})
}
return {
name: 'postgres',
allowIDOnCreate,
defaultIDType: payloadIDType,
init: adapter,
}
}
/**
* @todo deprecate /types subpath export in 4.0
*/
export type {
Args as VercelPostgresAdapterArgs,
GeneratedDatabaseSchema,
VercelPostgresAdapter,
} from './types.js'
export type { MigrateDownArgs, MigrateUpArgs } from '@payloadcms/drizzle/postgres'
export { geometryColumn } from '@payloadcms/drizzle/postgres'
export { sql } from 'drizzle-orm'