feat: mongoose-adapter: findOne, sort direction, id => where and cleanup (#2918)
* chore: add jsDocs for buildQuery * feat: where instead of id for updateOne and deleteOne * feat: find => findOne * sort order => sort direction * fix: typing of Global buildQuery * cleanup * fix: init payload's i18n for error message * fix: incorrect use of FindArgs in findByID * move deleteOne call to adapter * re-order * deleteVersions * versions stuff * more version stuff * moar version stuff * global stuff * global stuff * move combineQueries inside the findGlobal * global stuff * fix type * more global stuff * move docWithFilenameExists to adapter pattern * chore: remove unnecessary comments * perf: make everything lean, disable virtuals, ++performance * chore: remove unnecessary Model
This commit is contained in:
@@ -42,14 +42,11 @@ const getExecuteStaticAccess = (config: SanitizedCollectionConfig) => async (req
|
||||
});
|
||||
}
|
||||
|
||||
const { docs } = await req.payload.db.find({
|
||||
const doc = await req.payload.db.findOne({
|
||||
collection: config.slug,
|
||||
where: queryToBuild,
|
||||
limit: 1,
|
||||
});
|
||||
|
||||
const doc = docs[0];
|
||||
|
||||
if (!doc) {
|
||||
throw new Forbidden(req.t);
|
||||
}
|
||||
|
||||
@@ -68,13 +68,11 @@ async function forgotPassword(incomingArgs: Arguments): Promise<string | null> {
|
||||
resetPasswordExpiration?: Date,
|
||||
}
|
||||
|
||||
const { docs } = await payload.db.find<UserDoc>({
|
||||
let user = await payload.db.findOne<UserDoc>({
|
||||
collection: collectionConfig.slug,
|
||||
where: { email: { equals: (data.email as string).toLowerCase() } },
|
||||
limit: 1,
|
||||
});
|
||||
|
||||
let [user] = docs;
|
||||
|
||||
if (!user) return null;
|
||||
|
||||
|
||||
@@ -6,13 +6,11 @@ async function init(args: { req: PayloadRequest, collection: string }): Promise<
|
||||
collection: slug,
|
||||
} = args;
|
||||
|
||||
const { docs } = await payload.db.find({
|
||||
const doc = await payload.db.findOne({
|
||||
collection: slug,
|
||||
limit: 1,
|
||||
pagination: false,
|
||||
});
|
||||
|
||||
return docs.length === 1;
|
||||
return !!doc;
|
||||
}
|
||||
|
||||
export default init;
|
||||
|
||||
@@ -77,16 +77,11 @@ async function login<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
|
||||
const email = unsanitizedEmail ? (unsanitizedEmail as string).toLowerCase().trim() : null;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore Improper typing in library, additional args should be optional
|
||||
const { docs } = await payload.db.find<any>({
|
||||
let user = await payload.db.findOne<any>({
|
||||
collection: collectionConfig.slug,
|
||||
where: { email: { equals: email.toLowerCase() } },
|
||||
limit: 1,
|
||||
});
|
||||
|
||||
let [user] = docs;
|
||||
|
||||
if (!user || (args.collection.config.auth.verify && user._verified === false)) {
|
||||
throw new AuthenticationError(req.t);
|
||||
}
|
||||
|
||||
@@ -40,13 +40,11 @@ async function registerFirstUser<TSlug extends keyof GeneratedTypes['collections
|
||||
data,
|
||||
} = args;
|
||||
|
||||
const { docs } = await payload.db.find({
|
||||
const doc = await payload.db.findOne({
|
||||
collection: config.slug,
|
||||
limit: 1,
|
||||
pagination: false,
|
||||
});
|
||||
|
||||
if (docs.length === 1) throw new Forbidden(req.t);
|
||||
if (doc) throw new Forbidden(req.t);
|
||||
|
||||
// /////////////////////////////////////
|
||||
// Register first user
|
||||
|
||||
@@ -50,17 +50,14 @@ async function resetPassword(args: Arguments): Promise<Result> {
|
||||
// Reset Password
|
||||
// /////////////////////////////////////
|
||||
|
||||
const { docs } = await payload.db.find<any>({
|
||||
const user = await payload.db.findOne<any>({
|
||||
collection: collectionConfig.slug,
|
||||
limit: 1,
|
||||
where: {
|
||||
resetPasswordToken: { equals: data.token },
|
||||
resetPasswordExpiration: { greater_than: Date.now() },
|
||||
},
|
||||
});
|
||||
|
||||
const [user] = docs;
|
||||
|
||||
if (!user) throw new APIError('Token is either invalid or has expired.');
|
||||
|
||||
// TODO: replace this method
|
||||
@@ -77,7 +74,7 @@ async function resetPassword(args: Arguments): Promise<Result> {
|
||||
|
||||
const doc = await payload.db.updateOne({
|
||||
collection: collectionConfig.slug,
|
||||
id: user.id,
|
||||
where: { id: { equals: user.id } },
|
||||
data: user,
|
||||
});
|
||||
|
||||
|
||||
@@ -45,15 +45,12 @@ async function unlock(args: Args): Promise<boolean> {
|
||||
// Unlock
|
||||
// /////////////////////////////////////
|
||||
|
||||
const { docs } = await req.payload.db.find({
|
||||
const user = await req.payload.db.findOne({
|
||||
collection: collectionConfig.slug,
|
||||
where: { email: { equals: data.email.toLowerCase() } },
|
||||
limit: 1,
|
||||
locale,
|
||||
});
|
||||
|
||||
const [user] = docs;
|
||||
|
||||
if (!user) return null;
|
||||
|
||||
await resetLoginAttempts({
|
||||
|
||||
@@ -19,22 +19,19 @@ async function verifyEmail(args: Args): Promise<boolean> {
|
||||
throw new APIError('Missing required data.', httpStatus.BAD_REQUEST);
|
||||
}
|
||||
|
||||
const { docs } = await req.payload.db.find<any>({
|
||||
const user = await req.payload.db.findOne<any>({
|
||||
collection: collection.config.slug,
|
||||
limit: 1,
|
||||
where: {
|
||||
_verificationToken: { equals: token },
|
||||
},
|
||||
});
|
||||
|
||||
const [user] = docs;
|
||||
|
||||
if (!user) throw new APIError('Verification token is invalid.', httpStatus.BAD_REQUEST);
|
||||
if (user && user._verified === true) throw new APIError('This account has already been activated.', httpStatus.ACCEPTED);
|
||||
|
||||
await req.payload.db.updateOne({
|
||||
collection: collection.config.slug,
|
||||
id: user.id,
|
||||
where: { id: { equals: user.id } },
|
||||
data: {
|
||||
_verified: true,
|
||||
_verificationToken: undefined,
|
||||
|
||||
@@ -4,7 +4,7 @@ import { AggregatePaginateModel, IndexDefinition, IndexOptions, Model, PaginateM
|
||||
import { GraphQLInputObjectType, GraphQLNonNull, GraphQLObjectType } from 'graphql';
|
||||
import { Response } from 'express';
|
||||
import { Config as GeneratedTypes } from 'payload/generated-types';
|
||||
import { Where } from '../../types';
|
||||
import type { Where } from '../../types';
|
||||
import { Access, Endpoint, EntityDescription, GeneratePreviewURL } from '../../config/types';
|
||||
import { Field } from '../../fields/config/types';
|
||||
import { PayloadRequest } from '../../express/types';
|
||||
@@ -29,6 +29,7 @@ interface PassportLocalModel {
|
||||
}
|
||||
|
||||
export interface CollectionModel extends Model<any>, PaginateModel<any>, AggregatePaginateModel<any>, PassportLocalModel {
|
||||
/** buildQuery is used to transform payload's where operator into what can be used by mongoose (e.g. id => _id) */
|
||||
buildQuery: (args: BuildQueryArgs) => Promise<Record<string, unknown>> // TODO: Delete this
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,6 @@ async function deleteOperation<TSlug extends keyof GeneratedTypes['collections']
|
||||
const {
|
||||
depth,
|
||||
collection: {
|
||||
Model,
|
||||
config: collectionConfig,
|
||||
},
|
||||
where,
|
||||
@@ -133,7 +132,14 @@ async function deleteOperation<TSlug extends keyof GeneratedTypes['collections']
|
||||
// Delete document
|
||||
// /////////////////////////////////////
|
||||
|
||||
await Model.deleteOne({ _id: id }, { lean: true });
|
||||
await payload.db.deleteOne({
|
||||
collection: collectionConfig.slug,
|
||||
where: {
|
||||
id: {
|
||||
equals: id,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// /////////////////////////////////////
|
||||
// Delete versions
|
||||
|
||||
@@ -78,14 +78,12 @@ async function deleteByID<TSlug extends keyof GeneratedTypes['collections']>(inc
|
||||
// Retrieve document
|
||||
// /////////////////////////////////////
|
||||
|
||||
const { docs } = await req.payload.db.find({
|
||||
const docToDelete = await req.payload.db.findOne({
|
||||
collection: collectionConfig.slug,
|
||||
where: combineQueries({ id: { equals: id } }, accessResults),
|
||||
locale: req.locale,
|
||||
limit: 1,
|
||||
});
|
||||
|
||||
const [docToDelete] = docs;
|
||||
|
||||
if (!docToDelete && !hasWhereAccess) throw new NotFound(t);
|
||||
if (!docToDelete && hasWhereAccess) throw new Forbidden(t);
|
||||
@@ -100,7 +98,7 @@ async function deleteByID<TSlug extends keyof GeneratedTypes['collections']>(inc
|
||||
|
||||
let result = await req.payload.db.deleteOne({
|
||||
collection: collectionConfig.slug,
|
||||
id,
|
||||
where: { id: { equals: id } },
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -2,13 +2,12 @@
|
||||
import memoize from 'micro-memoize';
|
||||
import { PayloadRequest } from '../../express/types';
|
||||
import { Collection, TypeWithID } from '../config/types';
|
||||
import sanitizeInternalFields from '../../utilities/sanitizeInternalFields';
|
||||
import { NotFound } from '../../errors';
|
||||
import executeAccess from '../../auth/executeAccess';
|
||||
import replaceWithDraftIfAvailable from '../../versions/drafts/replaceWithDraftIfAvailable';
|
||||
import { afterRead } from '../../fields/hooks/afterRead';
|
||||
import { combineQueries } from '../../database/combineQueries';
|
||||
import { FindArgs } from '../../database/types';
|
||||
import type { FindOneArgs } from '../../database/types';
|
||||
|
||||
export type Arguments = {
|
||||
collection: Collection
|
||||
@@ -68,23 +67,22 @@ async function findByID<T extends TypeWithID>(
|
||||
if (accessResult === false) return null;
|
||||
|
||||
|
||||
const findArgs: FindArgs = {
|
||||
const findOneArgs: FindOneArgs = {
|
||||
collection: collectionConfig.slug,
|
||||
where: combineQueries({ id: { equals: id } }, accessResult),
|
||||
locale,
|
||||
limit: 1,
|
||||
};
|
||||
|
||||
// /////////////////////////////////////
|
||||
// Find by ID
|
||||
// /////////////////////////////////////
|
||||
|
||||
if (!findArgs.where.and[0].id) throw new NotFound(t);
|
||||
if (!findOneArgs.where.and[0].id) throw new NotFound(t);
|
||||
|
||||
if (!req.findByID) req.findByID = {};
|
||||
|
||||
if (!req.findByID[collectionConfig.slug]) {
|
||||
const nonMemoizedFindByID = async (query: FindArgs) => (await req.payload.db.find(query)).docs[0];
|
||||
const nonMemoizedFindByID = async (query: FindOneArgs) => req.payload.db.findOne(query);
|
||||
|
||||
req.findByID[collectionConfig.slug] = memoize(nonMemoizedFindByID, {
|
||||
isPromise: true,
|
||||
@@ -95,7 +93,7 @@ async function findByID<T extends TypeWithID>(
|
||||
});
|
||||
}
|
||||
|
||||
let result = await req.findByID[collectionConfig.slug](findArgs) as T;
|
||||
let result = await req.findByID[collectionConfig.slug](findOneArgs) as T;
|
||||
|
||||
if (!result) {
|
||||
if (!disableErrors) {
|
||||
@@ -108,7 +106,6 @@ async function findByID<T extends TypeWithID>(
|
||||
// Clone the result - it may have come back memoized
|
||||
result = JSON.parse(JSON.stringify(result));
|
||||
|
||||
result = sanitizeInternalFields(result);
|
||||
|
||||
// /////////////////////////////////////
|
||||
// Replace document with draft if available
|
||||
@@ -134,7 +131,7 @@ async function findByID<T extends TypeWithID>(
|
||||
|
||||
result = await hook({
|
||||
req,
|
||||
query: findArgs.where,
|
||||
query: findOneArgs.where,
|
||||
doc: result,
|
||||
}) || result;
|
||||
}, Promise.resolve());
|
||||
@@ -162,7 +159,7 @@ async function findByID<T extends TypeWithID>(
|
||||
|
||||
result = await hook({
|
||||
req,
|
||||
query: findArgs.where,
|
||||
query: findOneArgs.where,
|
||||
doc: result,
|
||||
}) || result;
|
||||
}, Promise.resolve());
|
||||
|
||||
@@ -9,7 +9,7 @@ import { afterChange } from '../../fields/hooks/afterChange';
|
||||
import { afterRead } from '../../fields/hooks/afterRead';
|
||||
import { getLatestCollectionVersion } from '../../versions/getLatestCollectionVersion';
|
||||
import { combineQueries } from '../../database/combineQueries';
|
||||
import { FindArgs } from '../../database/types';
|
||||
import type { FindOneArgs } from '../../database/types';
|
||||
|
||||
export type Arguments = {
|
||||
collection: Collection
|
||||
@@ -47,9 +47,6 @@ async function restoreVersion<T extends TypeWithID = any>(args: Arguments): Prom
|
||||
// Retrieve original raw version
|
||||
// /////////////////////////////////////
|
||||
|
||||
const VersionModel = payload.versions[collectionConfig.slug];
|
||||
|
||||
|
||||
const { docs: versionDocs } = await req.payload.db.findVersions({
|
||||
collection: collectionConfig.slug,
|
||||
where: { id: { equals: id } },
|
||||
@@ -76,16 +73,14 @@ async function restoreVersion<T extends TypeWithID = any>(args: Arguments): Prom
|
||||
// Retrieve document
|
||||
// /////////////////////////////////////
|
||||
|
||||
const findArgs: FindArgs = {
|
||||
const findOneArgs: FindOneArgs = {
|
||||
collection: collectionConfig.slug,
|
||||
where: combineQueries({ id: { equals: parentDocID } }, accessResults),
|
||||
locale,
|
||||
limit: 1,
|
||||
};
|
||||
|
||||
const { docs } = await req.payload.db.find(findArgs);
|
||||
const doc = await req.payload.db.findOne(findOneArgs);
|
||||
|
||||
const [doc] = docs;
|
||||
|
||||
if (!doc && !hasWherePolicy) throw new NotFound(t);
|
||||
if (!doc && hasWherePolicy) throw new Forbidden(t);
|
||||
@@ -97,7 +92,7 @@ async function restoreVersion<T extends TypeWithID = any>(args: Arguments): Prom
|
||||
const prevDocWithLocales = await getLatestCollectionVersion({
|
||||
payload,
|
||||
id: parentDocID,
|
||||
query: findArgs,
|
||||
query: findOneArgs,
|
||||
config: collectionConfig,
|
||||
});
|
||||
|
||||
@@ -107,7 +102,7 @@ async function restoreVersion<T extends TypeWithID = any>(args: Arguments): Prom
|
||||
|
||||
let result = await req.payload.db.updateOne({
|
||||
collection: collectionConfig.slug,
|
||||
id: parentDocID,
|
||||
where: { id: { equals: parentDocID } },
|
||||
data: rawVersion.version,
|
||||
|
||||
});
|
||||
@@ -120,9 +115,10 @@ async function restoreVersion<T extends TypeWithID = any>(args: Arguments): Prom
|
||||
|
||||
delete prevVersion.id;
|
||||
|
||||
await VersionModel.create({
|
||||
await payload.db.createVersion({
|
||||
collectionSlug: collectionConfig.slug,
|
||||
parent: parentDocID,
|
||||
version: rawVersion.version,
|
||||
versionData: rawVersion.version,
|
||||
autosave: false,
|
||||
createdAt: prevVersion.createdAt,
|
||||
updatedAt: new Date().toISOString(),
|
||||
|
||||
@@ -245,7 +245,7 @@ async function update<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
result = await req.payload.db.updateOne({
|
||||
collection: collectionConfig.slug,
|
||||
locale,
|
||||
id,
|
||||
where: { id: { equals: id } },
|
||||
data: result,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ import { deleteAssociatedFiles } from '../../uploads/deleteAssociatedFiles';
|
||||
import { unlinkTempFiles } from '../../uploads/unlinkTempFiles';
|
||||
import { generatePasswordSaltHash } from '../../auth/strategies/local/generatePasswordSaltHash';
|
||||
import { combineQueries } from '../../database/combineQueries';
|
||||
import { FindArgs } from '../../database/types';
|
||||
import type { FindOneArgs } from '../../database/types';
|
||||
|
||||
export type Arguments<T extends { [field: string | number | symbol]: unknown }> = {
|
||||
collection: Collection
|
||||
@@ -96,18 +96,17 @@ async function updateByID<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
// /////////////////////////////////////
|
||||
|
||||
|
||||
const findArgs: FindArgs = {
|
||||
const findOneArgs: FindOneArgs = {
|
||||
collection: collectionConfig.slug,
|
||||
where: combineQueries({ id: { equals: id } }, accessResults),
|
||||
locale,
|
||||
limit: 1,
|
||||
};
|
||||
|
||||
const docWithLocales = await getLatestCollectionVersion({
|
||||
payload,
|
||||
config: collectionConfig,
|
||||
id,
|
||||
query: findArgs,
|
||||
query: findOneArgs,
|
||||
});
|
||||
|
||||
if (!docWithLocales && !hasWherePolicy) throw new NotFound(t);
|
||||
@@ -233,7 +232,7 @@ async function updateByID<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
result = await req.payload.db.updateOne({
|
||||
collection: collectionConfig.slug,
|
||||
locale,
|
||||
id,
|
||||
where: { id: { equals: id } },
|
||||
data: dataToUpdate,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -38,12 +38,12 @@ export interface DatabaseAdapter {
|
||||
/**
|
||||
* Open the connection to the database
|
||||
*/
|
||||
connect?: ({ config }: { config: SanitizedConfig }) => Promise<void>;
|
||||
connect?: Connect;
|
||||
|
||||
/**
|
||||
* Perform startup tasks required to interact with the database such as building Schema and models
|
||||
*/
|
||||
init?: ({ config }: { config: SanitizedConfig }) => Promise<void>;
|
||||
init?: Init;
|
||||
|
||||
/**
|
||||
* Terminate the connection with the database
|
||||
@@ -53,7 +53,7 @@ export interface DatabaseAdapter {
|
||||
/**
|
||||
* Used to alias server only modules or make other changes to webpack configuration
|
||||
*/
|
||||
webpack?: (config: Configuration) => Configuration;
|
||||
webpack?: Webpack;
|
||||
|
||||
// migrations
|
||||
/**
|
||||
@@ -112,23 +112,36 @@ export interface DatabaseAdapter {
|
||||
*/
|
||||
commitTransaction?: () => Promise<boolean>;
|
||||
|
||||
// versions
|
||||
queryDrafts: <T = TypeWithID>(args: QueryDraftsArgs) => Promise<PaginatedDocs<T>>;
|
||||
queryDrafts: QueryDrafts;
|
||||
|
||||
// operations
|
||||
find: <T = TypeWithID>(args: FindArgs) => Promise<PaginatedDocs<T>>;
|
||||
|
||||
findGlobal: FindGlobal;
|
||||
|
||||
findVersions: <T = TypeWithID>(args: FindVersionArgs) => Promise<PaginatedDocs<TypeWithVersion<T>>>;
|
||||
findGlobalVersions: <T = TypeWithID>(args: FindGlobalVersionArgs) => Promise<PaginatedDocs<TypeWithVersion<T>>>;
|
||||
// operations - collections
|
||||
find: Find;
|
||||
findOne: FindOne;
|
||||
|
||||
create: Create;
|
||||
updateOne: UpdateOne;
|
||||
deleteOne: DeleteOne;
|
||||
deleteMany: DeleteMany;
|
||||
|
||||
// operations - globals
|
||||
findGlobal: FindGlobal;
|
||||
createGlobal: CreateGlobal;
|
||||
updateGlobal: UpdateGlobal;
|
||||
|
||||
|
||||
// versions
|
||||
findVersions: FindVersions;
|
||||
findGlobalVersions: FindGlobalVersions;
|
||||
createVersion: CreateVersion;
|
||||
updateVersion: UpdateVersion;
|
||||
deleteVersions: DeleteVersions;
|
||||
}
|
||||
|
||||
export type Init = ({ config }: { config: SanitizedConfig }) => Promise<void>;
|
||||
|
||||
export type Connect = ({ config }: { config: SanitizedConfig }) => Promise<void>
|
||||
|
||||
export type Webpack = (config: Configuration) => Configuration;
|
||||
|
||||
export type QueryDraftsArgs = {
|
||||
collection: string
|
||||
where?: Where
|
||||
@@ -139,6 +152,17 @@ export type QueryDraftsArgs = {
|
||||
locale?: string
|
||||
}
|
||||
|
||||
export type QueryDrafts = <T = TypeWithID>(args: QueryDraftsArgs) => Promise<PaginatedDocs<T>>;
|
||||
|
||||
export type FindOneArgs = {
|
||||
collection: string
|
||||
where?: Where
|
||||
locale?: string
|
||||
}
|
||||
|
||||
|
||||
export type FindOne = <T = TypeWithID>(args: FindOneArgs) => Promise<T|null>
|
||||
|
||||
export type FindArgs = {
|
||||
collection: string
|
||||
where?: Where
|
||||
@@ -152,7 +176,9 @@ export type FindArgs = {
|
||||
locale?: string
|
||||
}
|
||||
|
||||
export type FindVersionArgs = {
|
||||
export type Find = <T = TypeWithID>(args: FindArgs) => Promise<PaginatedDocs<T>>;
|
||||
|
||||
export type FindVersionsArgs = {
|
||||
collection: string
|
||||
where?: Where
|
||||
page?: number
|
||||
@@ -164,7 +190,10 @@ export type FindVersionArgs = {
|
||||
locale?: string
|
||||
}
|
||||
|
||||
export type FindGlobalVersionArgs = {
|
||||
export type FindVersions = <T = TypeWithID>(args: FindVersionsArgs) => Promise<PaginatedDocs<TypeWithVersion<T>>>;
|
||||
|
||||
|
||||
export type FindGlobalVersionsArgs = {
|
||||
global: string
|
||||
where?: Where
|
||||
page?: number
|
||||
@@ -179,53 +208,81 @@ export type FindGlobalVersionArgs = {
|
||||
export type FindGlobalArgs = {
|
||||
slug: string
|
||||
locale?: string
|
||||
where: Where
|
||||
where?: Where
|
||||
}
|
||||
|
||||
type FindGlobal = <T extends GlobalsTypeWithID = any>(args: FindGlobalArgs) => Promise<T>
|
||||
export type FindGlobal = <T extends GlobalsTypeWithID = any>(args: FindGlobalArgs) => Promise<T>
|
||||
|
||||
|
||||
export type FindOneArgs = {
|
||||
export type CreateGlobalArgs<T extends GlobalsTypeWithID = any> = {
|
||||
slug: string
|
||||
data: T
|
||||
}
|
||||
export type CreateGlobal = <T extends GlobalsTypeWithID = any>(args: CreateGlobalArgs<T>) => Promise<T>
|
||||
|
||||
|
||||
export type UpdateGlobalArgs<T extends GlobalsTypeWithID = any> = {
|
||||
slug: string
|
||||
data: T
|
||||
}
|
||||
export type UpdateGlobal = <T extends GlobalsTypeWithID = any>(args: UpdateGlobalArgs<T>) => Promise<T>
|
||||
|
||||
|
||||
export type FindGlobalVersions = <T = TypeWithID>(args: FindGlobalVersionsArgs) => Promise<PaginatedDocs<TypeWithVersion<T>>>;
|
||||
|
||||
export type DeleteVersionsArgs = {
|
||||
collection: string
|
||||
where: Where
|
||||
locale?: string
|
||||
sort?: {
|
||||
[key: string]: string,
|
||||
}
|
||||
};
|
||||
|
||||
export type CreateVersionArgs<T = TypeWithID> = {
|
||||
collectionSlug: string
|
||||
/** ID of the parent document for which the version should be created for */
|
||||
parent: string | number
|
||||
versionData: T
|
||||
autosave: boolean
|
||||
createdAt: string
|
||||
updatedAt: string
|
||||
}
|
||||
|
||||
export type CreateVersion = <T = TypeWithID>(args: CreateVersionArgs<T>) => Promise<TypeWithVersion<T>>;
|
||||
|
||||
export type DeleteVersions = (args: DeleteVersionsArgs) => Promise<void>;
|
||||
|
||||
|
||||
export type UpdateVersionArgs<T = TypeWithID> = {
|
||||
collectionSlug: string,
|
||||
where: Where,
|
||||
locale?: string,
|
||||
versionData: T
|
||||
}
|
||||
|
||||
export type UpdateVersion = <T = TypeWithID>(args: UpdateVersionArgs<T>) => Promise<TypeWithVersion<T>>
|
||||
|
||||
type FindOne = (args: FindOneArgs) => Promise<PaginatedDocs>
|
||||
|
||||
export type CreateArgs = {
|
||||
collection: string
|
||||
data: Record<string, unknown>
|
||||
}
|
||||
|
||||
type Create = (args: CreateArgs) => Promise<Document>
|
||||
export type Create = (args: CreateArgs) => Promise<Document>
|
||||
|
||||
export type UpdateOneArgs = {
|
||||
collection: string,
|
||||
data: Record<string, unknown>,
|
||||
id: string | number,
|
||||
where: Where,
|
||||
locale?: string
|
||||
}
|
||||
|
||||
type UpdateOne = (args: UpdateOneArgs) => Promise<Document>
|
||||
export type UpdateOne = (args: UpdateOneArgs) => Promise<Document>
|
||||
|
||||
export type DeleteOneArgs = {
|
||||
collection: string,
|
||||
id: string | number,
|
||||
}
|
||||
|
||||
type DeleteOne = (args: DeleteOneArgs) => Promise<Document>
|
||||
|
||||
type DeleteManyArgs = {
|
||||
collection: string,
|
||||
where: Where,
|
||||
}
|
||||
|
||||
type DeleteMany = (args: DeleteManyArgs) => Promise<Document>
|
||||
export type DeleteOne = (args: DeleteOneArgs) => Promise<Document>
|
||||
|
||||
export type BuildSchema<TSchema> = (args: {
|
||||
config: SanitizedConfig,
|
||||
@@ -325,7 +382,7 @@ export type FieldGenerator<TSchema, TField> = {
|
||||
|
||||
export type SortArgs = {
|
||||
property: string
|
||||
order: SortOrder
|
||||
direction: SortDirection
|
||||
}[]
|
||||
|
||||
export type SortOrder = 'asc' | 'desc';
|
||||
export type SortDirection = 'asc' | 'desc';
|
||||
|
||||
@@ -5,7 +5,7 @@ import { UploadedFile } from 'express-fileupload';
|
||||
import { Payload } from '../payload';
|
||||
import { Collection, TypeWithID } from '../collections/config/types';
|
||||
import { User } from '../auth/types';
|
||||
import { FindArgs } from '../database/types';
|
||||
import type { FindOneArgs } from '../database/types';
|
||||
|
||||
/** Express request with some Payload related context added */
|
||||
export declare type PayloadRequest<U = any> = Request & {
|
||||
@@ -46,6 +46,6 @@ export declare type PayloadRequest<U = any> = Request & {
|
||||
payloadUploadSizes?: Record<string, Buffer>;
|
||||
/** Cache of documents related to the current request */
|
||||
findByID?: {
|
||||
[slug: string]: (q: FindArgs) => Promise<TypeWithID>;
|
||||
[slug: string]: (q: FindOneArgs) => Promise<TypeWithID>;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -2,6 +2,7 @@ import React from 'react';
|
||||
import { Document, Model } from 'mongoose';
|
||||
import { DeepRequired } from 'ts-essentials';
|
||||
import { GraphQLNonNull, GraphQLObjectType } from 'graphql';
|
||||
import type { Where } from '../../types';
|
||||
import { User } from '../../auth/types';
|
||||
import { PayloadRequest } from '../../express/types';
|
||||
import { Access, Endpoint, EntityDescription, GeneratePreviewURL } from '../../config/types';
|
||||
@@ -44,12 +45,12 @@ export type BeforeReadHook = (args: {
|
||||
export type AfterReadHook = (args: {
|
||||
doc: any
|
||||
req: PayloadRequest
|
||||
query?: { [key: string]: any }
|
||||
query?: Where
|
||||
findMany?: boolean
|
||||
}) => any;
|
||||
|
||||
export interface GlobalModel extends Model<Document> {
|
||||
buildQuery: (query: unknown, locale?: string) => Record<string, unknown>
|
||||
buildQuery: (query: unknown, locale?: string) => Promise<Record<string, unknown>>
|
||||
}
|
||||
|
||||
export type GlobalAdminOptions = {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import type { Where } from '../../types';
|
||||
import executeAccess from '../../auth/executeAccess';
|
||||
import { AccessResult } from '../../config/types';
|
||||
import replaceWithDraftIfAvailable from '../../versions/drafts/replaceWithDraftIfAvailable';
|
||||
import { afterRead } from '../../fields/hooks/afterRead';
|
||||
import { SanitizedGlobalConfig } from '../config/types';
|
||||
import { PayloadRequest } from '../../express/types';
|
||||
import { combineQueries } from '../../database/combineQueries';
|
||||
|
||||
type Args = {
|
||||
globalConfig: SanitizedGlobalConfig
|
||||
@@ -48,8 +48,11 @@ async function findOne<T extends Record<string, unknown>>(args: Args): Promise<T
|
||||
let doc = await req.payload.db.findGlobal({
|
||||
slug,
|
||||
locale,
|
||||
where: overrideAccess ? { globalType: { equals: slug } } : combineQueries({ globalType: { equals: slug } }, accessResult),
|
||||
where: overrideAccess ? undefined : accessResult as Where,
|
||||
});
|
||||
if (!doc) {
|
||||
doc = {};
|
||||
}
|
||||
|
||||
// /////////////////////////////////////
|
||||
// Replace document with draft if available
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/* eslint-disable no-underscore-dangle */
|
||||
import { PayloadRequest } from '../../express/types';
|
||||
import sanitizeInternalFields from '../../utilities/sanitizeInternalFields';
|
||||
import { Forbidden, NotFound } from '../../errors';
|
||||
import executeAccess from '../../auth/executeAccess';
|
||||
import { TypeWithVersion } from '../../versions/types';
|
||||
import { SanitizedGlobalConfig } from '../config/types';
|
||||
import { afterRead } from '../../fields/hooks/afterRead';
|
||||
import { combineQueries } from '../../database/combineQueries';
|
||||
import { FindGlobalVersionsArgs } from '../../database/types';
|
||||
|
||||
export type Arguments = {
|
||||
globalConfig: SanitizedGlobalConfig
|
||||
@@ -36,8 +36,6 @@ async function findVersionByID<T extends TypeWithVersion<T> = any>(args: Argumen
|
||||
showHiddenFields,
|
||||
} = args;
|
||||
|
||||
const VersionsModel = payload.versions[globalConfig.slug];
|
||||
|
||||
// /////////////////////////////////////
|
||||
// Access
|
||||
// /////////////////////////////////////
|
||||
@@ -49,22 +47,22 @@ async function findVersionByID<T extends TypeWithVersion<T> = any>(args: Argumen
|
||||
|
||||
const hasWhereAccess = typeof accessResults === 'object';
|
||||
|
||||
const query = await VersionsModel.buildQuery({
|
||||
where: combineQueries({ _id: { equals: id } }, accessResults),
|
||||
payload,
|
||||
const findGlobalVersionsArgs: FindGlobalVersionsArgs = {
|
||||
global: globalConfig.slug,
|
||||
where: combineQueries({ id: { equals: id } }, accessResults),
|
||||
locale,
|
||||
globalSlug: globalConfig.slug,
|
||||
});
|
||||
limit: 1,
|
||||
};
|
||||
|
||||
// /////////////////////////////////////
|
||||
// Find by ID
|
||||
// /////////////////////////////////////
|
||||
|
||||
if (!query.$and[0]._id) throw new NotFound(t);
|
||||
if (!findGlobalVersionsArgs.where.and[0].id) throw new NotFound(t);
|
||||
|
||||
let result = await VersionsModel.findOne(query, {}).lean();
|
||||
|
||||
if (!result) {
|
||||
const { docs: results } = await payload.db.findGlobalVersions(findGlobalVersionsArgs);
|
||||
if (!results || results?.length === 0) {
|
||||
if (!disableErrors) {
|
||||
if (!hasWhereAccess) throw new NotFound(t);
|
||||
if (hasWhereAccess) throw new Forbidden(t);
|
||||
@@ -73,10 +71,9 @@ async function findVersionByID<T extends TypeWithVersion<T> = any>(args: Argumen
|
||||
return null;
|
||||
}
|
||||
|
||||
// Clone the result - it may have come back memoized
|
||||
result = JSON.parse(JSON.stringify(result));
|
||||
|
||||
result = sanitizeInternalFields(result);
|
||||
// Clone the result - it may have come back memoized
|
||||
let result = JSON.parse(JSON.stringify(results[0]));
|
||||
|
||||
// /////////////////////////////////////
|
||||
// beforeRead - Collection
|
||||
@@ -85,7 +82,7 @@ async function findVersionByID<T extends TypeWithVersion<T> = any>(args: Argumen
|
||||
await globalConfig.hooks.beforeRead.reduce(async (priorHook, hook) => {
|
||||
await priorHook;
|
||||
|
||||
result.version = await hook({
|
||||
result = await hook({
|
||||
req,
|
||||
doc: result.version,
|
||||
}) || result.version;
|
||||
@@ -114,7 +111,7 @@ async function findVersionByID<T extends TypeWithVersion<T> = any>(args: Argumen
|
||||
|
||||
result.version = await hook({
|
||||
req,
|
||||
query,
|
||||
query: findGlobalVersionsArgs.where,
|
||||
doc: result.version,
|
||||
}) || result.version;
|
||||
}, Promise.resolve());
|
||||
|
||||
@@ -56,7 +56,7 @@ export default async function updateLocal<TSlug extends keyof GeneratedTypes['gl
|
||||
if (!req.payloadDataLoader) req.payloadDataLoader = getDataLoader(req);
|
||||
|
||||
return update<TSlug>({
|
||||
slug: globalSlug,
|
||||
slug: globalSlug as string,
|
||||
data,
|
||||
depth,
|
||||
globalConfig,
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { PayloadRequest } from '../../express/types';
|
||||
import executeAccess from '../../auth/executeAccess';
|
||||
import sanitizeInternalFields from '../../utilities/sanitizeInternalFields';
|
||||
import { TypeWithVersion } from '../../versions/types';
|
||||
import { SanitizedGlobalConfig } from '../config/types';
|
||||
import { NotFound } from '../../errors';
|
||||
@@ -25,11 +24,6 @@ async function restoreVersion<T extends TypeWithVersion<T> = any>(args: Argument
|
||||
req: {
|
||||
t,
|
||||
payload,
|
||||
payload: {
|
||||
globals: {
|
||||
Model,
|
||||
},
|
||||
},
|
||||
},
|
||||
overrideAccess,
|
||||
showHiddenFields,
|
||||
@@ -47,17 +41,18 @@ async function restoreVersion<T extends TypeWithVersion<T> = any>(args: Argument
|
||||
// Retrieve original raw version
|
||||
// /////////////////////////////////////
|
||||
|
||||
const VersionModel = payload.versions[globalConfig.slug];
|
||||
|
||||
let rawVersion = await VersionModel.findOne({
|
||||
_id: id,
|
||||
const { docs: versionDocs } = await payload.db.findGlobalVersions<any>({
|
||||
global: globalConfig.slug,
|
||||
where: { id: { equals: id } },
|
||||
limit: 1,
|
||||
});
|
||||
|
||||
if (!rawVersion) {
|
||||
|
||||
if (!versionDocs || versionDocs.length === 0) {
|
||||
throw new NotFound(t);
|
||||
}
|
||||
|
||||
rawVersion = rawVersion.toJSON({ virtuals: true });
|
||||
const rawVersion = versionDocs[0];
|
||||
|
||||
// /////////////////////////////////////
|
||||
// fetch previousDoc
|
||||
@@ -72,29 +67,24 @@ async function restoreVersion<T extends TypeWithVersion<T> = any>(args: Argument
|
||||
// Update global
|
||||
// /////////////////////////////////////
|
||||
|
||||
const global = await Model.findOne({ globalType: globalConfig.slug });
|
||||
const global = await payload.db.findGlobal({
|
||||
slug: globalConfig.slug,
|
||||
});
|
||||
|
||||
let result = rawVersion.version;
|
||||
|
||||
if (global) {
|
||||
result = await Model.findOneAndUpdate(
|
||||
{ globalType: globalConfig.slug },
|
||||
result,
|
||||
{ new: true },
|
||||
);
|
||||
result = await payload.db.updateGlobal({
|
||||
slug: globalConfig.slug,
|
||||
data: result,
|
||||
});
|
||||
} else {
|
||||
result.globalType = globalConfig.slug;
|
||||
result = await Model.create(result);
|
||||
result = await payload.db.createGlobal({
|
||||
slug: globalConfig.slug,
|
||||
data: result,
|
||||
});
|
||||
}
|
||||
|
||||
result = result.toJSON({ virtuals: true });
|
||||
|
||||
// custom id type reset
|
||||
result.id = result._id;
|
||||
result = JSON.stringify(result);
|
||||
result = JSON.parse(result);
|
||||
result = sanitizeInternalFields(result);
|
||||
|
||||
// /////////////////////////////////////
|
||||
// afterRead - Fields
|
||||
// /////////////////////////////////////
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Config as GeneratedTypes } from 'payload/generated-types';
|
||||
import { DeepPartial } from 'ts-essentials';
|
||||
import type { Where } from '../../types';
|
||||
import { SanitizedGlobalConfig } from '../config/types';
|
||||
import executeAccess from '../../auth/executeAccess';
|
||||
import { beforeChange } from '../../fields/hooks/beforeChange';
|
||||
@@ -10,11 +11,10 @@ import { PayloadRequest } from '../../express/types';
|
||||
import { saveVersion } from '../../versions/saveVersion';
|
||||
import sanitizeInternalFields from '../../utilities/sanitizeInternalFields';
|
||||
import { getLatestGlobalVersion } from '../../versions/getLatestGlobalVersion';
|
||||
import { combineQueries } from '../../database/combineQueries';
|
||||
|
||||
type Args<T extends { [field: string | number | symbol]: unknown }> = {
|
||||
globalConfig: SanitizedGlobalConfig
|
||||
slug: string | number | symbol
|
||||
slug: string
|
||||
req: PayloadRequest
|
||||
depth?: number
|
||||
overrideAccess?: boolean
|
||||
@@ -34,11 +34,6 @@ async function update<TSlug extends keyof GeneratedTypes['globals']>(
|
||||
req: {
|
||||
payload,
|
||||
locale,
|
||||
payload: {
|
||||
globals: {
|
||||
Model,
|
||||
},
|
||||
},
|
||||
},
|
||||
depth,
|
||||
overrideAccess,
|
||||
@@ -61,24 +56,17 @@ async function update<TSlug extends keyof GeneratedTypes['globals']>(
|
||||
// Retrieve document
|
||||
// /////////////////////////////////////
|
||||
|
||||
const query = await Model.buildQuery({
|
||||
where: combineQueries({ globalType: { equals: slug } }, accessResults),
|
||||
payload,
|
||||
locale,
|
||||
overrideAccess,
|
||||
globalSlug: slug,
|
||||
});
|
||||
const query: Where = overrideAccess ? undefined : accessResults as Where;
|
||||
|
||||
// /////////////////////////////////////
|
||||
// 2. Retrieve document
|
||||
// /////////////////////////////////////
|
||||
|
||||
const { global, globalExists } = await getLatestGlobalVersion({
|
||||
payload,
|
||||
Model,
|
||||
config: globalConfig,
|
||||
query,
|
||||
lean: true,
|
||||
slug,
|
||||
where: query,
|
||||
locale,
|
||||
});
|
||||
|
||||
let globalJSON: Record<string, unknown> = {};
|
||||
@@ -161,20 +149,18 @@ async function update<TSlug extends keyof GeneratedTypes['globals']>(
|
||||
|
||||
if (!shouldSaveDraft) {
|
||||
if (globalExists) {
|
||||
result = await Model.findOneAndUpdate(
|
||||
{ globalType: slug },
|
||||
result,
|
||||
{ new: true },
|
||||
);
|
||||
result = await payload.db.updateGlobal({
|
||||
slug,
|
||||
data: result,
|
||||
});
|
||||
} else {
|
||||
result.globalType = slug;
|
||||
result = await Model.create(result);
|
||||
result = await payload.db.createGlobal({
|
||||
slug,
|
||||
data: result,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
result = JSON.parse(JSON.stringify(result));
|
||||
result = sanitizeInternalFields(result);
|
||||
|
||||
// /////////////////////////////////////
|
||||
// Create version
|
||||
// /////////////////////////////////////
|
||||
|
||||
@@ -2,13 +2,11 @@
|
||||
import type { ConnectOptions } from 'mongoose';
|
||||
import mongoose from 'mongoose';
|
||||
|
||||
import { SanitizedConfig } from 'payload/config';
|
||||
import type { MongooseAdapter } from '.';
|
||||
import type { Connect } from '../database/types';
|
||||
|
||||
export async function connect(
|
||||
this: MongooseAdapter,
|
||||
{ config }: { config: SanitizedConfig },
|
||||
): Promise<void> {
|
||||
export const connect: Connect = async function connect(this: MongooseAdapter,
|
||||
{ config }) {
|
||||
let urlToConnect = this.url;
|
||||
let successfulConnectionMessage = 'Connected to MongoDB server successfully!';
|
||||
|
||||
@@ -61,4 +59,4 @@ export async function connect(
|
||||
this.mongoMemoryServer = mongoMemoryServer;
|
||||
|
||||
return mongoMemoryServer;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,23 +1,21 @@
|
||||
import type { MongooseAdapter } from '.';
|
||||
import { CreateArgs } from '../database/types';
|
||||
import type { Create } from '../database/types';
|
||||
import { Document } from '../types';
|
||||
|
||||
export async function create<T = unknown>(
|
||||
this: MongooseAdapter,
|
||||
{ collection, data }: CreateArgs,
|
||||
): Promise<T> {
|
||||
export const create: Create = async function create(this: MongooseAdapter,
|
||||
{ collection, data }) {
|
||||
const Model = this.collections[collection];
|
||||
|
||||
const doc = await Model.create(data);
|
||||
|
||||
let result: Document = doc.toJSON({ virtuals: true });
|
||||
// doc.toJSON does not do stuff like converting ObjectIds to string, or date strings to date objects. That's why we use JSON.parse/stringify here
|
||||
const result: Document = JSON.parse(JSON.stringify(doc));
|
||||
const verificationToken = doc._verificationToken;
|
||||
|
||||
// custom id type reset
|
||||
result.id = result._id;
|
||||
result = JSON.parse(JSON.stringify(result));
|
||||
if (verificationToken) {
|
||||
result._verificationToken = verificationToken;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
22
src/mongoose/createGlobal.ts
Normal file
22
src/mongoose/createGlobal.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import type { MongooseAdapter } from '.';
|
||||
import type { CreateGlobal } from '../database/types';
|
||||
import sanitizeInternalFields from '../utilities/sanitizeInternalFields';
|
||||
|
||||
export const createGlobal: CreateGlobal = async function createGlobal(this: MongooseAdapter,
|
||||
{ data, slug }) {
|
||||
const Model = this.globals;
|
||||
|
||||
|
||||
let result = await Model.create({
|
||||
globalType: slug,
|
||||
...data,
|
||||
}) as any;
|
||||
|
||||
result = JSON.parse(JSON.stringify(result));
|
||||
|
||||
// custom id type reset
|
||||
result.id = result._id;
|
||||
result = sanitizeInternalFields(result);
|
||||
|
||||
return result;
|
||||
};
|
||||
27
src/mongoose/createVersion.ts
Normal file
27
src/mongoose/createVersion.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import type { MongooseAdapter } from '.';
|
||||
import type { CreateVersion } from '../database/types';
|
||||
import type { Document } from '../types';
|
||||
|
||||
export const createVersion: CreateVersion = async function createVersion(this: MongooseAdapter,
|
||||
{ collectionSlug, parent, versionData, autosave, createdAt, updatedAt }) {
|
||||
const VersionModel = this.versions[collectionSlug];
|
||||
|
||||
|
||||
const doc = await VersionModel.create({
|
||||
parent,
|
||||
version: versionData,
|
||||
autosave,
|
||||
createdAt,
|
||||
updatedAt,
|
||||
});
|
||||
|
||||
const result: Document = JSON.parse(JSON.stringify(doc));
|
||||
const verificationToken = doc._verificationToken;
|
||||
|
||||
// custom id type reset
|
||||
result.id = result._id;
|
||||
if (verificationToken) {
|
||||
result._verificationToken = verificationToken;
|
||||
}
|
||||
return result;
|
||||
};
|
||||
@@ -1,24 +1,26 @@
|
||||
import type { MongooseAdapter } from '.';
|
||||
import type { DeleteOneArgs } from '../database/types';
|
||||
import type { DeleteOne } from '../database/types';
|
||||
import type { Document } from '../types';
|
||||
import sanitizeInternalFields from '../utilities/sanitizeInternalFields';
|
||||
import { Document } from '../types';
|
||||
|
||||
export async function deleteOne<T = unknown>(
|
||||
this: MongooseAdapter,
|
||||
{ collection, id }: DeleteOneArgs,
|
||||
): Promise<T> {
|
||||
export const deleteOne: DeleteOne = async function deleteOne(this: MongooseAdapter,
|
||||
{ collection, where }) {
|
||||
const Model = this.collections[collection];
|
||||
|
||||
const doc = await Model.findOneAndDelete({ _id: id });
|
||||
const query = await Model.buildQuery({
|
||||
payload: this.payload,
|
||||
where,
|
||||
});
|
||||
|
||||
let result: Document = doc.toJSON({ virtuals: true });
|
||||
|
||||
const doc = await Model.findOneAndDelete(query).lean();
|
||||
|
||||
let result: Document = JSON.parse(JSON.stringify(doc));
|
||||
|
||||
// custom id type reset
|
||||
result.id = result._id;
|
||||
result = JSON.stringify(result);
|
||||
result = JSON.parse(result);
|
||||
result = sanitizeInternalFields(result);
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
16
src/mongoose/deleteVersions.ts
Normal file
16
src/mongoose/deleteVersions.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import type { MongooseAdapter } from '.';
|
||||
import type { DeleteVersions } from '../database/types';
|
||||
|
||||
export const deleteVersions: DeleteVersions = async function deleteVersions(this: MongooseAdapter,
|
||||
{ collection, where, locale }) {
|
||||
const VersionsModel = this.versions[collection];
|
||||
|
||||
|
||||
const query = await VersionsModel.buildQuery({
|
||||
payload: this.payload,
|
||||
locale,
|
||||
where,
|
||||
});
|
||||
|
||||
await VersionsModel.deleteMany(query).lean();
|
||||
};
|
||||
@@ -1,14 +1,12 @@
|
||||
import type { PaginateOptions } from 'mongoose';
|
||||
import type { MongooseAdapter } from '.';
|
||||
import { PaginatedDocs } from './types';
|
||||
import { FindArgs } from '../database/types';
|
||||
import type { Find } from '../database/types';
|
||||
import sanitizeInternalFields from '../utilities/sanitizeInternalFields';
|
||||
import flattenWhereToOperators from '../database/flattenWhereToOperators';
|
||||
|
||||
export async function find<T = unknown>(
|
||||
this: MongooseAdapter,
|
||||
{ collection, where, page, limit, sort, locale, pagination }: FindArgs,
|
||||
): Promise<PaginatedDocs<T>> {
|
||||
|
||||
export const find: Find = async function find(this: MongooseAdapter,
|
||||
{ collection, where, page, limit, sort, locale, pagination }) {
|
||||
const Model = this.collections[collection];
|
||||
|
||||
let useEstimatedCount = false;
|
||||
@@ -27,7 +25,7 @@ export async function find<T = unknown>(
|
||||
const paginationOptions: PaginateOptions = {
|
||||
page,
|
||||
sort: sort ? sort.reduce((acc, cur) => {
|
||||
acc[cur.property] = cur.order;
|
||||
acc[cur.property] = cur.direction;
|
||||
return acc;
|
||||
}, {}) : undefined,
|
||||
limit,
|
||||
@@ -42,13 +40,14 @@ export async function find<T = unknown>(
|
||||
};
|
||||
|
||||
const result = await Model.paginate(query, paginationOptions);
|
||||
const docs = JSON.parse(JSON.stringify(result.docs));
|
||||
|
||||
return {
|
||||
...result,
|
||||
docs: result.docs.map((doc) => {
|
||||
const sanitizedDoc = JSON.parse(JSON.stringify(doc));
|
||||
sanitizedDoc.id = sanitizedDoc._id;
|
||||
return sanitizeInternalFields(sanitizedDoc);
|
||||
docs: docs.map((doc) => {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
doc.id = doc._id;
|
||||
return sanitizeInternalFields(doc);
|
||||
}),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
import type { MongooseAdapter } from '.';
|
||||
import { FindGlobalArgs } from '../database/types';
|
||||
import { combineQueries } from '../database/combineQueries';
|
||||
import type { FindGlobal } from '../database/types';
|
||||
import sanitizeInternalFields from '../utilities/sanitizeInternalFields';
|
||||
import { TypeWithID } from '../globals/config/types';
|
||||
|
||||
export async function findGlobal<T extends TypeWithID = any>(
|
||||
this: MongooseAdapter,
|
||||
{ slug, locale, where }: FindGlobalArgs,
|
||||
): Promise<T> {
|
||||
export const findGlobal: FindGlobal = async function findGlobal(this: MongooseAdapter,
|
||||
{ slug, locale, where }) {
|
||||
const Model = this.globals;
|
||||
|
||||
const query = await Model.buildQuery({
|
||||
where,
|
||||
where: combineQueries({ globalType: { equals: slug } }, where),
|
||||
payload: this.payload,
|
||||
locale,
|
||||
globalSlug: slug,
|
||||
@@ -19,8 +17,8 @@ export async function findGlobal<T extends TypeWithID = any>(
|
||||
let doc = await Model.findOne(query).lean() as any;
|
||||
|
||||
if (!doc) {
|
||||
doc = {};
|
||||
} else if (doc._id) {
|
||||
return null;
|
||||
} if (doc._id) {
|
||||
doc.id = doc._id;
|
||||
delete doc._id;
|
||||
}
|
||||
@@ -30,4 +28,4 @@ export async function findGlobal<T extends TypeWithID = any>(
|
||||
|
||||
|
||||
return doc;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
import type { MongooseAdapter } from '.';
|
||||
import { PaginatedDocs } from './types';
|
||||
import { FindGlobalVersionArgs } from '../database/types';
|
||||
import type { FindGlobalVersions } from '../database/types';
|
||||
import sanitizeInternalFields from '../utilities/sanitizeInternalFields';
|
||||
import flattenWhereToOperators from '../database/flattenWhereToOperators';
|
||||
import type { TypeWithVersion } from '../versions/types';
|
||||
|
||||
export async function findGlobalVersions<T = unknown>(
|
||||
this: MongooseAdapter,
|
||||
{ global, where, page, limit, sort, locale, pagination, skip }: FindGlobalVersionArgs,
|
||||
): Promise<PaginatedDocs<TypeWithVersion<T>>> {
|
||||
export const findGlobalVersions: FindGlobalVersions = async function findGlobalVersions(this: MongooseAdapter,
|
||||
{ global, where, page, limit, sort, locale, pagination, skip }) {
|
||||
const Model = this.versions[global];
|
||||
|
||||
let useEstimatedCount = false;
|
||||
@@ -28,7 +24,7 @@ export async function findGlobalVersions<T = unknown>(
|
||||
const paginationOptions = {
|
||||
page,
|
||||
sort: sort ? sort.reduce((acc, cur) => {
|
||||
acc[cur.property] = cur.order;
|
||||
acc[cur.property] = cur.direction;
|
||||
return acc;
|
||||
}, {}) : undefined,
|
||||
limit,
|
||||
@@ -45,13 +41,14 @@ export async function findGlobalVersions<T = unknown>(
|
||||
};
|
||||
|
||||
const result = await Model.paginate(query, paginationOptions);
|
||||
const docs = JSON.parse(JSON.stringify(result.docs));
|
||||
|
||||
return {
|
||||
...result,
|
||||
docs: result.docs.map((doc) => {
|
||||
const sanitizedDoc = JSON.parse(JSON.stringify(doc));
|
||||
sanitizedDoc.id = sanitizedDoc._id;
|
||||
return sanitizeInternalFields(sanitizedDoc);
|
||||
docs: docs.map((doc) => {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
doc.id = doc._id;
|
||||
return sanitizeInternalFields(doc);
|
||||
}),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
31
src/mongoose/findOne.ts
Normal file
31
src/mongoose/findOne.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import type { MongooseAdapter } from '.';
|
||||
import type { FindOne } from '../database/types';
|
||||
import type { Document } from '../types';
|
||||
import sanitizeInternalFields from '../utilities/sanitizeInternalFields';
|
||||
|
||||
export const findOne: FindOne = async function findOne(this: MongooseAdapter,
|
||||
{ collection, where, locale }) {
|
||||
const Model = this.collections[collection];
|
||||
|
||||
|
||||
const query = await Model.buildQuery({
|
||||
payload: this.payload,
|
||||
locale,
|
||||
where,
|
||||
});
|
||||
|
||||
const doc = await Model.findOne(query).lean();
|
||||
|
||||
if (!doc) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
let result: Document = JSON.parse(JSON.stringify(doc));
|
||||
|
||||
// custom id type reset
|
||||
result.id = result._id;
|
||||
result = sanitizeInternalFields(result);
|
||||
|
||||
return result;
|
||||
};
|
||||
@@ -1,14 +1,10 @@
|
||||
import type { MongooseAdapter } from '.';
|
||||
import { PaginatedDocs } from './types';
|
||||
import { FindVersionArgs } from '../database/types';
|
||||
import type { FindVersions } from '../database/types';
|
||||
import sanitizeInternalFields from '../utilities/sanitizeInternalFields';
|
||||
import flattenWhereToOperators from '../database/flattenWhereToOperators';
|
||||
import type { TypeWithVersion } from '../versions/types';
|
||||
|
||||
export async function findVersions<T = unknown>(
|
||||
this: MongooseAdapter,
|
||||
{ collection, where, page, limit, sort, locale, pagination, skip }: FindVersionArgs,
|
||||
): Promise<PaginatedDocs<TypeWithVersion<T>>> {
|
||||
export const findVersions: FindVersions = async function findVersions(this: MongooseAdapter,
|
||||
{ collection, where, page, limit, sort, locale, pagination, skip }) {
|
||||
const Model = this.versions[collection];
|
||||
|
||||
let useEstimatedCount = false;
|
||||
@@ -27,7 +23,7 @@ export async function findVersions<T = unknown>(
|
||||
const paginationOptions = {
|
||||
page,
|
||||
sort: sort ? sort.reduce((acc, cur) => {
|
||||
acc[cur.property] = cur.order;
|
||||
acc[cur.property] = cur.direction;
|
||||
return acc;
|
||||
}, {}) : undefined,
|
||||
limit,
|
||||
@@ -44,13 +40,14 @@ export async function findVersions<T = unknown>(
|
||||
};
|
||||
|
||||
const result = await Model.paginate(query, paginationOptions);
|
||||
const docs = JSON.parse(JSON.stringify(result.docs));
|
||||
|
||||
return {
|
||||
...result,
|
||||
docs: result.docs.map((doc) => {
|
||||
const sanitizedDoc = JSON.parse(JSON.stringify(doc));
|
||||
sanitizedDoc.id = sanitizedDoc._id;
|
||||
return sanitizeInternalFields(sanitizedDoc);
|
||||
docs: docs.map((doc) => {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
doc.id = doc._id;
|
||||
return sanitizeInternalFields(doc);
|
||||
}),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { ConnectOptions } from 'mongoose';
|
||||
import type { DatabaseAdapter } from '../database/types';
|
||||
import type { Payload } from '../index';
|
||||
import { connect } from './connect';
|
||||
import { init } from './init';
|
||||
import { webpack } from './webpack';
|
||||
@@ -10,10 +11,15 @@ import { find } from './find';
|
||||
import { create } from './create';
|
||||
import { updateOne } from './updateOne';
|
||||
import { deleteOne } from './deleteOne';
|
||||
import { findGlobal } from './findGlobal';
|
||||
import { findOne } from './findOne';
|
||||
import { findVersions } from './findVersions';
|
||||
import { findGlobalVersions } from './findGlobalVersions';
|
||||
import type { Payload } from '../index';
|
||||
import { findGlobal } from './findGlobal';
|
||||
import { deleteVersions } from './deleteVersions';
|
||||
import { createVersion } from './createVersion';
|
||||
import { updateVersion } from './updateVersion';
|
||||
import { updateGlobal } from './updateGlobal';
|
||||
import { createGlobal } from './createGlobal';
|
||||
|
||||
export interface Args {
|
||||
payload: Payload,
|
||||
@@ -60,12 +66,18 @@ export function mongooseAdapter({ payload, url, connectOptions }: Args): Mongoos
|
||||
rollbackTransaction: async () => true,
|
||||
commitTransaction: async () => true,
|
||||
queryDrafts,
|
||||
findOne,
|
||||
find,
|
||||
findVersions,
|
||||
findGlobal,
|
||||
findGlobalVersions,
|
||||
create,
|
||||
updateOne,
|
||||
deleteOne,
|
||||
findGlobal,
|
||||
createGlobal,
|
||||
updateGlobal,
|
||||
findVersions,
|
||||
findGlobalVersions,
|
||||
createVersion,
|
||||
updateVersion,
|
||||
deleteVersions,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -11,13 +11,10 @@ import { getVersionsModelName } from '../versions/getVersionsModelName';
|
||||
import type { MongooseAdapter } from '.';
|
||||
import { buildGlobalModel } from './models/buildGlobalModel';
|
||||
import { buildVersionGlobalFields } from '../versions/buildGlobalFields';
|
||||
import type { SanitizedConfig } from '../config/types';
|
||||
import type { Init } from '../database/types';
|
||||
|
||||
|
||||
export async function init(
|
||||
this: MongooseAdapter,
|
||||
{ config }: { config: SanitizedConfig },
|
||||
): Promise<void> {
|
||||
export const init: Init = async function init(this: MongooseAdapter,
|
||||
{ config }) {
|
||||
this.payload.config.collections.forEach((collection: SanitizedCollectionConfig) => {
|
||||
const schema = buildCollectionSchema(collection, this.payload.config);
|
||||
|
||||
@@ -112,4 +109,4 @@ export async function init(
|
||||
this.payload.versions[global.slug] = versionsModel;
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Config } from '../../config/types';
|
||||
import { getLocalizedSortProperty } from './getLocalizedSortProperty';
|
||||
import { Field } from '../../fields/config/types';
|
||||
import type { SortArgs, SortOrder } from '../../database/types';
|
||||
import type { SortArgs, SortDirection } from '../../database/types';
|
||||
|
||||
type Args = {
|
||||
sort: string
|
||||
@@ -13,7 +13,7 @@ type Args = {
|
||||
|
||||
export const buildSortParam = ({ sort, config, fields, timestamps, locale }: Args): SortArgs => {
|
||||
let sortProperty: string;
|
||||
let sortOrder: SortOrder = 'desc';
|
||||
let sortDirection: SortDirection = 'desc';
|
||||
|
||||
if (!sort) {
|
||||
if (timestamps) {
|
||||
@@ -25,7 +25,7 @@ export const buildSortParam = ({ sort, config, fields, timestamps, locale }: Arg
|
||||
sortProperty = sort.substring(1);
|
||||
} else {
|
||||
sortProperty = sort;
|
||||
sortOrder = 'asc';
|
||||
sortDirection = 'asc';
|
||||
}
|
||||
|
||||
if (sortProperty === 'id') {
|
||||
@@ -39,5 +39,5 @@ export const buildSortParam = ({ sort, config, fields, timestamps, locale }: Arg
|
||||
});
|
||||
}
|
||||
|
||||
return [{ property: sortProperty, order: sortOrder }];
|
||||
return [{ property: sortProperty, direction: sortDirection }];
|
||||
};
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import type { MongooseAdapter } from '.';
|
||||
import { PaginatedDocs } from './types';
|
||||
import { QueryDraftsArgs } from '../database/types';
|
||||
import type { QueryDrafts } from '../database/types';
|
||||
import flattenWhereToOperators from '../database/flattenWhereToOperators';
|
||||
import sanitizeInternalFields from '../utilities/sanitizeInternalFields';
|
||||
|
||||
@@ -11,10 +10,8 @@ type AggregateVersion<T> = {
|
||||
createdAt: string
|
||||
}
|
||||
|
||||
export async function queryDrafts<T = unknown>(
|
||||
this: MongooseAdapter,
|
||||
{ collection, where, page, limit, sort, locale, pagination }: QueryDraftsArgs,
|
||||
): Promise<PaginatedDocs<T>> {
|
||||
export const queryDrafts: QueryDrafts = async function queryDrafts<T>(this: MongooseAdapter,
|
||||
{ collection, where, page, limit, sort, locale, pagination }) {
|
||||
const VersionModel = this.versions[collection];
|
||||
|
||||
const versionQuery = await VersionModel.buildQuery({
|
||||
@@ -66,7 +63,7 @@ export async function queryDrafts<T = unknown>(
|
||||
},
|
||||
sort: sort ? sort.reduce((acc, cur) => {
|
||||
let sanitizedSortProperty = cur.property;
|
||||
const sanitizedSortOrder = cur.order === 'asc' ? 1 : -1;
|
||||
const sanitizedSortOrder = cur.direction === 'asc' ? 1 : -1;
|
||||
|
||||
if (!['createdAt', 'updatedAt', '_id'].includes(cur.property)) {
|
||||
sanitizedSortProperty = `version.${cur.property}`;
|
||||
@@ -81,19 +78,21 @@ export async function queryDrafts<T = unknown>(
|
||||
result = aggregate.exec();
|
||||
}
|
||||
|
||||
const docs = JSON.parse(JSON.stringify(result.docs));
|
||||
|
||||
return {
|
||||
...result,
|
||||
docs: result.docs.map((doc) => {
|
||||
let sanitizedDoc = {
|
||||
docs: docs.map((doc) => {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
doc = {
|
||||
_id: doc._id,
|
||||
id: doc._id,
|
||||
...doc.version,
|
||||
updatedAt: doc.updatedAt,
|
||||
createdAt: doc.createdAt,
|
||||
};
|
||||
|
||||
sanitizedDoc = JSON.parse(JSON.stringify(sanitizedDoc));
|
||||
sanitizedDoc.id = sanitizedDoc._id;
|
||||
return sanitizeInternalFields(sanitizedDoc);
|
||||
return sanitizeInternalFields(doc);
|
||||
}),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
24
src/mongoose/updateGlobal.ts
Normal file
24
src/mongoose/updateGlobal.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import type { MongooseAdapter } from '.';
|
||||
import type { UpdateGlobal } from '../database/types';
|
||||
import sanitizeInternalFields from '../utilities/sanitizeInternalFields';
|
||||
|
||||
export const updateGlobal: UpdateGlobal = async function updateGlobal(this: MongooseAdapter,
|
||||
{ slug, data }) {
|
||||
const Model = this.globals;
|
||||
|
||||
let result;
|
||||
result = await Model.findOneAndUpdate(
|
||||
{ globalType: slug },
|
||||
data,
|
||||
{ new: true, lean: true },
|
||||
).lean();
|
||||
|
||||
result = JSON.parse(JSON.stringify(result));
|
||||
|
||||
// custom id type reset
|
||||
result.id = result._id;
|
||||
result = sanitizeInternalFields(result);
|
||||
|
||||
|
||||
return result;
|
||||
};
|
||||
@@ -1,36 +1,40 @@
|
||||
import { t } from 'i18next';
|
||||
import type { MongooseAdapter } from '.';
|
||||
import type { UpdateOneArgs } from '../database/types';
|
||||
import type { UpdateOne } from '../database/types';
|
||||
import { ValidationError } from '../errors';
|
||||
import sanitizeInternalFields from '../utilities/sanitizeInternalFields';
|
||||
import i18nInit from '../translations/init';
|
||||
|
||||
export async function updateOne<T = unknown>(
|
||||
this: MongooseAdapter,
|
||||
{ collection, data, id, locale }: UpdateOneArgs,
|
||||
): Promise<T> {
|
||||
export const updateOne: UpdateOne = async function updateOne(this: MongooseAdapter,
|
||||
{ collection, data, where, locale }) {
|
||||
const Model = this.collections[collection];
|
||||
|
||||
const query = await Model.buildQuery({
|
||||
payload: this.payload,
|
||||
locale,
|
||||
where,
|
||||
});
|
||||
|
||||
let result;
|
||||
try {
|
||||
result = await Model.findByIdAndUpdate(
|
||||
{ _id: id, locale },
|
||||
result = await Model.findOneAndUpdate(
|
||||
query,
|
||||
data,
|
||||
{ new: true },
|
||||
);
|
||||
{ new: true, lean: true },
|
||||
).lean();
|
||||
} catch (error) {
|
||||
// Handle uniqueness error from MongoDB
|
||||
throw error.code === 11000 && error.keyValue
|
||||
? new ValidationError([{
|
||||
message: 'Value must be unique',
|
||||
field: Object.keys(error.keyValue)[0],
|
||||
}], t)
|
||||
}], i18nInit(this.payload.config.i18n).t)
|
||||
: error;
|
||||
}
|
||||
|
||||
result = JSON.parse(JSON.stringify(result));
|
||||
result.id = result._id as string | number;
|
||||
result.id = result._id;
|
||||
result = sanitizeInternalFields(result);
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
31
src/mongoose/updateVersion.ts
Normal file
31
src/mongoose/updateVersion.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import type { MongooseAdapter } from '.';
|
||||
import type { UpdateVersion } from '../database/types';
|
||||
|
||||
export const updateVersion: UpdateVersion = async function updateVersion(this: MongooseAdapter,
|
||||
{ collectionSlug, where, locale, versionData }) {
|
||||
const VersionModel = this.versions[collectionSlug];
|
||||
|
||||
const query = await VersionModel.buildQuery({
|
||||
payload: this.payload,
|
||||
locale,
|
||||
where,
|
||||
});
|
||||
|
||||
|
||||
const doc = await VersionModel.findOneAndUpdate(
|
||||
query,
|
||||
versionData,
|
||||
{ new: true, lean: true },
|
||||
).lean();
|
||||
|
||||
const result = JSON.parse(JSON.stringify(doc));
|
||||
|
||||
const verificationToken = doc._verificationToken;
|
||||
|
||||
// custom id type reset
|
||||
result.id = result._id;
|
||||
if (verificationToken) {
|
||||
result._verificationToken = verificationToken;
|
||||
}
|
||||
return result;
|
||||
};
|
||||
@@ -1,6 +1,7 @@
|
||||
import path from 'path';
|
||||
import type { Webpack } from '../database/types';
|
||||
|
||||
export const webpack = (config) => ({
|
||||
export const webpack: Webpack = (config) => ({
|
||||
...config,
|
||||
resolve: {
|
||||
...config.resolve || {},
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
import { CollectionModel } from '../collections/config/types';
|
||||
import { Payload } from '..';
|
||||
|
||||
const docWithFilenameExists = async (Model: CollectionModel, path: string, filename: string): Promise<boolean> => {
|
||||
const doc = await Model.findOne({ filename });
|
||||
const docWithFilenameExists = async (payload: Payload, collectionSlug: string, path: string, filename: string): Promise<boolean> => {
|
||||
const doc = await payload.db.findOne({
|
||||
collection: collectionSlug,
|
||||
where: {
|
||||
filename: {
|
||||
equals: filename,
|
||||
},
|
||||
},
|
||||
});
|
||||
if (doc) return true;
|
||||
|
||||
return false;
|
||||
|
||||
@@ -32,7 +32,6 @@ export const generateFileData = async <T>({
|
||||
config,
|
||||
collection: {
|
||||
config: collectionConfig,
|
||||
Model,
|
||||
},
|
||||
req,
|
||||
data,
|
||||
@@ -141,7 +140,7 @@ export const generateFileData = async <T>({
|
||||
fsSafeName = `${baseFilename}${ext ? `.${ext}` : ''}`;
|
||||
|
||||
if (!overwriteExistingFiles) {
|
||||
fsSafeName = await getSafeFileName(Model, staticPath, fsSafeName);
|
||||
fsSafeName = await getSafeFileName(req.payload, collectionConfig.slug, staticPath, fsSafeName);
|
||||
}
|
||||
|
||||
fileData.filename = fsSafeName;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import sanitize from 'sanitize-filename';
|
||||
import { CollectionModel } from '../collections/config/types';
|
||||
import docWithFilenameExists from './docWithFilenameExists';
|
||||
import fileExists from './fileExists';
|
||||
import { Payload } from '..';
|
||||
|
||||
const incrementName = (name: string) => {
|
||||
const extension = name.split('.').pop();
|
||||
@@ -20,11 +20,11 @@ const incrementName = (name: string) => {
|
||||
return `${incrementedName}.${extension}`;
|
||||
};
|
||||
|
||||
async function getSafeFileName(Model: CollectionModel, staticPath: string, desiredFilename: string): Promise<string> {
|
||||
async function getSafeFileName(payload: Payload, collectionSlug: string, staticPath: string, desiredFilename: string): Promise<string> {
|
||||
let modifiedFilename = desiredFilename;
|
||||
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
while (await docWithFilenameExists(Model, staticPath, modifiedFilename) || await fileExists(`${staticPath}/${modifiedFilename}`)) {
|
||||
while (await docWithFilenameExists(payload, collectionSlug, staticPath, modifiedFilename) || await fileExists(`${staticPath}/${modifiedFilename}`)) {
|
||||
modifiedFilename = incrementName(modifiedFilename);
|
||||
}
|
||||
return modifiedFilename;
|
||||
|
||||
@@ -11,12 +11,13 @@ export const deleteCollectionVersions = async ({
|
||||
slug,
|
||||
id,
|
||||
}: Args): Promise<void> => {
|
||||
const VersionsModel = payload.versions[slug];
|
||||
|
||||
try {
|
||||
await VersionsModel.deleteMany({
|
||||
await payload.db.deleteVersions({
|
||||
collection: slug,
|
||||
where: {
|
||||
parent: {
|
||||
$eq: id,
|
||||
equals: id,
|
||||
},
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { Payload } from '../../payload';
|
||||
import { docHasTimestamps, PayloadRequest, Where } from '../../types';
|
||||
import { hasWhereAccessResult } from '../../auth';
|
||||
import { AccessResult } from '../../config/types';
|
||||
@@ -7,7 +6,7 @@ import sanitizeInternalFields from '../../utilities/sanitizeInternalFields';
|
||||
import { appendVersionToQueryKey } from './appendVersionToQueryKey';
|
||||
import { SanitizedGlobalConfig } from '../../globals/config/types';
|
||||
import { combineQueries } from '../../database/combineQueries';
|
||||
import { FindVersionArgs } from '../../database/types';
|
||||
import type { FindVersionsArgs } from '../../database/types';
|
||||
|
||||
type Arguments<T> = {
|
||||
entity: SanitizedCollectionConfig | SanitizedGlobalConfig
|
||||
@@ -58,18 +57,18 @@ const replaceWithDraftIfAvailable = async <T extends TypeWithID>({
|
||||
}
|
||||
|
||||
|
||||
const findVersionArgs: FindVersionArgs = {
|
||||
const findVersionsArgs: FindVersionsArgs = {
|
||||
locale: req.locale,
|
||||
where: combineQueries(queryToBuild, versionAccessResult),
|
||||
collection: entity.slug,
|
||||
limit: 1,
|
||||
sort: [{
|
||||
property: 'updatedAt',
|
||||
order: 'desc',
|
||||
direction: 'desc',
|
||||
}],
|
||||
};
|
||||
|
||||
const { docs: versionDocs } = await req.payload.db.findVersions<T>(findVersionArgs);
|
||||
const { docs: versionDocs } = await req.payload.db.findVersions<T>(findVersionsArgs);
|
||||
|
||||
let draft = versionDocs[0];
|
||||
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
import { FilterQuery } from 'mongoose';
|
||||
import { Payload } from '../payload';
|
||||
import { CollectionModel, SanitizedCollectionConfig } from '../collections/config/types';
|
||||
import { Where } from '../types';
|
||||
import { SanitizedGlobalConfig } from '../globals/config/types';
|
||||
import type { SanitizedCollectionConfig } from '../collections/config/types';
|
||||
import type { SanitizedGlobalConfig } from '../globals/config/types';
|
||||
import type { Where } from '../types';
|
||||
|
||||
type Args = {
|
||||
payload: Payload
|
||||
Model: CollectionModel
|
||||
max: number
|
||||
collection?: SanitizedCollectionConfig
|
||||
global?: SanitizedGlobalConfig
|
||||
@@ -15,7 +13,6 @@ type Args = {
|
||||
|
||||
export const enforceMaxVersions = async ({
|
||||
payload,
|
||||
Model,
|
||||
max,
|
||||
collection,
|
||||
global,
|
||||
@@ -39,7 +36,7 @@ export const enforceMaxVersions = async ({
|
||||
skip: max,
|
||||
sort: [{
|
||||
property: 'updatedAt',
|
||||
order: 'desc',
|
||||
direction: 'desc',
|
||||
}],
|
||||
pagination: false,
|
||||
});
|
||||
@@ -52,7 +49,7 @@ export const enforceMaxVersions = async ({
|
||||
skip: max,
|
||||
sort: [{
|
||||
property: 'updatedAt',
|
||||
order: 'desc',
|
||||
direction: 'desc',
|
||||
}],
|
||||
});
|
||||
|
||||
@@ -60,15 +57,22 @@ export const enforceMaxVersions = async ({
|
||||
}
|
||||
|
||||
if (oldestAllowedDoc?.updatedAt) {
|
||||
const deleteQuery: FilterQuery<unknown> = {
|
||||
const deleteQuery: Where = {
|
||||
updatedAt: {
|
||||
$lte: oldestAllowedDoc.updatedAt,
|
||||
less_than_equal: oldestAllowedDoc.updatedAt,
|
||||
},
|
||||
};
|
||||
|
||||
if (collection) deleteQuery.parent = id;
|
||||
if (collection) {
|
||||
deleteQuery.parent = {
|
||||
equals: id,
|
||||
};
|
||||
}
|
||||
|
||||
await Model.deleteMany(deleteQuery);
|
||||
await payload.db.deleteVersions({
|
||||
collection: collection?.slug,
|
||||
where: deleteQuery,
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
payload.logger.error(`There was an error cleaning up old versions for the ${entityType} ${slug}`);
|
||||
|
||||
@@ -2,11 +2,11 @@ import { docHasTimestamps } from '../types';
|
||||
import { Payload } from '../payload';
|
||||
import { SanitizedCollectionConfig, TypeWithID } from '../collections/config/types';
|
||||
import { TypeWithVersion } from './types';
|
||||
import { FindArgs } from '../database/types';
|
||||
import type { FindOneArgs } from '../database/types';
|
||||
|
||||
type Args = {
|
||||
payload: Payload
|
||||
query: FindArgs
|
||||
query: FindOneArgs
|
||||
id: string | number
|
||||
config: SanitizedCollectionConfig
|
||||
}
|
||||
@@ -25,14 +25,13 @@ export const getLatestCollectionVersion = async <T extends TypeWithID = any>({
|
||||
where: { parent: { equals: id } },
|
||||
sort: [{
|
||||
property: 'updatedAt',
|
||||
order: 'desc',
|
||||
direction: 'desc',
|
||||
}],
|
||||
});
|
||||
[latestVersion] = docs;
|
||||
}
|
||||
|
||||
const { docs } = await payload.db.find<T>(query);
|
||||
const [doc] = docs;
|
||||
const doc = await payload.db.findOne<T>(query);
|
||||
|
||||
|
||||
if (!latestVersion || (docHasTimestamps(doc) && latestVersion.updatedAt < doc.updatedAt)) {
|
||||
|
||||
@@ -1,32 +1,39 @@
|
||||
import { Payload } from '../payload';
|
||||
import { docHasTimestamps, Document } from '../types';
|
||||
import { GlobalModel, SanitizedGlobalConfig } from '../globals/config/types';
|
||||
import { docHasTimestamps, Document, Where } from '../types';
|
||||
import { SanitizedGlobalConfig } from '../globals/config/types';
|
||||
|
||||
type Args = {
|
||||
payload: Payload
|
||||
query: Record<string, unknown>
|
||||
lean?: boolean
|
||||
Model: GlobalModel
|
||||
where: Where
|
||||
slug: string
|
||||
config: SanitizedGlobalConfig
|
||||
locale?: string
|
||||
}
|
||||
|
||||
export const getLatestGlobalVersion = async ({
|
||||
payload,
|
||||
config,
|
||||
Model,
|
||||
query,
|
||||
lean = true,
|
||||
slug,
|
||||
where,
|
||||
locale,
|
||||
}: Args): Promise<{global: Document, globalExists: boolean}> => {
|
||||
let latestVersion;
|
||||
|
||||
if (config.versions?.drafts) {
|
||||
latestVersion = await payload.versions[config.slug].findOne({}, {}, {
|
||||
sort: { updatedAt: 'desc' },
|
||||
lean,
|
||||
});
|
||||
// eslint-disable-next-line prefer-destructuring
|
||||
latestVersion = (await payload.db.findGlobalVersions({
|
||||
global: slug,
|
||||
limit: 1,
|
||||
sort: [{ property: 'updatedAt', direction: 'desc' }],
|
||||
locale,
|
||||
})).docs[0];
|
||||
}
|
||||
|
||||
const global = await (Model as any).findOne(query, {}, { lean }) as Document;
|
||||
const global = await payload.db.findGlobal({
|
||||
slug,
|
||||
where,
|
||||
locale,
|
||||
});
|
||||
const globalExists = Boolean(global);
|
||||
|
||||
if (!latestVersion || (docHasTimestamps(global) && latestVersion.updatedAt < global.updatedAt)) {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { FilterQuery } from 'mongoose';
|
||||
import { Payload } from '../payload';
|
||||
import { SanitizedCollectionConfig, TypeWithID } from '../collections/config/types';
|
||||
import { enforceMaxVersions } from './enforceMaxVersions';
|
||||
@@ -36,9 +35,6 @@ export const saveVersion = async ({
|
||||
if (global) {
|
||||
entityConfig = global;
|
||||
}
|
||||
|
||||
const VersionModel = payload.versions[entityConfig.slug];
|
||||
|
||||
const versionData = { ...doc };
|
||||
if (draft) versionData._status = 'draft';
|
||||
if (versionData._id) delete versionData._id;
|
||||
@@ -48,8 +44,6 @@ export const saveVersion = async ({
|
||||
const now = new Date().toISOString();
|
||||
|
||||
if (autosave) {
|
||||
const query: FilterQuery<unknown> = {};
|
||||
if (collection) query.parent = id;
|
||||
const { docs } = await payload.db.findVersions({
|
||||
collection: entityConfig.slug,
|
||||
limit: 1,
|
||||
@@ -60,7 +54,7 @@ export const saveVersion = async ({
|
||||
},
|
||||
sort: [{
|
||||
property: 'updatedAt',
|
||||
order: 'desc',
|
||||
direction: 'desc',
|
||||
}],
|
||||
});
|
||||
const [latestVersion] = docs;
|
||||
@@ -76,25 +70,27 @@ export const saveVersion = async ({
|
||||
updatedAt: draft ? now : new Date(doc.updatedAt).toISOString(),
|
||||
};
|
||||
|
||||
result = await VersionModel.findByIdAndUpdate(
|
||||
{
|
||||
_id: latestVersion.id,
|
||||
result = await payload.db.updateVersion({
|
||||
collectionSlug: entityConfig.slug,
|
||||
versionData: data,
|
||||
where: {
|
||||
id: {
|
||||
equals: latestVersion.id,
|
||||
},
|
||||
data,
|
||||
{ new: true, lean: true },
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (createNewVersion) {
|
||||
const data: Record<string, unknown> = {
|
||||
result = await payload.db.createVersion({
|
||||
collectionSlug: entityConfig.slug,
|
||||
parent: collection ? id : undefined,
|
||||
autosave: Boolean(autosave),
|
||||
version: versionData,
|
||||
createdAt: doc?.createdAt ? new Date(doc.createdAt).toISOString() : now,
|
||||
updatedAt: draft ? now : new Date(doc.updatedAt).toISOString(),
|
||||
};
|
||||
if (collection) data.parent = id;
|
||||
result = await VersionModel.create(data);
|
||||
versionData,
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
let errorMessage: string;
|
||||
@@ -114,7 +110,6 @@ export const saveVersion = async ({
|
||||
await enforceMaxVersions({
|
||||
id,
|
||||
payload,
|
||||
Model: VersionModel,
|
||||
collection,
|
||||
global,
|
||||
max,
|
||||
|
||||
Reference in New Issue
Block a user