2024-12-18 19:50:44 +08:00

119 lines
3.5 KiB
TypeScript

/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { Context, Next } from '@nocobase/actions';
import { SQLCollection, SQLModel } from '../sql-collection';
const updateCollection = async (ctx: Context, transaction: any) => {
const { filterByTk, values } = ctx.action.params;
const repo = ctx.db.getRepository('collections');
const collection = await repo.findOne({
filter: {
name: filterByTk,
},
transaction,
});
const existFields = await collection.getFields({ transaction });
const deletedFields = existFields.filter((field: any) => !values.fields?.find((f: any) => f.name === field.name));
for (const field of deletedFields) {
await field.destroy({ transaction });
}
const upRes = await repo.update({
filterByTk,
values: {
...values,
fields: values.fields?.map((f: any) => {
delete f.key;
return f;
}),
},
updateAssociationValues: ['fields'],
transaction,
});
return { collection, upRes };
};
export default {
name: 'sqlCollection',
actions: {
execute: async (ctx: Context, next: Next) => {
let { sql } = ctx.action.params.values || {};
if (!sql) {
ctx.throw(400, ctx.t('Please enter a SQL statement'));
}
sql = sql.trim().split(';').shift();
if (!/^select/i.test(sql) && !/^with([\s\S]+)select([\s\S]+)/i.test(sql)) {
ctx.throw(400, ctx.t('Only supports SELECT statements or WITH clauses'));
}
const tmpCollection = new SQLCollection({ name: 'tmp', sql }, { database: ctx.db });
const model = tmpCollection.model as typeof SQLModel;
// The result is for preview only, add limit clause to avoid too many results
const data = await model.findAll({ attributes: ['*'], limit: 5, raw: true });
let fields: {
[field: string]: {
type: string;
source: string;
collection: string;
interface: string;
};
} = {};
try {
fields = model.inferFields();
} catch (err) {
ctx.logger.warn(`resource: sql-collection, action: execute, error: ${err}`);
fields = {};
}
const sources = Array.from(
new Set(
Object.values(fields)
.map((field) => field.collection)
.filter((c) => c),
),
);
ctx.body = { data, fields, sources };
await next();
},
setFields: async (ctx: Context, next: Next) => {
const transaction = await ctx.app.db.sequelize.transaction();
try {
const {
upRes: [collection],
} = await updateCollection(ctx, transaction);
await collection.loadFields({
transaction,
});
await transaction.commit();
} catch (e) {
await transaction.rollback();
throw e;
}
await next();
},
update: async (ctx: Context, next: Next) => {
const transaction = await ctx.app.db.sequelize.transaction();
try {
const { upRes } = await updateCollection(ctx, transaction);
const [collection] = upRes;
await collection.load({ transaction, resetFields: true });
await transaction.commit();
ctx.body = upRes;
} catch (e) {
await transaction.rollback();
throw e;
}
await next();
},
},
};