mirror of
https://github.com/strapi/strapi.git
synced 2025-09-26 00:39:49 +00:00
chore: rename doc service
This commit is contained in:
parent
cb1114d267
commit
83318fb940
@ -65,7 +65,7 @@ import getNumberOfDynamicZones from './services/utils/dynamic-zones';
|
|||||||
import convertCustomFieldType from './utils/convert-custom-field-type';
|
import convertCustomFieldType from './utils/convert-custom-field-type';
|
||||||
import { transformContentTypesToModels } from './utils/transform-content-types-to-models';
|
import { transformContentTypesToModels } from './utils/transform-content-types-to-models';
|
||||||
import { FeaturesService, createFeaturesService } from './services/features';
|
import { FeaturesService, createFeaturesService } from './services/features';
|
||||||
import { createDocumentEngine } from './services/document-service/document-engine';
|
import { createDocumentService } from './services/document-service/document-service';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolve the working directories based on the instance options.
|
* Resolve the working directories based on the instance options.
|
||||||
@ -152,7 +152,7 @@ class Strapi extends Container implements StrapiI {
|
|||||||
|
|
||||||
entityService?: EntityService.EntityService;
|
entityService?: EntityService.EntityService;
|
||||||
|
|
||||||
documents?: Documents.Repository;
|
documents?: Documents.Service;
|
||||||
|
|
||||||
telemetry: TelemetryService;
|
telemetry: TelemetryService;
|
||||||
|
|
||||||
@ -512,7 +512,7 @@ class Strapi extends Container implements StrapiI {
|
|||||||
entityValidator: this.entityValidator,
|
entityValidator: this.entityValidator,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.documents = createDocumentEngine(this);
|
this.documents = createDocumentService(this);
|
||||||
|
|
||||||
if (this.config.get('server.cron.enabled', true)) {
|
if (this.config.get('server.cron.enabled', true)) {
|
||||||
const cronTasks = this.config.get('server.cron.tasks', {});
|
const cronTasks = this.config.get('server.cron.tasks', {});
|
||||||
|
@ -1,159 +1,300 @@
|
|||||||
import { Strapi, Common, Documents } from '@strapi/types';
|
import type { Database } from '@strapi/database';
|
||||||
import createDocumentRepository from './document-repository';
|
import type { Common, Documents, Schema, Shared, Strapi } from '@strapi/types';
|
||||||
import createMiddlewareManager from './middlewares';
|
import { contentTypes as contentTypesUtils, convertQueryParams, mapAsync } from '@strapi/utils';
|
||||||
import { loadDefaultMiddlewares } from './middlewares/defaults';
|
|
||||||
|
import { isArray, omit } from 'lodash/fp';
|
||||||
|
import uploadFiles from '../utils/upload-files';
|
||||||
|
|
||||||
|
import {
|
||||||
|
cloneComponents,
|
||||||
|
createComponents,
|
||||||
|
deleteComponents,
|
||||||
|
getComponents,
|
||||||
|
omitComponentData,
|
||||||
|
updateComponents,
|
||||||
|
} from '../entity-service/components';
|
||||||
|
|
||||||
|
import { createDocumentId } from '../../utils/transform-content-types-to-models';
|
||||||
|
import { applyTransforms } from '../entity-service/attributes';
|
||||||
|
import entityValidator from '../entity-validator';
|
||||||
|
import { pickSelectionParams } from './params';
|
||||||
|
|
||||||
|
const { transformParamsToQuery } = convertQueryParams;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Repository to :
|
* TODO: Sanitization / validation built-in
|
||||||
* - Access documents via actions (findMany, findOne, create, update, delete, ...)
|
* TODO: i18n - Move logic to i18n package
|
||||||
* - Execute middlewares on document actions
|
* TODO: Webhooks
|
||||||
* - Apply default parameters to document actions
|
* TODO: Audit logs
|
||||||
*
|
* TODO: Entity Validation - Uniqueness across same locale and publication status
|
||||||
* @param strapi
|
* TODO: File upload
|
||||||
* @param options.defaults - Default parameters to apply to all actions
|
* TODO: replace 'any'
|
||||||
* @param options.parent - Parent repository, used when creating a new repository with .with()
|
* TODO: availableLocales
|
||||||
* @returns DocumentRepository
|
|
||||||
*
|
|
||||||
* @example Access documents
|
|
||||||
* const article = strapi.documents('api::article.article').create(params)
|
|
||||||
* const allArticles = strapi.documents('api::article.article').findMany(params)
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
export const createDocumentEngine = (
|
type Context = {
|
||||||
strapi: Strapi,
|
contentType: Schema.ContentType;
|
||||||
{ defaults = {} }: { defaults?: any } = {}
|
};
|
||||||
): Documents.Engine => {
|
|
||||||
const documents = createDocumentRepository({ strapi, db: strapi.db! });
|
const createPipeline = (data: Record<string, unknown>, context: Context) => {
|
||||||
|
return applyTransforms(data, context);
|
||||||
const middlewareManager = createMiddlewareManager();
|
};
|
||||||
loadDefaultMiddlewares(middlewareManager);
|
|
||||||
|
const updatePipeline = (data: Record<string, unknown>, context: Context) => {
|
||||||
function create<TContentTypeUID extends Common.UID.ContentType>(
|
return applyTransforms(data, context);
|
||||||
uid: TContentTypeUID
|
};
|
||||||
): Documents.EngineInstance<TContentTypeUID> {
|
|
||||||
return {
|
const createDocumentEngine = ({
|
||||||
async findMany(params = {} as any) {
|
strapi,
|
||||||
return strapi.db?.transaction?.(async () =>
|
db,
|
||||||
middlewareManager.run({ action: 'findMany', uid, params, options: {} }, ({ params }) =>
|
}: {
|
||||||
documents.findMany(uid, params)
|
strapi: Strapi;
|
||||||
)
|
db: Database;
|
||||||
);
|
}): Documents.Engine => ({
|
||||||
},
|
uploadFiles,
|
||||||
|
|
||||||
async findFirst(params = {} as any) {
|
async findMany(uid, params) {
|
||||||
return strapi.db?.transaction?.(async () =>
|
const { kind } = strapi.getModel(uid);
|
||||||
middlewareManager.run({ action: 'findFirst', uid, params, options: {} }, ({ params }) =>
|
|
||||||
documents.findFirst(uid, params)
|
const query = transformParamsToQuery(uid, params || ({} as any));
|
||||||
)
|
query.where = { ...params?.lookup, ...query.where };
|
||||||
);
|
|
||||||
},
|
if (kind === 'singleType') {
|
||||||
|
return db.query(uid).findOne(query);
|
||||||
async findOne(id: string, params = {} as any) {
|
}
|
||||||
return strapi.db?.transaction?.(async () =>
|
|
||||||
middlewareManager.run({ action: 'findOne', uid, params, options: { id } }, ({ params }) =>
|
return db.query(uid).findMany(query);
|
||||||
documents.findOne(uid, id, params)
|
},
|
||||||
)
|
|
||||||
);
|
async findFirst(uid, params) {
|
||||||
},
|
const query = transformParamsToQuery(uid, params || ({} as any));
|
||||||
|
|
||||||
async delete(id: string, params = {} as any) {
|
return db.query(uid).findOne({ ...query, where: { ...params?.lookup, ...query.where } });
|
||||||
return strapi.db?.transaction?.(async () =>
|
},
|
||||||
middlewareManager.run({ action: 'delete', uid, params, options: { id } }, ({ params }) =>
|
|
||||||
documents.delete(uid, id, params)
|
async findOne(uid, documentId, params) {
|
||||||
)
|
const query = transformParamsToQuery(uid, params || ({} as any));
|
||||||
);
|
return db
|
||||||
},
|
.query(uid)
|
||||||
|
.findOne({ ...query, where: { ...params?.lookup, ...query.where, documentId } });
|
||||||
async deleteMany(params = {} as any) {
|
},
|
||||||
return strapi.db?.transaction?.(async () =>
|
|
||||||
middlewareManager.run({ action: 'deleteMany', uid, params, options: {} }, ({ params }) =>
|
async delete(uid, documentId, params = {} as any) {
|
||||||
documents.deleteMany(uid, params)
|
const query = transformParamsToQuery(uid, params as any);
|
||||||
)
|
|
||||||
);
|
if (params.status === 'draft') {
|
||||||
},
|
throw new Error('Cannot delete a draft document');
|
||||||
|
}
|
||||||
async create(params = {} as any) {
|
|
||||||
return strapi.db?.transaction?.(async () =>
|
const entriesToDelete = await db.query(uid).findMany({
|
||||||
middlewareManager.run({ action: 'create', uid, params, options: {} }, ({ params }) =>
|
...query,
|
||||||
documents.create(uid, params)
|
where: {
|
||||||
)
|
...params.lookup,
|
||||||
);
|
...query?.where,
|
||||||
},
|
documentId,
|
||||||
|
},
|
||||||
async clone(id: string, params = {} as any) {
|
});
|
||||||
return strapi.db?.transaction?.(async () =>
|
|
||||||
middlewareManager.run({ action: 'clone', uid, params, options: { id } }, ({ params }) =>
|
// Delete all matched entries and its components
|
||||||
documents.clone(uid, id, params)
|
await mapAsync(entriesToDelete, async (entryToDelete: any) => {
|
||||||
)
|
const componentsToDelete = await getComponents(uid, entryToDelete);
|
||||||
);
|
await db.query(uid).delete({ where: { id: entryToDelete.id } });
|
||||||
},
|
await deleteComponents(uid, componentsToDelete as any, { loadComponents: false });
|
||||||
|
});
|
||||||
async update(id: string, params = {} as any) {
|
|
||||||
return strapi.db?.transaction?.(async () =>
|
// TODO: Change return value to actual count
|
||||||
middlewareManager.run({ action: 'update', uid, params, options: { id } }, ({ params }) =>
|
return { versions: entriesToDelete };
|
||||||
documents.update(uid, id, params)
|
},
|
||||||
)
|
|
||||||
);
|
// TODO: should we provide two separate methods?
|
||||||
},
|
async deleteMany(uid, paramsOrIds) {
|
||||||
|
let queryParams;
|
||||||
async count(params = {} as any) {
|
if (isArray(paramsOrIds)) {
|
||||||
return strapi.db?.transaction?.(async () =>
|
queryParams = { filter: { documentID: { $in: paramsOrIds } } };
|
||||||
middlewareManager.run({ action: 'count', uid, params, options: {} }, ({ params }) =>
|
} else {
|
||||||
documents.count(uid, params)
|
queryParams = paramsOrIds;
|
||||||
)
|
}
|
||||||
);
|
|
||||||
},
|
const query = transformParamsToQuery(uid, queryParams || ({} as any));
|
||||||
|
|
||||||
async publish(id: string, params = {} as any) {
|
return db.query(uid).deleteMany(query);
|
||||||
return strapi.db?.transaction?.(async () =>
|
},
|
||||||
middlewareManager.run({ action: 'publish', uid, params, options: { id } }, ({ params }) =>
|
|
||||||
documents.publish(uid, id, params)
|
async create(uid, params) {
|
||||||
)
|
// TODO: Entity validator.
|
||||||
);
|
// TODO: File upload - Probably in the lifecycles?
|
||||||
},
|
const { data } = params;
|
||||||
|
|
||||||
async unpublish(id: string, params = {} as any) {
|
if (!data) {
|
||||||
return strapi.db?.transaction?.(async () =>
|
throw new Error('Create requires data attribute');
|
||||||
middlewareManager.run(
|
}
|
||||||
{ action: 'unpublish', uid, params, options: { id } },
|
|
||||||
({ params }) => documents.unpublish(uid, id, params)
|
const model = strapi.getModel(uid) as Shared.ContentTypes[Common.UID.ContentType];
|
||||||
)
|
|
||||||
);
|
const validData = await entityValidator.validateEntityCreation(model, data, { isDraft: true });
|
||||||
},
|
|
||||||
|
const componentData = await createComponents(uid, validData);
|
||||||
async discardDraft(id: string, params = {} as any) {
|
const entryData = createPipeline(
|
||||||
return strapi.db?.transaction?.(async () =>
|
Object.assign(omitComponentData(model, validData), componentData),
|
||||||
middlewareManager.run(
|
{
|
||||||
{ action: 'discardDraft', uid, params, options: { id } },
|
contentType: model,
|
||||||
({ params }) => documents.discardDraft(uid, id, params)
|
}
|
||||||
)
|
);
|
||||||
);
|
|
||||||
},
|
// select / populate
|
||||||
|
const query = transformParamsToQuery(uid, pickSelectionParams(params) as any);
|
||||||
// @ts-expect-error - TODO: Fix this
|
|
||||||
with(params: object) {
|
return db.query(uid).create({ ...query, data: entryData });
|
||||||
return createDocumentEngine(strapi, {
|
},
|
||||||
defaults: { ...defaults, ...params },
|
|
||||||
})(uid);
|
// NOTE: What happens if user doesn't provide specific publications state and locale to update?
|
||||||
},
|
async update(uid, documentId, params) {
|
||||||
|
// TODO: Prevent updating a published document
|
||||||
use(action, cb, opts) {
|
// TODO: Entity validator.
|
||||||
middlewareManager.add(uid, action, cb, opts);
|
// TODO: File upload
|
||||||
return this;
|
const { data } = params || {};
|
||||||
},
|
const model = strapi.getModel(uid) as Shared.ContentTypes[Common.UID.ContentType];
|
||||||
};
|
|
||||||
}
|
const query = transformParamsToQuery(uid, pickSelectionParams(params || {}) as any);
|
||||||
|
|
||||||
Object.assign(create, {
|
// Find all locales of the document
|
||||||
use(action: any, cb: any, opts?: any) {
|
const entryToUpdate = await db
|
||||||
middlewareManager.add('_all', action, cb, opts);
|
.query(uid)
|
||||||
return create;
|
.findOne({ ...query, where: { ...params?.lookup, ...query?.where, documentId } });
|
||||||
},
|
|
||||||
middlewares: middlewareManager,
|
// Document does not exist
|
||||||
// NOTE : We should do this in a different way, where lifecycles are executed for the different methods
|
if (!entryToUpdate) {
|
||||||
...documents,
|
return null;
|
||||||
});
|
}
|
||||||
|
|
||||||
// @ts-expect-error - TODO: Fix this
|
const validData = await entityValidator.validateEntityUpdate(
|
||||||
return create;
|
model,
|
||||||
|
data,
|
||||||
|
{ isDraft: true }, // Always update the draft version
|
||||||
|
entryToUpdate
|
||||||
|
);
|
||||||
|
|
||||||
|
const componentData = await updateComponents(uid, entryToUpdate, validData);
|
||||||
|
const entryData = updatePipeline(
|
||||||
|
Object.assign(omitComponentData(model, validData), componentData),
|
||||||
|
{ contentType: model }
|
||||||
|
);
|
||||||
|
|
||||||
|
return db.query(uid).update({ ...query, where: { id: entryToUpdate.id }, data: entryData });
|
||||||
|
},
|
||||||
|
|
||||||
|
async count(uid, params = undefined) {
|
||||||
|
const query = transformParamsToQuery(uid, params || ({} as any));
|
||||||
|
query.where = { ...params?.lookup, ...query.where };
|
||||||
|
|
||||||
|
return db.query(uid).count(query);
|
||||||
|
},
|
||||||
|
|
||||||
|
async clone(uid, documentId, params) {
|
||||||
|
// TODO: File upload
|
||||||
|
// TODO: Entity validator.
|
||||||
|
const { data = {} as any } = params!;
|
||||||
|
|
||||||
|
const model = strapi.getModel(uid);
|
||||||
|
const query = transformParamsToQuery(uid, pickSelectionParams(params) as any);
|
||||||
|
|
||||||
|
// Find all locales of the document
|
||||||
|
const entries = await db.query(uid).findMany({
|
||||||
|
...query,
|
||||||
|
where: { ...params?.lookup, ...query.where, documentId },
|
||||||
|
});
|
||||||
|
|
||||||
|
// Document does not exist
|
||||||
|
if (!entries.length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const newDocumentId = createDocumentId();
|
||||||
|
|
||||||
|
const versions = await mapAsync(entries, async (entryToClone: any) => {
|
||||||
|
const isDraft = contentTypesUtils.isDraft(data);
|
||||||
|
// Todo: Merge data with entry to clone
|
||||||
|
const validData = await entityValidator.validateEntityUpdate(
|
||||||
|
model,
|
||||||
|
// Omit id fields, the cloned entity id will be generated by the database
|
||||||
|
omit(['id'], data),
|
||||||
|
{ isDraft },
|
||||||
|
entryToClone
|
||||||
|
);
|
||||||
|
|
||||||
|
const componentData = await cloneComponents(uid, entryToClone, validData);
|
||||||
|
const entityData = createPipeline(
|
||||||
|
Object.assign(omitComponentData(model, validData), componentData),
|
||||||
|
{ contentType: model }
|
||||||
|
);
|
||||||
|
|
||||||
|
// TODO: Transform params to query
|
||||||
|
return db.query(uid).clone(entryToClone.id, {
|
||||||
|
...query,
|
||||||
|
// Allows entityData to override the documentId (e.g. when publishing)
|
||||||
|
data: { documentId: newDocumentId, ...entityData, locale: entryToClone.locale },
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return { id: newDocumentId, versions };
|
||||||
|
},
|
||||||
|
|
||||||
|
// TODO: Handle relations so they target the published version
|
||||||
|
async publish(uid, documentId, params) {
|
||||||
|
// Delete already published versions that match the locales to be published
|
||||||
|
await this.delete(uid, documentId, {
|
||||||
|
...params,
|
||||||
|
lookup: { ...params?.lookup, publishedAt: { $ne: null } },
|
||||||
|
});
|
||||||
|
|
||||||
|
// Clone every draft version to be published
|
||||||
|
const clonedDocuments = (await this.clone(uid, documentId, {
|
||||||
|
...(params || {}),
|
||||||
|
// @ts-expect-error - Generic type does not have publishedAt attribute by default
|
||||||
|
data: { documentId, publishedAt: new Date() },
|
||||||
|
})) as any;
|
||||||
|
|
||||||
|
// TODO: Return actual count
|
||||||
|
return { versions: clonedDocuments?.versions || [] };
|
||||||
|
},
|
||||||
|
|
||||||
|
async unpublish(uid, documentId, params) {
|
||||||
|
// Delete all published versions
|
||||||
|
return this.delete(uid, documentId, {
|
||||||
|
...params,
|
||||||
|
lookup: { ...params?.lookup, publishedAt: { $ne: null } },
|
||||||
|
}) as any;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Steps:
|
||||||
|
* - Delete the matching draft versions (publishedAt = null)
|
||||||
|
* - Clone the matching published versions into draft versions
|
||||||
|
*/
|
||||||
|
async discardDraft(uid, documentId, params) {
|
||||||
|
// Delete draft versions, clone published versions into draft versions
|
||||||
|
await this.delete(uid, documentId, {
|
||||||
|
...params,
|
||||||
|
// Delete all drafts that match query
|
||||||
|
lookup: { ...params?.lookup, publishedAt: null },
|
||||||
|
});
|
||||||
|
|
||||||
|
// Clone published versions into draft versions
|
||||||
|
const clonedDocuments = (await this.clone(uid, documentId, {
|
||||||
|
...(params || {}),
|
||||||
|
// Clone only published versions
|
||||||
|
lookup: { ...params?.lookup, publishedAt: { $ne: null } },
|
||||||
|
// @ts-expect-error - Generic type does not have publishedAt attribute by default
|
||||||
|
data: { documentId, publishedAt: null },
|
||||||
|
})) as any;
|
||||||
|
|
||||||
|
return { versions: clonedDocuments?.versions || [] };
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default (ctx: { strapi: Strapi; db: Database }): Documents.Engine => {
|
||||||
|
const implementation = createDocumentEngine(ctx);
|
||||||
|
|
||||||
|
// TODO: Wrap with database error handling
|
||||||
|
return implementation;
|
||||||
};
|
};
|
||||||
|
@ -1,300 +0,0 @@
|
|||||||
import type { Database } from '@strapi/database';
|
|
||||||
import type { Common, Documents, Schema, Shared, Strapi } from '@strapi/types';
|
|
||||||
import { contentTypes as contentTypesUtils, convertQueryParams, mapAsync } from '@strapi/utils';
|
|
||||||
|
|
||||||
import { isArray, omit } from 'lodash/fp';
|
|
||||||
import uploadFiles from '../utils/upload-files';
|
|
||||||
|
|
||||||
import {
|
|
||||||
cloneComponents,
|
|
||||||
createComponents,
|
|
||||||
deleteComponents,
|
|
||||||
getComponents,
|
|
||||||
omitComponentData,
|
|
||||||
updateComponents,
|
|
||||||
} from '../entity-service/components';
|
|
||||||
|
|
||||||
import { createDocumentId } from '../../utils/transform-content-types-to-models';
|
|
||||||
import { applyTransforms } from '../entity-service/attributes';
|
|
||||||
import entityValidator from '../entity-validator';
|
|
||||||
import { pickSelectionParams } from './params';
|
|
||||||
|
|
||||||
const { transformParamsToQuery } = convertQueryParams;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO: Sanitization / validation built-in
|
|
||||||
* TODO: i18n - Move logic to i18n package
|
|
||||||
* TODO: Webhooks
|
|
||||||
* TODO: Audit logs
|
|
||||||
* TODO: Entity Validation - Uniqueness across same locale and publication status
|
|
||||||
* TODO: File upload
|
|
||||||
* TODO: replace 'any'
|
|
||||||
* TODO: availableLocales
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
type Context = {
|
|
||||||
contentType: Schema.ContentType;
|
|
||||||
};
|
|
||||||
|
|
||||||
const createPipeline = (data: Record<string, unknown>, context: Context) => {
|
|
||||||
return applyTransforms(data, context);
|
|
||||||
};
|
|
||||||
|
|
||||||
const updatePipeline = (data: Record<string, unknown>, context: Context) => {
|
|
||||||
return applyTransforms(data, context);
|
|
||||||
};
|
|
||||||
|
|
||||||
const createDocumentRepository = ({
|
|
||||||
strapi,
|
|
||||||
db,
|
|
||||||
}: {
|
|
||||||
strapi: Strapi;
|
|
||||||
db: Database;
|
|
||||||
}): Documents.Repository => ({
|
|
||||||
uploadFiles,
|
|
||||||
|
|
||||||
async findMany(uid, params) {
|
|
||||||
const { kind } = strapi.getModel(uid);
|
|
||||||
|
|
||||||
const query = transformParamsToQuery(uid, params || ({} as any));
|
|
||||||
query.where = { ...params?.lookup, ...query.where };
|
|
||||||
|
|
||||||
if (kind === 'singleType') {
|
|
||||||
return db.query(uid).findOne(query);
|
|
||||||
}
|
|
||||||
|
|
||||||
return db.query(uid).findMany(query);
|
|
||||||
},
|
|
||||||
|
|
||||||
async findFirst(uid, params) {
|
|
||||||
const query = transformParamsToQuery(uid, params || ({} as any));
|
|
||||||
|
|
||||||
return db.query(uid).findOne({ ...query, where: { ...params?.lookup, ...query.where } });
|
|
||||||
},
|
|
||||||
|
|
||||||
async findOne(uid, documentId, params) {
|
|
||||||
const query = transformParamsToQuery(uid, params || ({} as any));
|
|
||||||
return db
|
|
||||||
.query(uid)
|
|
||||||
.findOne({ ...query, where: { ...params?.lookup, ...query.where, documentId } });
|
|
||||||
},
|
|
||||||
|
|
||||||
async delete(uid, documentId, params = {} as any) {
|
|
||||||
const query = transformParamsToQuery(uid, params as any);
|
|
||||||
|
|
||||||
if (params.status === 'draft') {
|
|
||||||
throw new Error('Cannot delete a draft document');
|
|
||||||
}
|
|
||||||
|
|
||||||
const entriesToDelete = await db.query(uid).findMany({
|
|
||||||
...query,
|
|
||||||
where: {
|
|
||||||
...params.lookup,
|
|
||||||
...query?.where,
|
|
||||||
documentId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// Delete all matched entries and its components
|
|
||||||
await mapAsync(entriesToDelete, async (entryToDelete: any) => {
|
|
||||||
const componentsToDelete = await getComponents(uid, entryToDelete);
|
|
||||||
await db.query(uid).delete({ where: { id: entryToDelete.id } });
|
|
||||||
await deleteComponents(uid, componentsToDelete as any, { loadComponents: false });
|
|
||||||
});
|
|
||||||
|
|
||||||
// TODO: Change return value to actual count
|
|
||||||
return { versions: entriesToDelete };
|
|
||||||
},
|
|
||||||
|
|
||||||
// TODO: should we provide two separate methods?
|
|
||||||
async deleteMany(uid, paramsOrIds) {
|
|
||||||
let queryParams;
|
|
||||||
if (isArray(paramsOrIds)) {
|
|
||||||
queryParams = { filter: { documentID: { $in: paramsOrIds } } };
|
|
||||||
} else {
|
|
||||||
queryParams = paramsOrIds;
|
|
||||||
}
|
|
||||||
|
|
||||||
const query = transformParamsToQuery(uid, queryParams || ({} as any));
|
|
||||||
|
|
||||||
return db.query(uid).deleteMany(query);
|
|
||||||
},
|
|
||||||
|
|
||||||
async create(uid, params) {
|
|
||||||
// TODO: Entity validator.
|
|
||||||
// TODO: File upload - Probably in the lifecycles?
|
|
||||||
const { data } = params;
|
|
||||||
|
|
||||||
if (!data) {
|
|
||||||
throw new Error('Create requires data attribute');
|
|
||||||
}
|
|
||||||
|
|
||||||
const model = strapi.getModel(uid) as Shared.ContentTypes[Common.UID.ContentType];
|
|
||||||
|
|
||||||
const validData = await entityValidator.validateEntityCreation(model, data, { isDraft: true });
|
|
||||||
|
|
||||||
const componentData = await createComponents(uid, validData);
|
|
||||||
const entryData = createPipeline(
|
|
||||||
Object.assign(omitComponentData(model, validData), componentData),
|
|
||||||
{
|
|
||||||
contentType: model,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// select / populate
|
|
||||||
const query = transformParamsToQuery(uid, pickSelectionParams(params));
|
|
||||||
|
|
||||||
return db.query(uid).create({ ...query, data: entryData });
|
|
||||||
},
|
|
||||||
|
|
||||||
// NOTE: What happens if user doesn't provide specific publications state and locale to update?
|
|
||||||
async update(uid, documentId, params) {
|
|
||||||
// TODO: Prevent updating a published document
|
|
||||||
// TODO: Entity validator.
|
|
||||||
// TODO: File upload
|
|
||||||
const { data } = params || {};
|
|
||||||
const model = strapi.getModel(uid) as Shared.ContentTypes[Common.UID.ContentType];
|
|
||||||
|
|
||||||
const query = transformParamsToQuery(uid, pickSelectionParams(params || {}));
|
|
||||||
|
|
||||||
// Find all locales of the document
|
|
||||||
const entryToUpdate = await db
|
|
||||||
.query(uid)
|
|
||||||
.findOne({ ...query, where: { ...params?.lookup, ...query?.where, documentId } });
|
|
||||||
|
|
||||||
// Document does not exist
|
|
||||||
if (!entryToUpdate) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const validData = await entityValidator.validateEntityUpdate(
|
|
||||||
model,
|
|
||||||
data,
|
|
||||||
{ isDraft: true }, // Always update the draft version
|
|
||||||
entryToUpdate
|
|
||||||
);
|
|
||||||
|
|
||||||
const componentData = await updateComponents(uid, entryToUpdate, validData);
|
|
||||||
const entryData = updatePipeline(
|
|
||||||
Object.assign(omitComponentData(model, validData), componentData),
|
|
||||||
{ contentType: model }
|
|
||||||
);
|
|
||||||
|
|
||||||
return db.query(uid).update({ ...query, where: { id: entryToUpdate.id }, data: entryData });
|
|
||||||
},
|
|
||||||
|
|
||||||
async count(uid, params = undefined) {
|
|
||||||
const query = transformParamsToQuery(uid, params || ({} as any));
|
|
||||||
query.where = { ...params?.lookup, ...query.where };
|
|
||||||
|
|
||||||
return db.query(uid).count(query);
|
|
||||||
},
|
|
||||||
|
|
||||||
async clone(uid, documentId, params) {
|
|
||||||
// TODO: File upload
|
|
||||||
// TODO: Entity validator.
|
|
||||||
const { data = {} as any } = params!;
|
|
||||||
|
|
||||||
const model = strapi.getModel(uid);
|
|
||||||
const query = transformParamsToQuery(uid, pickSelectionParams(params));
|
|
||||||
|
|
||||||
// Find all locales of the document
|
|
||||||
const entries = await db.query(uid).findMany({
|
|
||||||
...query,
|
|
||||||
where: { ...params?.lookup, ...query.where, documentId },
|
|
||||||
});
|
|
||||||
|
|
||||||
// Document does not exist
|
|
||||||
if (!entries.length) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const newDocumentId = createDocumentId();
|
|
||||||
|
|
||||||
const versions = await mapAsync(entries, async (entryToClone: any) => {
|
|
||||||
const isDraft = contentTypesUtils.isDraft(data);
|
|
||||||
// Todo: Merge data with entry to clone
|
|
||||||
const validData = await entityValidator.validateEntityUpdate(
|
|
||||||
model,
|
|
||||||
// Omit id fields, the cloned entity id will be generated by the database
|
|
||||||
omit(['id'], data),
|
|
||||||
{ isDraft },
|
|
||||||
entryToClone
|
|
||||||
);
|
|
||||||
|
|
||||||
const componentData = await cloneComponents(uid, entryToClone, validData);
|
|
||||||
const entityData = createPipeline(
|
|
||||||
Object.assign(omitComponentData(model, validData), componentData),
|
|
||||||
{ contentType: model }
|
|
||||||
);
|
|
||||||
|
|
||||||
// TODO: Transform params to query
|
|
||||||
return db.query(uid).clone(entryToClone.id, {
|
|
||||||
...query,
|
|
||||||
// Allows entityData to override the documentId (e.g. when publishing)
|
|
||||||
data: { documentId: newDocumentId, ...entityData, locale: entryToClone.locale },
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return { id: newDocumentId, versions };
|
|
||||||
},
|
|
||||||
|
|
||||||
// TODO: Handle relations so they target the published version
|
|
||||||
async publish(uid, documentId, params) {
|
|
||||||
// Delete already published versions that match the locales to be published
|
|
||||||
await this.delete(uid, documentId, {
|
|
||||||
...params,
|
|
||||||
lookup: { ...params?.lookup, publishedAt: { $ne: null } },
|
|
||||||
});
|
|
||||||
|
|
||||||
// Clone every draft version to be published
|
|
||||||
const clonedDocuments = (await this.clone(uid, documentId, {
|
|
||||||
...(params || {}),
|
|
||||||
// @ts-expect-error - Generic type does not have publishedAt attribute by default
|
|
||||||
data: { documentId, publishedAt: new Date() },
|
|
||||||
})) as any;
|
|
||||||
|
|
||||||
// TODO: Return actual count
|
|
||||||
return { versions: clonedDocuments?.versions || [] };
|
|
||||||
},
|
|
||||||
|
|
||||||
async unpublish(uid, documentId, params) {
|
|
||||||
// Delete all published versions
|
|
||||||
return this.delete(uid, documentId, {
|
|
||||||
...params,
|
|
||||||
lookup: { ...params?.lookup, publishedAt: { $ne: null } },
|
|
||||||
}) as any;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Steps:
|
|
||||||
* - Delete the matching draft versions (publishedAt = null)
|
|
||||||
* - Clone the matching published versions into draft versions
|
|
||||||
*/
|
|
||||||
async discardDraft(uid, documentId, params) {
|
|
||||||
// Delete draft versions, clone published versions into draft versions
|
|
||||||
await this.delete(uid, documentId, {
|
|
||||||
...params,
|
|
||||||
// Delete all drafts that match query
|
|
||||||
lookup: { ...params?.lookup, publishedAt: null },
|
|
||||||
});
|
|
||||||
|
|
||||||
// Clone published versions into draft versions
|
|
||||||
const clonedDocuments = (await this.clone(uid, documentId, {
|
|
||||||
...(params || {}),
|
|
||||||
// Clone only published versions
|
|
||||||
lookup: { ...params?.lookup, publishedAt: { $ne: null } },
|
|
||||||
// @ts-expect-error - Generic type does not have publishedAt attribute by default
|
|
||||||
data: { documentId, publishedAt: null },
|
|
||||||
})) as any;
|
|
||||||
|
|
||||||
return { versions: clonedDocuments?.versions || [] };
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export default (ctx: { strapi: Strapi; db: Database }): Documents.Repository => {
|
|
||||||
const implementation = createDocumentRepository(ctx);
|
|
||||||
|
|
||||||
// TODO: Wrap with database error handling
|
|
||||||
return implementation;
|
|
||||||
};
|
|
@ -0,0 +1,159 @@
|
|||||||
|
import { Strapi, Common, Documents } from '@strapi/types';
|
||||||
|
import createDocumentRepository from './document-engine';
|
||||||
|
import createMiddlewareManager from './middlewares';
|
||||||
|
import { loadDefaultMiddlewares } from './middlewares/defaults';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Repository to :
|
||||||
|
* - Access documents via actions (findMany, findOne, create, update, delete, ...)
|
||||||
|
* - Execute middlewares on document actions
|
||||||
|
* - Apply default parameters to document actions
|
||||||
|
*
|
||||||
|
* @param strapi
|
||||||
|
* @param options.defaults - Default parameters to apply to all actions
|
||||||
|
* @param options.parent - Parent repository, used when creating a new repository with .with()
|
||||||
|
* @returns DocumentService
|
||||||
|
*
|
||||||
|
* @example Access documents
|
||||||
|
* const article = strapi.documents('api::article.article').create(params)
|
||||||
|
* const allArticles = strapi.documents('api::article.article').findMany(params)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export const createDocumentService = (
|
||||||
|
strapi: Strapi,
|
||||||
|
{ defaults = {} }: { defaults?: any } = {}
|
||||||
|
): Documents.Service => {
|
||||||
|
const documents = createDocumentRepository({ strapi, db: strapi.db! });
|
||||||
|
|
||||||
|
const middlewareManager = createMiddlewareManager();
|
||||||
|
loadDefaultMiddlewares(middlewareManager);
|
||||||
|
|
||||||
|
function create<TContentTypeUID extends Common.UID.ContentType>(
|
||||||
|
uid: TContentTypeUID
|
||||||
|
): Documents.ServiceInstance<TContentTypeUID> {
|
||||||
|
return {
|
||||||
|
async findMany(params = {} as any) {
|
||||||
|
return strapi.db?.transaction?.(async () =>
|
||||||
|
middlewareManager.run({ action: 'findMany', uid, params, options: {} }, ({ params }) =>
|
||||||
|
documents.findMany(uid, params)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
async findFirst(params = {} as any) {
|
||||||
|
return strapi.db?.transaction?.(async () =>
|
||||||
|
middlewareManager.run({ action: 'findFirst', uid, params, options: {} }, ({ params }) =>
|
||||||
|
documents.findFirst(uid, params)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
async findOne(id: string, params = {} as any) {
|
||||||
|
return strapi.db?.transaction?.(async () =>
|
||||||
|
middlewareManager.run({ action: 'findOne', uid, params, options: { id } }, ({ params }) =>
|
||||||
|
documents.findOne(uid, id, params)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
async delete(id: string, params = {} as any) {
|
||||||
|
return strapi.db?.transaction?.(async () =>
|
||||||
|
middlewareManager.run({ action: 'delete', uid, params, options: { id } }, ({ params }) =>
|
||||||
|
documents.delete(uid, id, params)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
async deleteMany(params = {} as any) {
|
||||||
|
return strapi.db?.transaction?.(async () =>
|
||||||
|
middlewareManager.run({ action: 'deleteMany', uid, params, options: {} }, ({ params }) =>
|
||||||
|
documents.deleteMany(uid, params)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
async create(params = {} as any) {
|
||||||
|
return strapi.db?.transaction?.(async () =>
|
||||||
|
middlewareManager.run({ action: 'create', uid, params, options: {} }, ({ params }) =>
|
||||||
|
documents.create(uid, params)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
async clone(id: string, params = {} as any) {
|
||||||
|
return strapi.db?.transaction?.(async () =>
|
||||||
|
middlewareManager.run({ action: 'clone', uid, params, options: { id } }, ({ params }) =>
|
||||||
|
documents.clone(uid, id, params)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
async update(id: string, params = {} as any) {
|
||||||
|
return strapi.db?.transaction?.(async () =>
|
||||||
|
middlewareManager.run({ action: 'update', uid, params, options: { id } }, ({ params }) =>
|
||||||
|
documents.update(uid, id, params)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
async count(params = {} as any) {
|
||||||
|
return strapi.db?.transaction?.(async () =>
|
||||||
|
middlewareManager.run({ action: 'count', uid, params, options: {} }, ({ params }) =>
|
||||||
|
documents.count(uid, params)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
async publish(id: string, params = {} as any) {
|
||||||
|
return strapi.db?.transaction?.(async () =>
|
||||||
|
middlewareManager.run({ action: 'publish', uid, params, options: { id } }, ({ params }) =>
|
||||||
|
documents.publish(uid, id, params)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
async unpublish(id: string, params = {} as any) {
|
||||||
|
return strapi.db?.transaction?.(async () =>
|
||||||
|
middlewareManager.run(
|
||||||
|
{ action: 'unpublish', uid, params, options: { id } },
|
||||||
|
({ params }) => documents.unpublish(uid, id, params)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
async discardDraft(id: string, params = {} as any) {
|
||||||
|
return strapi.db?.transaction?.(async () =>
|
||||||
|
middlewareManager.run(
|
||||||
|
{ action: 'discardDraft', uid, params, options: { id } },
|
||||||
|
({ params }) => documents.discardDraft(uid, id, params)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
// @ts-expect-error - TODO: Fix this
|
||||||
|
with(params: object) {
|
||||||
|
return createDocumentService(strapi, {
|
||||||
|
defaults: { ...defaults, ...params },
|
||||||
|
})(uid);
|
||||||
|
},
|
||||||
|
|
||||||
|
use(action, cb, opts) {
|
||||||
|
middlewareManager.add(uid, action, cb, opts);
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.assign(create, {
|
||||||
|
use(action: any, cb: any, opts?: any) {
|
||||||
|
middlewareManager.add('_all', action, cb, opts);
|
||||||
|
return create;
|
||||||
|
},
|
||||||
|
middlewares: middlewareManager,
|
||||||
|
// NOTE : We should do this in a different way, where lifecycles are executed for the different methods
|
||||||
|
...documents,
|
||||||
|
});
|
||||||
|
|
||||||
|
// @ts-expect-error - TODO: Fix this
|
||||||
|
return create;
|
||||||
|
};
|
@ -108,7 +108,7 @@ export interface Strapi extends Container {
|
|||||||
store?: CoreStore;
|
store?: CoreStore;
|
||||||
entityValidator?: EntityValidator;
|
entityValidator?: EntityValidator;
|
||||||
entityService?: EntityService.EntityService;
|
entityService?: EntityService.EntityService;
|
||||||
documents?: Documents.Engine;
|
documents?: Documents.Service;
|
||||||
telemetry: TelemetryService;
|
telemetry: TelemetryService;
|
||||||
requestContext: RequestContext;
|
requestContext: RequestContext;
|
||||||
customFields: CustomFields.CustomFields;
|
customFields: CustomFields.CustomFields;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import type { Common } from '../../types';
|
import type { Common } from '../../types';
|
||||||
import type * as Params from './params/document-repository';
|
import type * as Params from './params/document-engine';
|
||||||
import type * as Result from './result/document-repository';
|
import type * as Result from './result/document-enigne';
|
||||||
|
|
||||||
export type ID = string;
|
export type ID = string;
|
||||||
|
|
||||||
@ -10,7 +10,7 @@ export type UploadFile = (
|
|||||||
files: Record<string, unknown>
|
files: Record<string, unknown>
|
||||||
) => Promise<void>;
|
) => Promise<void>;
|
||||||
|
|
||||||
export interface DocumentRepository {
|
export interface DocumentEngine {
|
||||||
uploadFiles: UploadFile;
|
uploadFiles: UploadFile;
|
||||||
|
|
||||||
findMany<
|
findMany<
|
@ -1,16 +1,16 @@
|
|||||||
import { Common } from '../..';
|
import { Common } from '../..';
|
||||||
import { ID, type DocumentRepository } from './document-repository';
|
import { ID, type DocumentEngine } from './document-engine';
|
||||||
import type * as Middleware from './middleware';
|
import type * as Middleware from './middleware';
|
||||||
import type * as Params from './params/document-repository';
|
import type * as Params from './params/document-engine';
|
||||||
import type * as Result from './result/document-repository';
|
import type * as Result from './result/document-enigne';
|
||||||
|
|
||||||
export { ID, DocumentRepository as Repository } from './document-repository';
|
export { ID, DocumentEngine as Engine } from './document-engine';
|
||||||
export type * as Middleware from './middleware';
|
export type * as Middleware from './middleware';
|
||||||
export * as Params from './params';
|
export * as Params from './params';
|
||||||
export * from './plugin';
|
export * from './plugin';
|
||||||
export * from './result';
|
export * from './result';
|
||||||
|
|
||||||
export type EngineInstance<
|
export type ServiceInstance<
|
||||||
TContentTypeUID extends Common.UID.ContentType = Common.UID.ContentType
|
TContentTypeUID extends Common.UID.ContentType = Common.UID.ContentType
|
||||||
> = {
|
> = {
|
||||||
findMany: <TParams extends Params.FindMany<TContentTypeUID>>(
|
findMany: <TParams extends Params.FindMany<TContentTypeUID>>(
|
||||||
@ -74,7 +74,7 @@ export type EngineInstance<
|
|||||||
* return result;
|
* return result;
|
||||||
* })
|
* })
|
||||||
*/
|
*/
|
||||||
use: <TAction extends keyof DocumentRepository>(
|
use: <TAction extends keyof DocumentEngine>(
|
||||||
action: TAction,
|
action: TAction,
|
||||||
// QUESTION: How do we type the result type of next?
|
// QUESTION: How do we type the result type of next?
|
||||||
// Should we send params + document id attribute?
|
// Should we send params + document id attribute?
|
||||||
@ -82,7 +82,7 @@ export type EngineInstance<
|
|||||||
| Middleware.Middleware<Common.UID.ContentType, TAction>
|
| Middleware.Middleware<Common.UID.ContentType, TAction>
|
||||||
| Middleware.Middleware<Common.UID.ContentType, TAction>[],
|
| Middleware.Middleware<Common.UID.ContentType, TAction>[],
|
||||||
opts?: Middleware.Options
|
opts?: Middleware.Options
|
||||||
) => ThisType<EngineInstance<TContentTypeUID>>;
|
) => ThisType<ServiceInstance<TContentTypeUID>>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* `.with()` instantiates a new document repository with default parameters
|
* `.with()` instantiates a new document repository with default parameters
|
||||||
@ -99,13 +99,13 @@ export type EngineInstance<
|
|||||||
*/
|
*/
|
||||||
with: <TParams extends Params.With<TContentTypeUID>>(
|
with: <TParams extends Params.With<TContentTypeUID>>(
|
||||||
params?: TParams
|
params?: TParams
|
||||||
) => EngineInstance<TContentTypeUID>;
|
) => ServiceInstance<TContentTypeUID>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Engine = {
|
export type Service = {
|
||||||
<TContentTypeUID extends Common.UID.ContentType>(
|
<TContentTypeUID extends Common.UID.ContentType>(
|
||||||
uid: TContentTypeUID
|
uid: TContentTypeUID
|
||||||
): EngineInstance<TContentTypeUID>;
|
): ServiceInstance<TContentTypeUID>;
|
||||||
|
|
||||||
/** Add a middleware for all uid's and a specific action
|
/** Add a middleware for all uid's and a specific action
|
||||||
* @example - Add a default locale
|
* @example - Add a default locale
|
||||||
@ -114,13 +114,13 @@ export type Engine = {
|
|||||||
* return next(ctx)
|
* return next(ctx)
|
||||||
* })
|
* })
|
||||||
*/
|
*/
|
||||||
use: <TAction extends keyof DocumentRepository>(
|
use: <TAction extends keyof DocumentEngine>(
|
||||||
action: TAction,
|
action: TAction,
|
||||||
cb:
|
cb:
|
||||||
| Middleware.Middleware<Common.UID.ContentType, TAction>
|
| Middleware.Middleware<Common.UID.ContentType, TAction>
|
||||||
| Middleware.Middleware<Common.UID.ContentType, TAction>[],
|
| Middleware.Middleware<Common.UID.ContentType, TAction>[],
|
||||||
opts?: Middleware.Options
|
opts?: Middleware.Options
|
||||||
) => Engine;
|
) => Service;
|
||||||
|
|
||||||
middlewares: Middleware.Manager;
|
middlewares: Middleware.Manager;
|
||||||
} & DocumentRepository;
|
} & DocumentEngine;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// Utility type to reuse Param definition in MiddlewareContext
|
// Utility type to reuse Param definition in MiddlewareContext
|
||||||
import { Common } from '../..';
|
import { Common } from '../..';
|
||||||
import { DocumentRepository } from './document-repository';
|
import { DocumentEngine } from './document-engine';
|
||||||
import type * as Params from './params/document-repository';
|
import type * as Params from './params/document-engine';
|
||||||
|
|
||||||
export type ParamsMap<TContentTypeUID extends Common.UID.ContentType = Common.UID.ContentType> = {
|
export type ParamsMap<TContentTypeUID extends Common.UID.ContentType = Common.UID.ContentType> = {
|
||||||
findOne: Params.FindOne<TContentTypeUID>;
|
findOne: Params.FindOne<TContentTypeUID>;
|
||||||
@ -20,7 +20,7 @@ export type ParamsMap<TContentTypeUID extends Common.UID.ContentType = Common.UI
|
|||||||
|
|
||||||
export interface Context<
|
export interface Context<
|
||||||
TContentTypeUID extends Common.UID.ContentType = Common.UID.ContentType,
|
TContentTypeUID extends Common.UID.ContentType = Common.UID.ContentType,
|
||||||
TAction extends keyof DocumentRepository = keyof DocumentRepository
|
TAction extends keyof DocumentEngine = keyof DocumentEngine
|
||||||
> {
|
> {
|
||||||
uid: TContentTypeUID;
|
uid: TContentTypeUID;
|
||||||
action: TAction;
|
action: TAction;
|
||||||
@ -40,11 +40,11 @@ export interface Options {
|
|||||||
|
|
||||||
export type Middleware<
|
export type Middleware<
|
||||||
TContentTypeUID extends Common.UID.ContentType,
|
TContentTypeUID extends Common.UID.ContentType,
|
||||||
TAction extends keyof DocumentRepository
|
TAction extends keyof DocumentEngine
|
||||||
> = (
|
> = (
|
||||||
ctx: Context<TContentTypeUID, TAction>,
|
ctx: Context<TContentTypeUID, TAction>,
|
||||||
next: (ctx: Context<TContentTypeUID, TAction>) => ReturnType<DocumentRepository[TAction]>
|
next: (ctx: Context<TContentTypeUID, TAction>) => ReturnType<DocumentEngine[TAction]>
|
||||||
) => ReturnType<DocumentRepository[TAction]>;
|
) => ReturnType<DocumentEngine[TAction]>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles middlewares for document service
|
* Handles middlewares for document service
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Common, Utils } from '../../..';
|
import { Common, Utils } from '../../..';
|
||||||
import { Result } from '.';
|
import { Result } from '.';
|
||||||
import * as Params from '../params/document-repository';
|
import * as Params from '../params/document-engine';
|
||||||
|
|
||||||
export type CountResult = { count: number };
|
export type CountResult = { count: number };
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user