Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 20s
Build & Deploy / 🧪 QA (push) Failing after 34s
Build & Deploy / 🏗️ Build (push) Has started running
Build & Deploy / 🚀 Deploy (push) Has been cancelled
Build & Deploy / 🧪 Smoke Test (push) Has been cancelled
Build & Deploy / ⚡ Lighthouse (push) Has been cancelled
Build & Deploy / 🔔 Notify (push) Has been cancelled
283 lines
12 KiB
Plaintext
283 lines
12 KiB
Plaintext
import { executeAccess } from '../../auth/executeAccess.js';
|
|
import { combineQueries } from '../../database/combineQueries.js';
|
|
import { validateQueryPaths } from '../../database/queryValidation/validateQueryPaths.js';
|
|
import { sanitizeJoinQuery } from '../../database/sanitizeJoinQuery.js';
|
|
import { sanitizeWhereQuery } from '../../database/sanitizeWhereQuery.js';
|
|
import { afterRead } from '../../fields/hooks/afterRead/index.js';
|
|
import { lockedDocumentsCollectionSlug } from '../../locked-documents/config.js';
|
|
import { appendNonTrashedFilter } from '../../utilities/appendNonTrashedFilter.js';
|
|
import { hasDraftsEnabled } from '../../utilities/getVersionsConfig.js';
|
|
import { killTransaction } from '../../utilities/killTransaction.js';
|
|
import { sanitizeSelect } from '../../utilities/sanitizeSelect.js';
|
|
import { buildVersionCollectionFields } from '../../versions/buildCollectionFields.js';
|
|
import { appendVersionToQueryKey } from '../../versions/drafts/appendVersionToQueryKey.js';
|
|
import { getQueryDraftsSelect } from '../../versions/drafts/getQueryDraftsSelect.js';
|
|
import { getQueryDraftsSort } from '../../versions/drafts/getQueryDraftsSort.js';
|
|
import { buildAfterOperation } from './utilities/buildAfterOperation.js';
|
|
import { buildBeforeOperation } from './utilities/buildBeforeOperation.js';
|
|
import { sanitizeSortQuery } from './utilities/sanitizeSortQuery.js';
|
|
const lockDurationDefault = 300 // Default 5 minutes in seconds
|
|
;
|
|
export const findOperation = async (incomingArgs)=>{
|
|
let args = incomingArgs;
|
|
try {
|
|
// /////////////////////////////////////
|
|
// beforeOperation - Collection
|
|
// /////////////////////////////////////
|
|
args = await buildBeforeOperation({
|
|
args,
|
|
collection: args.collection.config,
|
|
operation: 'read',
|
|
overrideAccess: args.overrideAccess
|
|
});
|
|
const { collection: { config: collectionConfig }, collection, currentDepth, depth, disableErrors, draft: draftsEnabled, includeLockStatus: includeLockStatusFromArgs, joins, limit, overrideAccess, page, pagination = true, populate, select: incomingSelect, showHiddenFields, sort: incomingSort, trash = false, where } = args;
|
|
const req = args.req;
|
|
const includeLockStatus = includeLockStatusFromArgs && req.payload.collections?.[lockedDocumentsCollectionSlug];
|
|
const { fallbackLocale, locale, payload } = req;
|
|
const select = sanitizeSelect({
|
|
fields: collectionConfig.flattenedFields,
|
|
forceSelect: collectionConfig.forceSelect,
|
|
select: incomingSelect
|
|
});
|
|
// /////////////////////////////////////
|
|
// Access
|
|
// /////////////////////////////////////
|
|
let accessResult;
|
|
if (!overrideAccess) {
|
|
accessResult = await executeAccess({
|
|
disableErrors,
|
|
req
|
|
}, collectionConfig.access.read);
|
|
// If errors are disabled, and access returns false, return empty results
|
|
if (accessResult === false) {
|
|
return {
|
|
docs: [],
|
|
hasNextPage: false,
|
|
hasPrevPage: false,
|
|
limit: limit,
|
|
nextPage: null,
|
|
page: 1,
|
|
pagingCounter: 1,
|
|
prevPage: null,
|
|
totalDocs: 0,
|
|
totalPages: 1
|
|
};
|
|
}
|
|
}
|
|
// /////////////////////////////////////
|
|
// Find
|
|
// /////////////////////////////////////
|
|
const usePagination = pagination && limit !== 0;
|
|
const sanitizedLimit = limit ?? (usePagination ? 10 : 0);
|
|
const sanitizedPage = page || 1;
|
|
let result;
|
|
let fullWhere = combineQueries(where, accessResult);
|
|
sanitizeWhereQuery({
|
|
fields: collectionConfig.flattenedFields,
|
|
payload,
|
|
where: fullWhere
|
|
});
|
|
// Exclude trashed documents when trash: false
|
|
fullWhere = appendNonTrashedFilter({
|
|
enableTrash: collectionConfig.trash,
|
|
trash,
|
|
where: fullWhere
|
|
});
|
|
const sort = sanitizeSortQuery({
|
|
fields: collection.config.flattenedFields,
|
|
sort: incomingSort
|
|
});
|
|
const sanitizedJoins = await sanitizeJoinQuery({
|
|
collectionConfig,
|
|
joins,
|
|
overrideAccess: overrideAccess,
|
|
req
|
|
});
|
|
if (hasDraftsEnabled(collectionConfig) && draftsEnabled) {
|
|
fullWhere = appendVersionToQueryKey(fullWhere);
|
|
await validateQueryPaths({
|
|
collectionConfig: collection.config,
|
|
overrideAccess: overrideAccess,
|
|
req,
|
|
versionFields: buildVersionCollectionFields(payload.config, collection.config, true),
|
|
where: appendVersionToQueryKey(where)
|
|
});
|
|
result = await payload.db.queryDrafts({
|
|
collection: collectionConfig.slug,
|
|
joins: req.payloadAPI === 'GraphQL' ? false : sanitizedJoins,
|
|
limit: sanitizedLimit,
|
|
locale: locale,
|
|
page: sanitizedPage,
|
|
pagination: usePagination,
|
|
req,
|
|
select: getQueryDraftsSelect({
|
|
select
|
|
}),
|
|
sort: getQueryDraftsSort({
|
|
collectionConfig,
|
|
sort
|
|
}),
|
|
where: fullWhere
|
|
});
|
|
} else {
|
|
await validateQueryPaths({
|
|
collectionConfig,
|
|
overrideAccess: overrideAccess,
|
|
req,
|
|
where: where
|
|
});
|
|
result = await payload.db.find({
|
|
collection: collectionConfig.slug,
|
|
draftsEnabled,
|
|
joins: req.payloadAPI === 'GraphQL' ? false : sanitizedJoins,
|
|
limit: sanitizedLimit,
|
|
locale: locale,
|
|
page: sanitizedPage,
|
|
pagination,
|
|
req,
|
|
select,
|
|
sort,
|
|
where: fullWhere
|
|
});
|
|
}
|
|
// /////////////////////////////////////
|
|
// Add collection property for auth collections
|
|
// /////////////////////////////////////
|
|
if (collectionConfig.auth) {
|
|
result.docs = result.docs.map((doc)=>({
|
|
...doc,
|
|
collection: collectionConfig.slug
|
|
}));
|
|
}
|
|
if (includeLockStatus) {
|
|
try {
|
|
const lockDocumentsProp = collectionConfig?.lockDocuments;
|
|
const lockDuration = typeof lockDocumentsProp === 'object' ? lockDocumentsProp.duration : lockDurationDefault;
|
|
const lockDurationInMilliseconds = lockDuration * 1000;
|
|
const now = new Date().getTime();
|
|
const lockedDocuments = await payload.find({
|
|
collection: lockedDocumentsCollectionSlug,
|
|
depth: 1,
|
|
limit: sanitizedLimit,
|
|
overrideAccess: false,
|
|
pagination: false,
|
|
req,
|
|
where: {
|
|
and: [
|
|
{
|
|
'document.relationTo': {
|
|
equals: collectionConfig.slug
|
|
}
|
|
},
|
|
{
|
|
'document.value': {
|
|
in: result.docs.map((doc)=>doc.id)
|
|
}
|
|
},
|
|
// Query where the lock is newer than the current time minus lock time
|
|
{
|
|
updatedAt: {
|
|
greater_than: new Date(now - lockDurationInMilliseconds)
|
|
}
|
|
}
|
|
]
|
|
}
|
|
});
|
|
const lockedDocs = Array.isArray(lockedDocuments?.docs) ? lockedDocuments.docs : [];
|
|
// Filter out stale locks
|
|
const validLockedDocs = lockedDocs.filter((lock)=>{
|
|
const lastEditedAt = new Date(lock?.updatedAt).getTime();
|
|
return lastEditedAt + lockDurationInMilliseconds > now;
|
|
});
|
|
for (const doc of result.docs){
|
|
const lockedDoc = validLockedDocs.find((lock)=>lock?.document?.value === doc.id);
|
|
doc._isLocked = !!lockedDoc;
|
|
doc._userEditing = lockedDoc ? lockedDoc?.user?.value : null;
|
|
}
|
|
} catch (_err) {
|
|
for (const doc of result.docs){
|
|
doc._isLocked = false;
|
|
doc._userEditing = null;
|
|
}
|
|
}
|
|
}
|
|
// /////////////////////////////////////
|
|
// beforeRead - Collection
|
|
// /////////////////////////////////////
|
|
if (collectionConfig?.hooks?.beforeRead?.length) {
|
|
result.docs = await Promise.all(result.docs.map(async (doc)=>{
|
|
let docRef = doc;
|
|
for (const hook of collectionConfig.hooks.beforeRead){
|
|
docRef = await hook({
|
|
collection: collectionConfig,
|
|
context: req.context,
|
|
doc: docRef,
|
|
overrideAccess: overrideAccess,
|
|
query: fullWhere,
|
|
req
|
|
}) || docRef;
|
|
}
|
|
return docRef;
|
|
}));
|
|
}
|
|
// /////////////////////////////////////
|
|
// afterRead - Fields
|
|
// /////////////////////////////////////
|
|
result.docs = await Promise.all(result.docs.map(async (doc)=>afterRead({
|
|
collection: collectionConfig,
|
|
context: req.context,
|
|
currentDepth,
|
|
depth: depth,
|
|
doc,
|
|
draft: draftsEnabled,
|
|
fallbackLocale: fallbackLocale,
|
|
findMany: true,
|
|
global: null,
|
|
locale: locale,
|
|
overrideAccess: overrideAccess,
|
|
populate,
|
|
req,
|
|
select,
|
|
showHiddenFields: showHiddenFields
|
|
})));
|
|
// /////////////////////////////////////
|
|
// afterRead - Collection
|
|
// /////////////////////////////////////
|
|
if (collectionConfig?.hooks?.afterRead?.length) {
|
|
result.docs = await Promise.all(result.docs.map(async (doc)=>{
|
|
let docRef = doc;
|
|
for (const hook of collectionConfig.hooks.afterRead){
|
|
docRef = await hook({
|
|
collection: collectionConfig,
|
|
context: req.context,
|
|
doc: docRef,
|
|
findMany: true,
|
|
overrideAccess: overrideAccess,
|
|
query: fullWhere,
|
|
req
|
|
}) || docRef;
|
|
}
|
|
return docRef;
|
|
}));
|
|
}
|
|
// /////////////////////////////////////
|
|
// afterOperation - Collection
|
|
// /////////////////////////////////////
|
|
result = await buildAfterOperation({
|
|
args,
|
|
collection: collectionConfig,
|
|
operation: 'find',
|
|
overrideAccess: overrideAccess,
|
|
result
|
|
});
|
|
// /////////////////////////////////////
|
|
// Return results
|
|
// /////////////////////////////////////
|
|
return result;
|
|
} catch (error) {
|
|
await killTransaction(args.req);
|
|
throw error;
|
|
}
|
|
};
|
|
|
|
//# sourceMappingURL=find.js.map |