feat: mock server access to plugin mssql import static and compatible mssql function

This commit is contained in:
aaaaaajie 2025-03-30 19:24:28 +08:00
parent c98508d12c
commit 09eda5ffdc
5 changed files with 27 additions and 12 deletions

View File

@ -11,6 +11,7 @@ import {
ColumnDescription, ColumnDescription,
ModelStatic, ModelStatic,
QueryInterface as SequelizeQueryInterface, QueryInterface as SequelizeQueryInterface,
TableName,
Transaction, Transaction,
Transactionable, Transactionable,
} from 'sequelize'; } from 'sequelize';
@ -23,7 +24,7 @@ export type TableInfo = {
}; };
export interface ChangeColumnOptions { export interface ChangeColumnOptions {
tableName: string; tableName: TableName;
schema?: string; schema?: string;
columnName: string; columnName: string;
columnDescription: ColumnDescription; columnDescription: ColumnDescription;

View File

@ -255,7 +255,7 @@ export class SyncRunner {
} else { } else {
await this.database.queryInterface.changeColumn({ await this.database.queryInterface.changeColumn({
actions: ['setDefaultValue'], actions: ['setDefaultValue'],
tableName: this.tableName as string, tableName: this.tableName,
columnDescription: changeAttribute, columnDescription: changeAttribute,
columnName: columnName, columnName: columnName,
model: this.model, model: this.model,

View File

@ -8,7 +8,14 @@
*/ */
import { mockDatabase } from '@nocobase/database'; import { mockDatabase } from '@nocobase/database';
import { Application, ApplicationOptions, AppSupervisor, Gateway, PluginManager } from '@nocobase/server'; import {
Application,
ApplicationOptions,
AppSupervisor,
Gateway,
PluginManager,
runPluginStaticImports,
} from '@nocobase/server';
import { uid } from '@nocobase/utils'; import { uid } from '@nocobase/utils';
import jwt from 'jsonwebtoken'; import jwt from 'jsonwebtoken';
import qs from 'qs'; import qs from 'qs';
@ -223,7 +230,7 @@ export class MockServer extends Application {
} }
} }
export function mockServer(options: ApplicationOptions = {}) { export async function mockServer(options: ApplicationOptions = {}) {
if (typeof TextEncoder === 'undefined') { if (typeof TextEncoder === 'undefined') {
global.TextEncoder = require('util').TextEncoder; global.TextEncoder = require('util').TextEncoder;
} }
@ -231,7 +238,7 @@ export function mockServer(options: ApplicationOptions = {}) {
if (typeof TextDecoder === 'undefined') { if (typeof TextDecoder === 'undefined') {
global.TextDecoder = require('util').TextDecoder; global.TextDecoder = require('util').TextDecoder;
} }
await runPluginStaticImports();
Gateway.getInstance().reset(); Gateway.getInstance().reset();
// AppSupervisor.getInstance().reset(); // AppSupervisor.getInstance().reset();
@ -271,7 +278,7 @@ export function mockServer(options: ApplicationOptions = {}) {
} }
export async function startMockServer(options: ApplicationOptions = {}) { export async function startMockServer(options: ApplicationOptions = {}) {
const app = mockServer(options); const app = await mockServer(options);
await app.runCommand('start'); await app.runCommand('start');
return app; return app;
} }
@ -347,7 +354,7 @@ export async function createMockServer(options: MockServerOptions = {}): Promise
// ignore errors // ignore errors
} }
const { version, beforeInstall, skipInstall, skipStart, ...others } = options; const { version, beforeInstall, skipInstall, skipStart, ...others } = options;
const app: MockServer = mockServer(others); const app: MockServer = await mockServer(others);
if (!skipInstall) { if (!skipInstall) {
if (beforeInstall) { if (beforeInstall) {
await beforeInstall(app); await beforeInstall(app);

View File

@ -92,7 +92,8 @@ export class PluginDataSourceMainServer extends Plugin {
this.app.db.on('collections.beforeCreate', beforeCreateForViewCollection(this.db)); this.app.db.on('collections.beforeCreate', beforeCreateForViewCollection(this.db));
this.app.db.on('collections.beforeCreate', async (model: CollectionModel, options) => { this.app.db.on('collections.beforeCreate', async (model: CollectionModel, options) => {
if (this.app.db.getCollection(model.get('name')) && model.get('from') !== 'db2cm' && !model.get('isThrough')) { const isDB2cm = model.get('from') === 'db2cm' || options.values?.from === 'db2cm';
if (this.app.db.getCollection(model.get('name')) && !isDB2cm && !model.get('isThrough')) {
throw new Error(`Collection named ${model.get('name')} already exists`); throw new Error(`Collection named ${model.get('name')} already exists`);
} }
}); });

View File

@ -731,10 +731,15 @@ export class UiSchemaRepository extends Repository {
} }
if (nodePosition === 'last') { if (nodePosition === 'last') {
let isNull = 'ifnull';
const dialect = this.database.sequelize.getDialect();
if (dialect === 'postgres') {
isNull = 'coalesce';
} else if (dialect === 'mssql') {
isNull = 'ISNULL';
}
const maxSort = await db.sequelize.query( const maxSort = await db.sequelize.query(
`SELECT ${ `SELECT ${isNull}(MAX(TreeTable.sort), 0) as maxsort FROM ${treeTable} as TreeTable
this.database.sequelize.getDialect() === 'postgres' ? 'coalesce' : 'ifnull'
}(MAX(TreeTable.sort), 0) as maxsort FROM ${treeTable} as TreeTable
LEFT JOIN ${treeTable} as NodeInfo LEFT JOIN ${treeTable} as NodeInfo
ON NodeInfo.descendant = TreeTable.descendant and NodeInfo.depth = 0 ON NodeInfo.descendant = TreeTable.descendant and NodeInfo.depth = 0
WHERE TreeTable.depth = 1 AND TreeTable.ancestor = :ancestor and NodeInfo.type = :type`, WHERE TreeTable.depth = 1 AND TreeTable.ancestor = :ancestor and NodeInfo.type = :type`,
@ -1085,6 +1090,7 @@ WHERE TreeTable.depth = 1 AND TreeTable.ancestor = :ancestor and TreeTable.sort
const db = this.database; const db = this.database;
const treeTable = this.uiSchemaTreePathTableName; const treeTable = this.uiSchemaTreePathTableName;
const isNotTrue = this.database.options.dialect === 'mssql' ? '1' : 'true';
const rawSql = ` const rawSql = `
SELECT "SchemaTable"."x-uid" as "x-uid", "SchemaTable"."name" as name, "SchemaTable"."schema" as "schema" , SELECT "SchemaTable"."x-uid" as "x-uid", "SchemaTable"."name" as name, "SchemaTable"."schema" as "schema" ,
@ -1095,7 +1101,7 @@ WHERE TreeTable.depth = 1 AND TreeTable.ancestor = :ancestor and TreeTable.sort
LEFT JOIN ${treeTable} as NodeInfo ON NodeInfo.descendant = "SchemaTable"."x-uid" and NodeInfo.descendant = NodeInfo.ancestor and NodeInfo.depth = 0 LEFT JOIN ${treeTable} as NodeInfo ON NodeInfo.descendant = "SchemaTable"."x-uid" and NodeInfo.descendant = NodeInfo.ancestor and NodeInfo.depth = 0
LEFT JOIN ${treeTable} as ParentPath ON (ParentPath.descendant = "SchemaTable"."x-uid" AND ParentPath.depth = 1) LEFT JOIN ${treeTable} as ParentPath ON (ParentPath.descendant = "SchemaTable"."x-uid" AND ParentPath.depth = 1)
WHERE TreePath.ancestor = :ancestor ${ WHERE TreePath.ancestor = :ancestor ${
options?.includeAsyncNode ? '' : 'AND (NodeInfo.async != true or TreePath.depth = 0)' options?.includeAsyncNode ? '' : `AND (NodeInfo.async != ${isNotTrue} or TreePath.depth = 0)`
} }
`; `;