Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 63 additions & 2 deletions packages/datasource-sequelize/src/collection.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import type { SequelizeDatasourceOptions } from './types';
import type {
ActionResult,
AggregateResult,
Aggregation,
Caller,
Expand Down Expand Up @@ -43,6 +45,7 @@ export default class SequelizeCollection extends BaseCollection {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
model: ModelDefined<any, any>,
logger?: Logger,
options?: SequelizeDatasourceOptions,
) {
if (!model) throw new Error('Invalid (null) model instance.');

Expand All @@ -63,9 +66,9 @@ export default class SequelizeCollection extends BaseCollection {
rawQuery: async (
sql: string,
replacements: Replacements,
options?: { syntax?: 'bind' | 'replacements' },
opts?: { syntax?: 'bind' | 'replacements' },
) => {
const opt = { syntax: 'replacements', ...options };
const opt = { syntax: 'replacements', ...opts };
const result = await model.sequelize.query(sql, {
type: QueryTypes.RAW,
plain: false,
Expand All @@ -89,6 +92,29 @@ export default class SequelizeCollection extends BaseCollection {
this.enableCount();
this.addFields(modelSchema.fields);
this.addSegments(modelSchema.segments);

if (this.model.options.paranoid && options?.actions) {
const { hardDelete, restoreSoftDeleted } = options.actions;

if ((Array.isArray(hardDelete) && hardDelete.includes(name)) || hardDelete === true) {
this.addAction('Hard Delete', {
scope: 'Bulk',
description: 'Permanently deletes selected records',
staticForm: true,
});
}

if (
(Array.isArray(restoreSoftDeleted) && restoreSoftDeleted.includes(name)) ||
restoreSoftDeleted === true
) {
this.addAction('Restore Soft Deleted', {
scope: 'Bulk',
description: 'Restores selected records',
staticForm: true,
});
}
}
}

async create(caller: Caller, data: RecordData[]): Promise<RecordData[]> {
Expand Down Expand Up @@ -226,4 +252,39 @@ export default class SequelizeCollection extends BaseCollection {
!aggregationFieldSchema || aggregationFieldSchema?.columnType === 'Number',
);
}

override async execute(
caller: Caller,
name: string,
formValues: RecordData,
filter?: Filter,
): Promise<ActionResult> {
const options = {
where: await this.queryConverter.getWhereFromConditionTreeToByPassInclude(
filter.conditionTree,
),
};

if (name === 'Hard Delete') {
try {
await handleErrors('delete', () => this.model.destroy({ ...options, force: true }));
} catch (error) {
return { message: error.message, type: 'Error' };
}

return { message: 'Records permanently deleted', type: 'Success', invalidated: new Set() };
}

if (name === 'Restore Soft Deleted') {
try {
await handleErrors('update', () => this.model.restore(options));
} catch (error) {
return { message: error.message, type: 'Error' };
}

return { message: 'Records restored', type: 'Success', invalidated: new Set() };
}

return super.execute(caller, name, formValues, filter);
}
}
10 changes: 7 additions & 3 deletions packages/datasource-sequelize/src/datasource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export default class SequelizeDataSource extends BaseDataSource<SequelizeCollect

this.sequelize = sequelize;

this.createCollections(this.sequelize.models, logger);
this.createCollections(this.sequelize.models, logger, options);

if (options?.liveQueryConnections) {
this.addNativeQueryConnection(options.liveQueryConnections, { instance: this.sequelize });
Expand All @@ -39,12 +39,16 @@ export default class SequelizeDataSource extends BaseDataSource<SequelizeCollect
await this.sequelize.close();
}

protected createCollections(models: Sequelize['models'], logger?: Logger) {
protected createCollections(
models: Sequelize['models'],
logger?: Logger,
options?: SequelizeDatasourceOptions,
) {
Object.values(models)
// avoid schema reordering
.sort((modelA, modelB) => (modelA.name > modelB.name ? 1 : -1))
.forEach(model => {
const collection = new SequelizeCollection(model.name, this, model, logger);
const collection = new SequelizeCollection(model.name, this, model, logger, options);
this.addCollection(collection);
});
}
Expand Down
11 changes: 11 additions & 0 deletions packages/datasource-sequelize/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
export type SequelizeDatasourceOptions = {
liveQueryConnections?: string;
actions?: {
/**
* If true, add an action to restore soft deleted records.
* If an array of strings is provided, add an action to restore soft deleted records only for the specified collections.
*/
restoreSoftDeleted?: boolean | string[];
/** If true, add an action will permanently delete records.
* If an array of strings is provided, add an action to permanently delete records only for the specified collections.
*/
hardDelete?: boolean | string[];
};
};
1 change: 1 addition & 0 deletions packages/datasource-sql/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ export function createSqlDataSource(
return new SqlDatasource(
new SequelizeDataSource(sequelize, logger, {
liveQueryConnections: options?.liveQueryConnections,
actions: options?.actions,
}),
latestIntrospection.views,
);
Expand Down
11 changes: 11 additions & 0 deletions packages/datasource-sql/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,15 @@ export type SqlDatasourceOptions = {
introspection?: SupportedIntrospection;
displaySoftDeleted?: string[] | true;
liveQueryConnections?: string;
actions?: {
/**
* If true, add an action to restore soft deleted records.
* If an array of strings is provided, add an action to restore soft deleted records only for the specified collections.
*/
restoreSoftDeleted?: boolean | string[];
/** If true, add an action will permanently delete records.
* If an array of strings is provided, add an action to permanently delete records only for the specified collections.
*/
hardDelete?: boolean | string[];
};
};
Loading