@tachybase/plugin-full-text-search 0.23.40 → 0.23.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/externalVersion.js +5 -4
- package/dist/server/dialects/FieldBase.d.ts +23 -0
- package/dist/server/dialects/FieldBase.js +116 -0
- package/dist/server/dialects/FieldMariadb.d.ts +11 -0
- package/dist/server/dialects/FieldMariadb.js +88 -0
- package/dist/server/dialects/FieldPostgres.d.ts +10 -0
- package/dist/server/dialects/FieldPostgres.js +79 -0
- package/dist/server/dialects/FieldSqlite.d.ts +15 -0
- package/dist/server/dialects/FieldSqlite.js +83 -0
- package/dist/server/middlewares/search.d.ts +2 -0
- package/dist/server/middlewares/search.js +97 -0
- package/dist/server/plugin.js +6 -222
- package/dist/server/searchField.d.ts +7 -0
- package/dist/server/searchField.js +113 -0
- package/dist/server/types.d.ts +24 -0
- package/dist/server/types.js +15 -0
- package/dist/server/utils.d.ts +2 -0
- package/dist/server/utils.js +41 -0
- package/package.json +9 -7
package/dist/externalVersion.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
module.exports = {
|
|
2
|
-
"@tachybase/client": "0.23.
|
|
2
|
+
"@tachybase/client": "0.23.41",
|
|
3
3
|
"antd": "5.22.5",
|
|
4
4
|
"lodash": "4.17.21",
|
|
5
|
-
"@tachybase/
|
|
6
|
-
"@tachybase/database": "0.23.
|
|
7
|
-
"@tachybase/
|
|
5
|
+
"@tachybase/server": "0.23.41",
|
|
6
|
+
"@tachybase/database": "0.23.41",
|
|
7
|
+
"@tachybase/actions": "0.23.41",
|
|
8
|
+
"sequelize": "6.37.5"
|
|
8
9
|
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { WhereOptions } from 'sequelize';
|
|
2
|
+
import { handleFieldParams } from '../types';
|
|
3
|
+
type NestedRecord<T, K extends string> = K extends `${infer Head}.${infer Tail}` ? {
|
|
4
|
+
[Key in Head]: NestedRecord<T, Tail>;
|
|
5
|
+
} : {
|
|
6
|
+
[Key in K]: T;
|
|
7
|
+
};
|
|
8
|
+
export declare class FieldBase {
|
|
9
|
+
type: string;
|
|
10
|
+
like: symbol;
|
|
11
|
+
likeOperator: string;
|
|
12
|
+
constructor();
|
|
13
|
+
getFormateDateStr(field: string, fieldInfo: any): string;
|
|
14
|
+
date(params: handleFieldParams): any;
|
|
15
|
+
string(params: handleFieldParams): WhereOptions<any> | null;
|
|
16
|
+
number(params: handleFieldParams): WhereOptions<any>;
|
|
17
|
+
json(params: handleFieldParams): any;
|
|
18
|
+
protected convertToObj<T, K extends string>(key: K, value: T): NestedRecord<T, K>;
|
|
19
|
+
getMultiSelectFilter(field: string, matchEnum: string[]): WhereOptions<any>;
|
|
20
|
+
array(params: handleFieldParams): WhereOptions<any>;
|
|
21
|
+
private getMatchEnum;
|
|
22
|
+
}
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
+
var FieldBase_exports = {};
|
|
19
|
+
__export(FieldBase_exports, {
|
|
20
|
+
FieldBase: () => FieldBase
|
|
21
|
+
});
|
|
22
|
+
module.exports = __toCommonJS(FieldBase_exports);
|
|
23
|
+
var import_database = require("@tachybase/database");
|
|
24
|
+
var import_sequelize = require("sequelize");
|
|
25
|
+
var import_utils = require("../utils");
|
|
26
|
+
class FieldBase {
|
|
27
|
+
type = "";
|
|
28
|
+
like = import_database.Op.like;
|
|
29
|
+
likeOperator = "LIKE";
|
|
30
|
+
constructor() {
|
|
31
|
+
}
|
|
32
|
+
getFormateDateStr(field, fieldInfo) {
|
|
33
|
+
return "YYYY-MM-DD HH:mm:ss";
|
|
34
|
+
}
|
|
35
|
+
date(params) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
string(params) {
|
|
39
|
+
var _a, _b;
|
|
40
|
+
const { field, fields, keyword } = params;
|
|
41
|
+
const fieldInfo = fields.get(field);
|
|
42
|
+
if (((_b = (_a = fieldInfo == null ? void 0 : fieldInfo.options) == null ? void 0 : _a.uiSchema) == null ? void 0 : _b["x-component"]) === "Select") {
|
|
43
|
+
const matchEnum = this.getMatchEnum(fieldInfo, keyword);
|
|
44
|
+
if (!matchEnum.length) {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
return this.convertToObj(field, { [import_database.Op.in]: matchEnum });
|
|
48
|
+
}
|
|
49
|
+
return this.convertToObj(field, { [this.like]: `%${(0, import_utils.escapeLike)(keyword)}%` });
|
|
50
|
+
}
|
|
51
|
+
number(params) {
|
|
52
|
+
const { field, keyword } = params;
|
|
53
|
+
return {
|
|
54
|
+
[import_database.Op.and]: [
|
|
55
|
+
(0, import_database.where)(
|
|
56
|
+
(0, import_database.literal)(`CAST(${(0, import_sequelize.col)(field).col} AS TEXT)`),
|
|
57
|
+
// 确保不加引号,直接插入 SQL 表达式
|
|
58
|
+
{
|
|
59
|
+
[import_database.Op.like]: `%${(0, import_utils.escapeLike)(keyword)}%`
|
|
60
|
+
}
|
|
61
|
+
)
|
|
62
|
+
]
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
json(params) {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
// a.b.c = xxx 转成 { a: { b: { c: 'xxx' } } }
|
|
69
|
+
convertToObj(key, value) {
|
|
70
|
+
const MAX_DEPTH = 3;
|
|
71
|
+
const parts = key.split(".");
|
|
72
|
+
if (parts.length > MAX_DEPTH) {
|
|
73
|
+
throw new Error(`Maximum nesting depth of ${MAX_DEPTH} exceeded`);
|
|
74
|
+
}
|
|
75
|
+
const newKey = parts.shift();
|
|
76
|
+
if (!newKey) {
|
|
77
|
+
throw new Error("Invalid key");
|
|
78
|
+
}
|
|
79
|
+
if (!parts.length) {
|
|
80
|
+
return { [newKey]: value };
|
|
81
|
+
}
|
|
82
|
+
return { [newKey]: this.convertToObj(parts.join("."), value) };
|
|
83
|
+
}
|
|
84
|
+
// 多选框如何生成filter
|
|
85
|
+
getMultiSelectFilter(field, matchEnum) {
|
|
86
|
+
return this.convertToObj(field, { [import_database.Op.contains]: matchEnum });
|
|
87
|
+
}
|
|
88
|
+
array(params) {
|
|
89
|
+
var _a, _b;
|
|
90
|
+
const { field, keyword, fields } = params;
|
|
91
|
+
const fieldInfo = fields.get(field);
|
|
92
|
+
if (((_b = (_a = fieldInfo == null ? void 0 : fieldInfo.options) == null ? void 0 : _a.uiSchema) == null ? void 0 : _b["x-component"]) === "Select") {
|
|
93
|
+
const matchEnum = this.getMatchEnum(fieldInfo, keyword);
|
|
94
|
+
if (!matchEnum.length) {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
return this.getMultiSelectFilter(field, matchEnum);
|
|
98
|
+
}
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
getMatchEnum(fieldInfo, keyword) {
|
|
102
|
+
const matchEnum = [];
|
|
103
|
+
const enumList = (fieldInfo == null ? void 0 : fieldInfo.options.uiSchema.enum) || [];
|
|
104
|
+
const lowerKeyword = keyword.toLowerCase();
|
|
105
|
+
for (const item of enumList) {
|
|
106
|
+
if (typeof (item == null ? void 0 : item.label) === "string" && item.label.toLowerCase().includes(lowerKeyword)) {
|
|
107
|
+
matchEnum.push(item.value);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return matchEnum;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
114
|
+
0 && (module.exports = {
|
|
115
|
+
FieldBase
|
|
116
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { WhereOptions } from 'sequelize';
|
|
2
|
+
import { handleFieldParams } from '../types';
|
|
3
|
+
import { FieldBase } from './FieldBase';
|
|
4
|
+
export declare class FieldMariadb extends FieldBase {
|
|
5
|
+
type: string;
|
|
6
|
+
getFormateDateStr(field: string, fieldInfo: any): string;
|
|
7
|
+
number(params: handleFieldParams): WhereOptions<any>;
|
|
8
|
+
date(params: handleFieldParams): WhereOptions<any>;
|
|
9
|
+
json(params: handleFieldParams): WhereOptions<any>;
|
|
10
|
+
getMultiSelectFilter(field: string, matchEnum: string[]): WhereOptions<any>;
|
|
11
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
+
var FieldMariadb_exports = {};
|
|
19
|
+
__export(FieldMariadb_exports, {
|
|
20
|
+
FieldMariadb: () => FieldMariadb
|
|
21
|
+
});
|
|
22
|
+
module.exports = __toCommonJS(FieldMariadb_exports);
|
|
23
|
+
var import_database = require("@tachybase/database");
|
|
24
|
+
var import_sequelize = require("sequelize");
|
|
25
|
+
var import_utils = require("../utils");
|
|
26
|
+
var import_FieldBase = require("./FieldBase");
|
|
27
|
+
class FieldMariadb extends import_FieldBase.FieldBase {
|
|
28
|
+
type = "mariadb";
|
|
29
|
+
getFormateDateStr(field, fieldInfo) {
|
|
30
|
+
var _a, _b, _c, _d;
|
|
31
|
+
let formatStr = "%Y-%m-%d";
|
|
32
|
+
if ((_d = (_c = (_b = (_a = fieldInfo == null ? void 0 : fieldInfo.get(field)) == null ? void 0 : _a.options) == null ? void 0 : _b.uiSchema) == null ? void 0 : _c["x-component-props"]) == null ? void 0 : _d.dateFormat) {
|
|
33
|
+
const props = fieldInfo.get(field).options.uiSchema["x-component-props"];
|
|
34
|
+
formatStr = props.dateFormat.replace("YYYY", "%Y").replace("MM", "%m").replace("DD", "%d");
|
|
35
|
+
if (props.showTime) {
|
|
36
|
+
if (props.timeFormat.endsWith(" a")) {
|
|
37
|
+
formatStr += " %I:%i:%s %p";
|
|
38
|
+
} else {
|
|
39
|
+
formatStr += " %H:%i:%s";
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return formatStr;
|
|
44
|
+
}
|
|
45
|
+
number(params) {
|
|
46
|
+
const { field, keyword } = params;
|
|
47
|
+
return {
|
|
48
|
+
[import_database.Op.and]: [
|
|
49
|
+
(0, import_database.where)(
|
|
50
|
+
(0, import_database.literal)(`CAST(${(0, import_sequelize.col)(field).col} AS CHAR)`),
|
|
51
|
+
// 确保不加引号,直接插入 SQL 表达式
|
|
52
|
+
{
|
|
53
|
+
[import_database.Op.like]: `%${(0, import_utils.escapeLike)(keyword)}%`
|
|
54
|
+
}
|
|
55
|
+
)
|
|
56
|
+
]
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
date(params) {
|
|
60
|
+
const { field, keyword, dateStr, timezone } = params;
|
|
61
|
+
return {
|
|
62
|
+
[import_database.Op.and]: [
|
|
63
|
+
(0, import_database.where)((0, import_database.fn)("DATE_FORMAT", (0, import_database.fn)("CONVERT_TZ", (0, import_sequelize.col)(field), "+00:00", timezone), dateStr), {
|
|
64
|
+
[this.like]: `%${(0, import_utils.escapeLike)(keyword)}%`
|
|
65
|
+
})
|
|
66
|
+
]
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
json(params) {
|
|
70
|
+
const { field, keyword } = params;
|
|
71
|
+
return {
|
|
72
|
+
[import_database.Op.and]: [
|
|
73
|
+
(0, import_database.where)((0, import_database.literal)(`JSON_UNQUOTE(JSON_EXTRACT(${field}, '$'))`), {
|
|
74
|
+
[import_database.Op.like]: `%${(0, import_utils.escapeLike)(keyword)}%`
|
|
75
|
+
})
|
|
76
|
+
]
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
getMultiSelectFilter(field, matchEnum) {
|
|
80
|
+
return {
|
|
81
|
+
[import_database.Op.and]: [(0, import_database.literal)(`JSON_CONTAINS(${(0, import_sequelize.col)(field).col}, '${JSON.stringify(matchEnum)}')`)]
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
86
|
+
0 && (module.exports = {
|
|
87
|
+
FieldMariadb
|
|
88
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { handleFieldParams } from '../types';
|
|
2
|
+
import { FieldBase } from './FieldBase';
|
|
3
|
+
export declare class FieldPostgres extends FieldBase {
|
|
4
|
+
type: string;
|
|
5
|
+
like: symbol;
|
|
6
|
+
likeOperator: string;
|
|
7
|
+
getFormateDateStr(field: string, fieldInfo: any): string;
|
|
8
|
+
date(params: handleFieldParams): any;
|
|
9
|
+
json(params: handleFieldParams): any;
|
|
10
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
+
var FieldPostgres_exports = {};
|
|
19
|
+
__export(FieldPostgres_exports, {
|
|
20
|
+
FieldPostgres: () => FieldPostgres
|
|
21
|
+
});
|
|
22
|
+
module.exports = __toCommonJS(FieldPostgres_exports);
|
|
23
|
+
var import_database = require("@tachybase/database");
|
|
24
|
+
var import_sequelize = require("sequelize");
|
|
25
|
+
var import_utils = require("../utils");
|
|
26
|
+
var import_FieldBase = require("./FieldBase");
|
|
27
|
+
class FieldPostgres extends import_FieldBase.FieldBase {
|
|
28
|
+
type = "postgres";
|
|
29
|
+
like = import_database.Op.iLike;
|
|
30
|
+
likeOperator = "ILIKE";
|
|
31
|
+
getFormateDateStr(field, fieldInfo) {
|
|
32
|
+
var _a, _b, _c, _d;
|
|
33
|
+
let formatStr = "YYYY-MM-DD HH:mm:ss";
|
|
34
|
+
if ((_d = (_c = (_b = (_a = fieldInfo == null ? void 0 : fieldInfo.get(field)) == null ? void 0 : _a.options) == null ? void 0 : _b.uiSchema) == null ? void 0 : _c["x-component-props"]) == null ? void 0 : _d.dateFormat) {
|
|
35
|
+
const props = fieldInfo.get(field).options.uiSchema["x-component-props"];
|
|
36
|
+
formatStr = props.dateFormat;
|
|
37
|
+
if (props.showTime) {
|
|
38
|
+
formatStr += props.timeFormat.endsWith(" a") ? " HH12:MI:SS" : " HH24:MI:SS";
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return formatStr;
|
|
42
|
+
}
|
|
43
|
+
date(params) {
|
|
44
|
+
const { field, keyword, dateStr, timezone } = params;
|
|
45
|
+
return {
|
|
46
|
+
[import_database.Op.and]: [
|
|
47
|
+
(0, import_database.where)(
|
|
48
|
+
(0, import_database.fn)(
|
|
49
|
+
"TO_CHAR",
|
|
50
|
+
(0, import_database.fn)(
|
|
51
|
+
"TIMEZONE",
|
|
52
|
+
timezone,
|
|
53
|
+
// 参数1:目标时区
|
|
54
|
+
(0, import_database.fn)("TIMEZONE", "UTC", (0, import_sequelize.col)(field))
|
|
55
|
+
// 参数2:UTC 转换后的字段
|
|
56
|
+
),
|
|
57
|
+
dateStr
|
|
58
|
+
// 参数3:格式化字符串
|
|
59
|
+
),
|
|
60
|
+
{
|
|
61
|
+
[import_database.Op.like]: `%${(0, import_utils.escapeLike)(keyword)}%`
|
|
62
|
+
}
|
|
63
|
+
)
|
|
64
|
+
]
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
json(params) {
|
|
68
|
+
const { field, keyword } = params;
|
|
69
|
+
return this.convertToObj(field, {
|
|
70
|
+
["::text"]: {
|
|
71
|
+
[this.like]: `%${(0, import_utils.escapeLike)(keyword)}%`
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
77
|
+
0 && (module.exports = {
|
|
78
|
+
FieldPostgres
|
|
79
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Op } from '@tachybase/database';
|
|
2
|
+
import { WhereOptions } from 'sequelize';
|
|
3
|
+
import { handleFieldParams } from '../types';
|
|
4
|
+
import { FieldBase } from './FieldBase';
|
|
5
|
+
export declare class FieldSqlite extends FieldBase {
|
|
6
|
+
type: string;
|
|
7
|
+
getFormateDateStr(field: string, fieldInfo: any): string;
|
|
8
|
+
date(params: handleFieldParams): {
|
|
9
|
+
[Op.and]: any[];
|
|
10
|
+
};
|
|
11
|
+
json(params: handleFieldParams): {
|
|
12
|
+
[Op.and]: any[];
|
|
13
|
+
};
|
|
14
|
+
getMultiSelectFilter(field: string, matchEnum: string[]): WhereOptions<any>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
+
var FieldSqlite_exports = {};
|
|
19
|
+
__export(FieldSqlite_exports, {
|
|
20
|
+
FieldSqlite: () => FieldSqlite
|
|
21
|
+
});
|
|
22
|
+
module.exports = __toCommonJS(FieldSqlite_exports);
|
|
23
|
+
var import_database = require("@tachybase/database");
|
|
24
|
+
var import_sequelize = require("sequelize");
|
|
25
|
+
var import_utils = require("../utils");
|
|
26
|
+
var import_FieldBase = require("./FieldBase");
|
|
27
|
+
class FieldSqlite extends import_FieldBase.FieldBase {
|
|
28
|
+
type = "sqlite";
|
|
29
|
+
getFormateDateStr(field, fieldInfo) {
|
|
30
|
+
var _a, _b, _c, _d;
|
|
31
|
+
let formatStr = "%Y-%m-%d";
|
|
32
|
+
if ((_d = (_c = (_b = (_a = fieldInfo == null ? void 0 : fieldInfo.get(field)) == null ? void 0 : _a.options) == null ? void 0 : _b.uiSchema) == null ? void 0 : _c["x-component-props"]) == null ? void 0 : _d.dateFormat) {
|
|
33
|
+
const props = fieldInfo.get(field).options.uiSchema["x-component-props"];
|
|
34
|
+
formatStr = props.dateFormat.replace("YYYY", "%Y").replace("MM", "%m").replace("DD", "%d");
|
|
35
|
+
if (props.showTime) {
|
|
36
|
+
if (props.timeFormat.endsWith(" a")) {
|
|
37
|
+
formatStr += " %I:%M:%S %p";
|
|
38
|
+
} else {
|
|
39
|
+
formatStr += " %H:%M:%S";
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return formatStr;
|
|
44
|
+
}
|
|
45
|
+
date(params) {
|
|
46
|
+
const { field, keyword, dateStr, timezone } = params;
|
|
47
|
+
return {
|
|
48
|
+
[import_database.Op.and]: [
|
|
49
|
+
(0, import_database.where)((0, import_database.fn)("strftime", dateStr, (0, import_database.fn)("datetime", (0, import_sequelize.col)(field), (0, import_utils.convertTimezoneOffset)(timezone))), {
|
|
50
|
+
[this.like]: `%${(0, import_utils.escapeLike)(keyword)}%`
|
|
51
|
+
})
|
|
52
|
+
]
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
json(params) {
|
|
56
|
+
const { field, keyword } = params;
|
|
57
|
+
return {
|
|
58
|
+
[import_database.Op.and]: [
|
|
59
|
+
(0, import_database.where)((0, import_database.literal)(`json_extract(${field}, '$')`), {
|
|
60
|
+
[this.like]: `%${(0, import_utils.escapeLike)(keyword)}%`
|
|
61
|
+
})
|
|
62
|
+
]
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
getMultiSelectFilter(field, matchEnum) {
|
|
66
|
+
const matchList = matchEnum.map((value) => `'${value}'`).join(",");
|
|
67
|
+
return {
|
|
68
|
+
[import_database.Op.and]: [
|
|
69
|
+
(0, import_database.literal)(`
|
|
70
|
+
EXISTS (
|
|
71
|
+
SELECT 1
|
|
72
|
+
FROM json_each(${(0, import_sequelize.col)(field).col})
|
|
73
|
+
WHERE json_each.value IN (${matchList})
|
|
74
|
+
)
|
|
75
|
+
`)
|
|
76
|
+
]
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
81
|
+
0 && (module.exports = {
|
|
82
|
+
FieldSqlite
|
|
83
|
+
});
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
+
var search_exports = {};
|
|
19
|
+
__export(search_exports, {
|
|
20
|
+
searchMiddleware: () => searchMiddleware
|
|
21
|
+
});
|
|
22
|
+
module.exports = __toCommonJS(search_exports);
|
|
23
|
+
var import_constants = require("../../constants");
|
|
24
|
+
var import_FieldMariadb = require("../dialects/FieldMariadb");
|
|
25
|
+
var import_FieldPostgres = require("../dialects/FieldPostgres");
|
|
26
|
+
var import_FieldSqlite = require("../dialects/FieldSqlite");
|
|
27
|
+
var import_searchField = require("../searchField");
|
|
28
|
+
function getDialect(dbType) {
|
|
29
|
+
const handlers = {
|
|
30
|
+
postgres: () => new import_FieldPostgres.FieldPostgres(),
|
|
31
|
+
mysql: () => new import_FieldMariadb.FieldMariadb(),
|
|
32
|
+
// TODO: 考虑mysql5.7的兼容性
|
|
33
|
+
mariadb: () => new import_FieldMariadb.FieldMariadb(),
|
|
34
|
+
sqlite: () => new import_FieldSqlite.FieldSqlite()
|
|
35
|
+
};
|
|
36
|
+
const handler = handlers[dbType];
|
|
37
|
+
if (!handler) {
|
|
38
|
+
throw new Error(`Unsupported database type: ${dbType}`);
|
|
39
|
+
}
|
|
40
|
+
return handler();
|
|
41
|
+
}
|
|
42
|
+
async function searchMiddleware(ctx, next) {
|
|
43
|
+
var _a, _b, _c;
|
|
44
|
+
const params = ctx.action.params;
|
|
45
|
+
if ((_a = params.search) == null ? void 0 : _a.keywords) {
|
|
46
|
+
params.search.keywords = params.search.keywords.map((v) => v.trim()).filter((v) => v);
|
|
47
|
+
}
|
|
48
|
+
if (!((_c = (_b = params.search) == null ? void 0 : _b.keywords) == null ? void 0 : _c.length)) {
|
|
49
|
+
return next();
|
|
50
|
+
}
|
|
51
|
+
if (params.search.keywords.length > import_constants.SEARCH_KEYWORDS_MAX) {
|
|
52
|
+
ctx.throw(400, `keywords max length is ${import_constants.SEARCH_KEYWORDS_MAX}`);
|
|
53
|
+
}
|
|
54
|
+
let fields = [];
|
|
55
|
+
const collection = ctx.db.getCollection(ctx.action.resourceName);
|
|
56
|
+
if (params.search.fields && !params.search.isSearchAllFields) {
|
|
57
|
+
fields = params.search.fields;
|
|
58
|
+
} else {
|
|
59
|
+
fields = [...collection.fields.keys()];
|
|
60
|
+
}
|
|
61
|
+
const dbType = ctx.db.sequelize.getDialect();
|
|
62
|
+
const handler = getDialect(dbType);
|
|
63
|
+
const timezone = ctx.get("X-Timezone") || "+00:00";
|
|
64
|
+
const searchFilterList = [];
|
|
65
|
+
for (const field of fields) {
|
|
66
|
+
searchFilterList.push(
|
|
67
|
+
...(0, import_searchField.processField)({
|
|
68
|
+
field,
|
|
69
|
+
handler,
|
|
70
|
+
collection,
|
|
71
|
+
ctx,
|
|
72
|
+
search: params.search,
|
|
73
|
+
timezone
|
|
74
|
+
})
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
if (!searchFilterList.length) {
|
|
78
|
+
return next();
|
|
79
|
+
}
|
|
80
|
+
const searchFilter = { $or: searchFilterList };
|
|
81
|
+
if (params.filter && Object.keys(params.filter).length) {
|
|
82
|
+
if (Array.isArray(params.filter.$and)) {
|
|
83
|
+
params.filter.$and.push(searchFilter);
|
|
84
|
+
} else {
|
|
85
|
+
params.filter = {
|
|
86
|
+
$and: [params.filter, searchFilter]
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
} else {
|
|
90
|
+
params.filter = searchFilter;
|
|
91
|
+
}
|
|
92
|
+
await next();
|
|
93
|
+
}
|
|
94
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
95
|
+
0 && (module.exports = {
|
|
96
|
+
searchMiddleware
|
|
97
|
+
});
|
package/dist/server/plugin.js
CHANGED
|
@@ -21,235 +21,19 @@ __export(plugin_exports, {
|
|
|
21
21
|
default: () => plugin_default
|
|
22
22
|
});
|
|
23
23
|
module.exports = __toCommonJS(plugin_exports);
|
|
24
|
-
var import_database = require("@tachybase/database");
|
|
25
24
|
var import_server = require("@tachybase/server");
|
|
26
|
-
var
|
|
27
|
-
function escapeLike(value) {
|
|
28
|
-
return value.replace(/[_%]/g, "\\$&");
|
|
29
|
-
}
|
|
30
|
-
const stringFields = ["string", "text", "sequence", "uid", "integer", "float"];
|
|
31
|
-
const numberFields = ["bigInt", "double"];
|
|
32
|
-
const dateFields = ["date", "datetime", "timestamp"];
|
|
33
|
-
const jsonFields = ["json", "jsonb"];
|
|
34
|
-
function getCollectionField(collection, fieldStr, db) {
|
|
35
|
-
if (!fieldStr.includes(".")) {
|
|
36
|
-
return {
|
|
37
|
-
collection,
|
|
38
|
-
fieldStr
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
const parts = fieldStr.split(".");
|
|
42
|
-
const associationTable = parts.shift();
|
|
43
|
-
const fields = collection.getFields();
|
|
44
|
-
const foreignField = fields.find((v) => v.name === associationTable);
|
|
45
|
-
const nextCollection = db.getCollection(foreignField.target);
|
|
46
|
-
const nextField = parts.join(".");
|
|
47
|
-
return getCollectionField(nextCollection, nextField, db);
|
|
48
|
-
}
|
|
49
|
-
function handleJsonQuery(field, dbType, keyword) {
|
|
50
|
-
if (dbType === "postgres") {
|
|
51
|
-
return (0, import_database.where)(
|
|
52
|
-
(0, import_database.literal)(`${field}->>0`),
|
|
53
|
-
// Assuming the key is '0', adjust for your actual key
|
|
54
|
-
{
|
|
55
|
-
[import_database.Op.iLike]: `%${escapeLike(keyword)}%`
|
|
56
|
-
}
|
|
57
|
-
);
|
|
58
|
-
} else if (dbType === "mysql") {
|
|
59
|
-
return (0, import_database.where)((0, import_database.literal)(`JSON_UNQUOTE(JSON_EXTRACT(${field}, '$'))`), {
|
|
60
|
-
[import_database.Op.like]: `%${escapeLike(keyword)}%`
|
|
61
|
-
});
|
|
62
|
-
} else if (dbType === "sqlite") {
|
|
63
|
-
return (0, import_database.where)((0, import_database.literal)(`json_extract(${field}, '$')`), {
|
|
64
|
-
[import_database.Op.like]: `%${escapeLike(keyword)}%`
|
|
65
|
-
});
|
|
66
|
-
} else {
|
|
67
|
-
return field;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
function convertTimezoneOffset(offset) {
|
|
71
|
-
const regex = /^([+-])(\d{2}):(\d{2})$/;
|
|
72
|
-
const match = offset.match(regex);
|
|
73
|
-
if (match) {
|
|
74
|
-
const sign = match[1];
|
|
75
|
-
const hours = parseInt(match[2], 10);
|
|
76
|
-
return `${sign}${hours} hours`;
|
|
77
|
-
}
|
|
78
|
-
return offset;
|
|
79
|
-
}
|
|
80
|
-
function getRealFieldFilter(field, value) {
|
|
81
|
-
const parts = field.split(".");
|
|
82
|
-
const key = parts.shift();
|
|
83
|
-
if (!parts.length) {
|
|
84
|
-
return { [key]: value };
|
|
85
|
-
}
|
|
86
|
-
return { [key]: getRealFieldFilter(parts.join("."), value) };
|
|
87
|
-
}
|
|
25
|
+
var import_search = require("./middlewares/search");
|
|
88
26
|
class PluginFullTextSearchServer extends import_server.Plugin {
|
|
89
27
|
async afterAdd() {
|
|
90
28
|
}
|
|
91
29
|
async beforeLoad() {
|
|
92
30
|
}
|
|
93
31
|
async load() {
|
|
94
|
-
this.app.resourcer.use(
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
}
|
|
100
|
-
const params = ctx.action.params;
|
|
101
|
-
if ((_a = params.search) == null ? void 0 : _a.keywords) {
|
|
102
|
-
params.search.keywords = params.search.keywords.map((v) => v.trim()).filter((v) => v);
|
|
103
|
-
}
|
|
104
|
-
if (!((_c = (_b = params.search) == null ? void 0 : _b.keywords) == null ? void 0 : _c.length)) {
|
|
105
|
-
return next();
|
|
106
|
-
}
|
|
107
|
-
if (params.search.keywords.length > import_constants.SEARCH_KEYWORDS_MAX) {
|
|
108
|
-
ctx.throw(500, `keywords max length is ${import_constants.SEARCH_KEYWORDS_MAX}`);
|
|
109
|
-
}
|
|
110
|
-
let fields = [];
|
|
111
|
-
const collection = ctx.db.getCollection(ctx.action.resourceName);
|
|
112
|
-
const fieldsAll = collection.fields;
|
|
113
|
-
if (params.search.fields && !params.search.isSearchAllFields) {
|
|
114
|
-
fields = params.search.fields;
|
|
115
|
-
} else {
|
|
116
|
-
fields = [...collection.fields.keys()];
|
|
117
|
-
}
|
|
118
|
-
const utcOffset = ctx.get("X-Timezone") || "+00:00";
|
|
119
|
-
const dbType = ctx.db.sequelize.getDialect();
|
|
120
|
-
const searchFilter = fields.reduce((acc, field) => {
|
|
121
|
-
var _a2, _b2, _c2, _d, _e;
|
|
122
|
-
let type;
|
|
123
|
-
let fieldName;
|
|
124
|
-
let fieldInfo;
|
|
125
|
-
if (!field.includes(".")) {
|
|
126
|
-
fieldName = dbType === "postgres" ? `"${ctx.action.resourceName}"."${field}"` : `\`${collection.name}\`.\`${field}\``;
|
|
127
|
-
fieldInfo = fieldsAll;
|
|
128
|
-
type = (_a2 = fieldInfo.get(field)) == null ? void 0 : _a2.type;
|
|
129
|
-
} else {
|
|
130
|
-
const { collection: targetCollection, fieldStr } = getCollectionField(collection, field, ctx.db);
|
|
131
|
-
fieldInfo = targetCollection.fields;
|
|
132
|
-
type = (_b2 = fieldInfo.get(fieldStr)) == null ? void 0 : _b2.type;
|
|
133
|
-
fieldName = dbType === "postgres" ? `"${targetCollection.name}"."${fieldStr}"` : `\`${targetCollection.name}\`.\`${fieldStr}\``;
|
|
134
|
-
fieldInfo = fieldsAll;
|
|
135
|
-
}
|
|
136
|
-
if (stringFields.includes(type)) {
|
|
137
|
-
for (const keyword of params.search.keywords) {
|
|
138
|
-
const filterCondition = getRealFieldFilter(field, {
|
|
139
|
-
[dbType === "postgres" ? import_database.Op.iLike : import_database.Op.like]: `%${escapeLike(keyword)}%`
|
|
140
|
-
});
|
|
141
|
-
acc.push(filterCondition);
|
|
142
|
-
}
|
|
143
|
-
} else if (numberFields.includes(type)) {
|
|
144
|
-
if (field.includes(".")) {
|
|
145
|
-
return acc;
|
|
146
|
-
}
|
|
147
|
-
let castFunction = "";
|
|
148
|
-
if (dbType === "mysql") {
|
|
149
|
-
castFunction = `CAST(${fieldName} AS CHAR)`;
|
|
150
|
-
} else {
|
|
151
|
-
castFunction = `CAST(${fieldName} AS TEXT)`;
|
|
152
|
-
}
|
|
153
|
-
const searchList = [];
|
|
154
|
-
for (const keyword of params.search.keywords) {
|
|
155
|
-
searchList.push(
|
|
156
|
-
(0, import_database.where)(
|
|
157
|
-
(0, import_database.literal)(castFunction),
|
|
158
|
-
// 将 BIGINT 转换为字符串
|
|
159
|
-
{
|
|
160
|
-
// 根据数据库类型选择 LIKE 或 ILIKE
|
|
161
|
-
[dbType === "postgres" ? import_database.Op.iLike : import_database.Op.like]: `%${escapeLike(keyword)}%`
|
|
162
|
-
}
|
|
163
|
-
)
|
|
164
|
-
);
|
|
165
|
-
}
|
|
166
|
-
acc.push({
|
|
167
|
-
[import_database.Op.or]: searchList
|
|
168
|
-
});
|
|
169
|
-
} else if (dateFields.includes(type)) {
|
|
170
|
-
if (field.includes(".")) {
|
|
171
|
-
return acc;
|
|
172
|
-
}
|
|
173
|
-
let formatStr = "YYYY-MM-DD HH:mm:ss";
|
|
174
|
-
const info = fieldInfo.get(field);
|
|
175
|
-
const searchList = [];
|
|
176
|
-
if ((_e = (_d = (_c2 = info == null ? void 0 : info.options) == null ? void 0 : _c2.uiSchema) == null ? void 0 : _d["x-component-props"]) == null ? void 0 : _e.dateFormat) {
|
|
177
|
-
const props = info.options.uiSchema["x-component-props"];
|
|
178
|
-
if (dbType === "postgres") {
|
|
179
|
-
formatStr = props.dateFormat;
|
|
180
|
-
if (props.showTime) {
|
|
181
|
-
if (props.timeFormat.endsWith(" a")) {
|
|
182
|
-
formatStr += " HH12:MI:SS";
|
|
183
|
-
} else {
|
|
184
|
-
formatStr += " HH24:MI:SS";
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
} else if (dbType === "mysql") {
|
|
188
|
-
formatStr = props.dateFormat.replace("YYYY", "%Y").replace("MM", "%m").replace("DD", "%d");
|
|
189
|
-
if (props.showTime) {
|
|
190
|
-
if (props.timeFormat.endsWith(" a")) {
|
|
191
|
-
formatStr += " %I:%i:%s %p";
|
|
192
|
-
} else {
|
|
193
|
-
formatStr += " %H:%i:%s";
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
} else if (dbType === "sqlite") {
|
|
197
|
-
formatStr = props.dateFormat.replace("YYYY", "%Y").replace("MM", "%m").replace("DD", "%d");
|
|
198
|
-
if (props.showTime) {
|
|
199
|
-
if (props.timeFormat.endsWith(" a")) {
|
|
200
|
-
formatStr += " %I:%M:%S %p";
|
|
201
|
-
} else {
|
|
202
|
-
formatStr += " %H:%M:%S";
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
for (const keyword of params.search.keywords) {
|
|
208
|
-
const condition = dbType === "postgres" ? (0, import_database.literal)(`TO_CHAR((${fieldName} AT TIME ZONE 'UTC') AT TIME ZONE '${utcOffset}', '${formatStr}')`) : dbType === "mysql" ? (0, import_database.fn)("DATE_FORMAT", (0, import_database.fn)("CONVERT_TZ", fieldName, "+00:00", utcOffset), formatStr) : dbType === "sqlite" ? (0, import_database.fn)("strftime", formatStr, (0, import_database.fn)("datetime", fieldName, convertTimezoneOffset(utcOffset))) : fieldName;
|
|
209
|
-
searchList.push(
|
|
210
|
-
(0, import_database.where)(condition, {
|
|
211
|
-
[dbType === "postgres" ? import_database.Op.iLike : import_database.Op.like]: `%${escapeLike(keyword)}%`
|
|
212
|
-
})
|
|
213
|
-
);
|
|
214
|
-
}
|
|
215
|
-
acc.push({
|
|
216
|
-
[import_database.Op.or]: searchList
|
|
217
|
-
});
|
|
218
|
-
} else if (jsonFields.includes(type)) {
|
|
219
|
-
if (field.includes(".")) {
|
|
220
|
-
return acc;
|
|
221
|
-
}
|
|
222
|
-
const searchList = [];
|
|
223
|
-
for (const keyword of params.search.keywords) {
|
|
224
|
-
searchList.push(handleJsonQuery(fieldName, dbType, keyword));
|
|
225
|
-
}
|
|
226
|
-
acc.push({
|
|
227
|
-
[import_database.Op.or]: searchList
|
|
228
|
-
});
|
|
229
|
-
}
|
|
230
|
-
return acc;
|
|
231
|
-
}, []);
|
|
232
|
-
if (searchFilter.length) {
|
|
233
|
-
if (params.filter && Object.keys(params.filter).length) {
|
|
234
|
-
if (params.filter.$and) {
|
|
235
|
-
params.filter.$and.push({ $or: searchFilter });
|
|
236
|
-
} else {
|
|
237
|
-
params.filter = {
|
|
238
|
-
$and: [params.filter, { $or: searchFilter }]
|
|
239
|
-
};
|
|
240
|
-
}
|
|
241
|
-
} else {
|
|
242
|
-
params.filter = { $or: searchFilter };
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
await next();
|
|
246
|
-
},
|
|
247
|
-
{
|
|
248
|
-
tag: "full-text-search",
|
|
249
|
-
after: "acl",
|
|
250
|
-
before: "parseVariables"
|
|
251
|
-
}
|
|
252
|
-
);
|
|
32
|
+
this.app.resourcer.use(import_search.searchMiddleware, {
|
|
33
|
+
tag: "full-text-search",
|
|
34
|
+
after: "acl",
|
|
35
|
+
before: "parseVariables"
|
|
36
|
+
});
|
|
253
37
|
}
|
|
254
38
|
async install() {
|
|
255
39
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { FieldBase } from './dialects/FieldBase';
|
|
2
|
+
import { ProcessFieldParams } from './types';
|
|
3
|
+
export declare function handleField(handler: FieldBase, func: Function, field: string, fields: Map<string, any>, keywords: string[], extraParams?: {
|
|
4
|
+
timezone?: string;
|
|
5
|
+
dateStr?: string;
|
|
6
|
+
}): any[];
|
|
7
|
+
export declare function processField({ field, handler, collection, ctx, search, timezone }: ProcessFieldParams): any[];
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
+
var searchField_exports = {};
|
|
19
|
+
__export(searchField_exports, {
|
|
20
|
+
handleField: () => handleField,
|
|
21
|
+
processField: () => processField
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(searchField_exports);
|
|
24
|
+
const fieldTypes = {
|
|
25
|
+
string: ["string", "text", "sequence", "uid", "integer", "float"],
|
|
26
|
+
number: ["bigInt", "double"],
|
|
27
|
+
date: ["date", "datetime", "timestamp"],
|
|
28
|
+
json: ["json", "jsonb"],
|
|
29
|
+
array: ["array"]
|
|
30
|
+
};
|
|
31
|
+
function isFieldType(type, fieldType) {
|
|
32
|
+
return fieldTypes[fieldType].includes(type);
|
|
33
|
+
}
|
|
34
|
+
function getCollectionField(collection, fieldStr, db) {
|
|
35
|
+
if (!fieldStr.includes(".")) {
|
|
36
|
+
return {
|
|
37
|
+
collection,
|
|
38
|
+
fieldStr
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
const parts = fieldStr.split(".");
|
|
42
|
+
const associationTable = parts.shift();
|
|
43
|
+
const fields = collection.getFields();
|
|
44
|
+
const foreignField = fields.find((v) => v.name === associationTable);
|
|
45
|
+
if (!foreignField) {
|
|
46
|
+
db.logger.error(`Foreign field '${associationTable}' not found in collection '${collection.name}'`);
|
|
47
|
+
}
|
|
48
|
+
const newCollection = db.getCollection(foreignField.target);
|
|
49
|
+
const newField = parts.join(".");
|
|
50
|
+
return getCollectionField(newCollection, newField, db);
|
|
51
|
+
}
|
|
52
|
+
function handleField(handler, func, field, fields, keywords, extraParams = {}) {
|
|
53
|
+
const conditions = [];
|
|
54
|
+
for (const keyword of keywords) {
|
|
55
|
+
const params = {
|
|
56
|
+
field,
|
|
57
|
+
fields,
|
|
58
|
+
keyword,
|
|
59
|
+
timezone: extraParams.timezone,
|
|
60
|
+
dateStr: extraParams.dateStr
|
|
61
|
+
};
|
|
62
|
+
const condition = func.call(handler, params);
|
|
63
|
+
if (condition) {
|
|
64
|
+
conditions.push(condition);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return conditions;
|
|
68
|
+
}
|
|
69
|
+
function processField({ field, handler, collection, ctx, search, timezone }) {
|
|
70
|
+
var _a, _b, _c, _d;
|
|
71
|
+
let type;
|
|
72
|
+
let fields;
|
|
73
|
+
if (!field.includes(".")) {
|
|
74
|
+
fields = collection.fields;
|
|
75
|
+
type = (_a = fields.get(field)) == null ? void 0 : _a.type;
|
|
76
|
+
} else {
|
|
77
|
+
const { collection: targetCollection, fieldStr } = getCollectionField(collection, field, ctx.db);
|
|
78
|
+
fields = targetCollection.fields;
|
|
79
|
+
type = (_b = fields.get(fieldStr)) == null ? void 0 : _b.type;
|
|
80
|
+
}
|
|
81
|
+
if ((_d = (_c = fields.get(field)) == null ? void 0 : _c.options) == null ? void 0 : _d.isForeignKey) {
|
|
82
|
+
return [];
|
|
83
|
+
}
|
|
84
|
+
if (isFieldType(type, "string")) {
|
|
85
|
+
return handleField(handler, handler.string, field, fields, search.keywords);
|
|
86
|
+
} else if (isFieldType(type, "number")) {
|
|
87
|
+
if (!field.includes(".")) {
|
|
88
|
+
return handleField(handler, handler.number, field, fields, search.keywords);
|
|
89
|
+
}
|
|
90
|
+
} else if (isFieldType(type, "date")) {
|
|
91
|
+
if (!field.includes(".")) {
|
|
92
|
+
const dateStr = handler.getFormateDateStr(field, fields);
|
|
93
|
+
return handleField(handler, handler.date, field, fields, search.keywords, {
|
|
94
|
+
timezone,
|
|
95
|
+
dateStr
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
} else if (isFieldType(type, "json")) {
|
|
99
|
+
if (!field.includes(".")) {
|
|
100
|
+
return handleField(handler, handler.json, field, fields, search.keywords);
|
|
101
|
+
}
|
|
102
|
+
} else if (isFieldType(type, "array")) {
|
|
103
|
+
if (!field.includes(".")) {
|
|
104
|
+
return handleField(handler, handler.array, field, fields, search.keywords);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return [];
|
|
108
|
+
}
|
|
109
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
110
|
+
0 && (module.exports = {
|
|
111
|
+
handleField,
|
|
112
|
+
processField
|
|
113
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Context } from '@tachybase/actions';
|
|
2
|
+
import { Collection } from '@tachybase/database';
|
|
3
|
+
import { FieldBase } from './dialects/FieldBase';
|
|
4
|
+
export type FiledName = string;
|
|
5
|
+
export interface SearchParams {
|
|
6
|
+
keywords?: string[];
|
|
7
|
+
fields?: string[];
|
|
8
|
+
isSearchAllFields?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export interface ProcessFieldParams {
|
|
11
|
+
ctx: Context;
|
|
12
|
+
field: string;
|
|
13
|
+
handler: FieldBase;
|
|
14
|
+
collection: Collection;
|
|
15
|
+
search: SearchParams;
|
|
16
|
+
timezone: string;
|
|
17
|
+
}
|
|
18
|
+
export type handleFieldParams = {
|
|
19
|
+
field: string;
|
|
20
|
+
keyword: string;
|
|
21
|
+
fields: Map<string, any>;
|
|
22
|
+
timezone?: string;
|
|
23
|
+
dateStr?: string;
|
|
24
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __copyProps = (to, from, except, desc) => {
|
|
6
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
7
|
+
for (let key of __getOwnPropNames(from))
|
|
8
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
9
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
10
|
+
}
|
|
11
|
+
return to;
|
|
12
|
+
};
|
|
13
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
14
|
+
var types_exports = {};
|
|
15
|
+
module.exports = __toCommonJS(types_exports);
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
+
var utils_exports = {};
|
|
19
|
+
__export(utils_exports, {
|
|
20
|
+
convertTimezoneOffset: () => convertTimezoneOffset,
|
|
21
|
+
escapeLike: () => escapeLike
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(utils_exports);
|
|
24
|
+
function escapeLike(value) {
|
|
25
|
+
return value.replace(/[_%]/g, "\\$&");
|
|
26
|
+
}
|
|
27
|
+
function convertTimezoneOffset(utcOffset) {
|
|
28
|
+
if (!/^[+-]?\d{2}:\d{2}$/.test(utcOffset)) {
|
|
29
|
+
throw new Error("Invalid UTC offset format. Expected format: (+/-)HH:MM");
|
|
30
|
+
}
|
|
31
|
+
const parts = utcOffset.split(":");
|
|
32
|
+
const hours = parseInt(parts[0].replace("+", ""), 10);
|
|
33
|
+
const minutes = parseInt(parts[1], 10);
|
|
34
|
+
const totalMinutes = hours * 60 + (hours >= 0 ? minutes : -minutes);
|
|
35
|
+
return `${totalMinutes} minutes`;
|
|
36
|
+
}
|
|
37
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
38
|
+
0 && (module.exports = {
|
|
39
|
+
convertTimezoneOffset,
|
|
40
|
+
escapeLike
|
|
41
|
+
});
|
package/package.json
CHANGED
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tachybase/plugin-full-text-search",
|
|
3
|
-
"version": "0.23.
|
|
3
|
+
"version": "0.23.41",
|
|
4
4
|
"description": "Provides full text search capability",
|
|
5
5
|
"main": "dist/server/index.js",
|
|
6
6
|
"devDependencies": {
|
|
7
|
+
"@types/sequelize": "^4.28.20",
|
|
7
8
|
"antd": "5.22.5",
|
|
8
|
-
"lodash": "4.17.21"
|
|
9
|
+
"lodash": "4.17.21",
|
|
10
|
+
"sequelize": "^6.37.5"
|
|
9
11
|
},
|
|
10
12
|
"peerDependencies": {
|
|
11
|
-
"@tachybase/actions": "0.23.
|
|
12
|
-
"@tachybase/
|
|
13
|
-
"@tachybase/
|
|
14
|
-
"@tachybase/
|
|
15
|
-
"@tachybase/
|
|
13
|
+
"@tachybase/actions": "0.23.41",
|
|
14
|
+
"@tachybase/client": "0.23.41",
|
|
15
|
+
"@tachybase/database": "0.23.41",
|
|
16
|
+
"@tachybase/test": "0.23.41",
|
|
17
|
+
"@tachybase/server": "0.23.41"
|
|
16
18
|
},
|
|
17
19
|
"description.zh-CN": "提供全字段搜索能力",
|
|
18
20
|
"displayName.zh-CN": "全文搜索"
|