mirror of
https://github.com/cool-team-official/cool-admin-midway-packages.git
synced 2025-12-10 13:23:22 +00:00
add elasticsearch
This commit is contained in:
parent
69536b0da1
commit
79e49fea73
11
es/.editorconfig
Normal file
11
es/.editorconfig
Normal file
@ -0,0 +1,11 @@
|
||||
# 🎨 editorconfig.org
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
22
es/.eslintrc.json
Normal file
22
es/.eslintrc.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"extends": "./node_modules/mwts/",
|
||||
"ignorePatterns": ["node_modules", "dist", "test", "jest.config.js", "typings"],
|
||||
"env": {
|
||||
"jest": true
|
||||
},
|
||||
"rules": {
|
||||
"@typescript-eslint/explicit-module-boundary-types": "off",
|
||||
"@typescript-eslint/no-unused-vars": "off",
|
||||
"@typescript-eslint/ban-ts-comment": "off",
|
||||
"node/no-extraneous-import": "off",
|
||||
"@typescript-eslint/no-this-alias": "off",
|
||||
"no-empty": "off",
|
||||
"node/no-extraneous-require": "off",
|
||||
"node/no-unpublished-import": "off",
|
||||
"eqeqeq": "off",
|
||||
"node/no-unsupported-features/node-builtins": "off",
|
||||
"@typescript-eslint/ban-types": "off",
|
||||
"no-control-regex": "off",
|
||||
"prefer-const": "off"
|
||||
}
|
||||
}
|
||||
4
es/.gitattributes
vendored
Normal file
4
es/.gitattributes
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
*.js text eol=lf
|
||||
*.json text eol=lf
|
||||
*.ts text eol=lf
|
||||
*.code-snippets text eol=lf
|
||||
13
es/.gitignore
vendored
Normal file
13
es/.gitignore
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
logs/
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
node_modules/
|
||||
coverage/
|
||||
dist/
|
||||
.idea/
|
||||
run/
|
||||
.DS_Store
|
||||
*.sw*
|
||||
*.un~
|
||||
.tsbuildinfo
|
||||
.tsbuildinfo.*
|
||||
3
es/.prettierrc.js
Normal file
3
es/.prettierrc.js
Normal file
@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
...require('mwts/.prettierrc.json')
|
||||
}
|
||||
13
es/README.md
Normal file
13
es/README.md
Normal file
@ -0,0 +1,13 @@
|
||||
# Cool Admin Node
|
||||
|
||||
cool-admin一个很酷的后台权限管理系统,开源免费,模块化、插件化、极速开发CRUD,方便快速构建迭代后台管理系统,支持serverless、docker、普通服务器等多种方式部署 到 官网 进一步了解。
|
||||
|
||||
[https://cool-js.com](https://cool-js.com)
|
||||
|
||||
## 特性
|
||||
|
||||
- 🔥 **AI 编码** - 从页面到后端代码,部分功能实现零代码
|
||||
- 🎯 **Ai 流程编排** - 专门为 AI 开发设计,几乎无需编码,拖拽即可
|
||||
- 🎨 **扩展插件** - 可插拔式的插件机制,支付、短信等功能可通过后台动态安装卸载
|
||||
- 📦 **代码简洁** - 不同于一般代码生成器生成冗余代码,只需极少编码即可实现大部分需求
|
||||
- 🚀 **微服务支持** - 基于 Moleculer 的微服务架构,支持分布式部署
|
||||
10
es/index.d.ts
vendored
Normal file
10
es/index.d.ts
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
export * from './dist/index';
|
||||
|
||||
declare module '@midwayjs/core/dist/interface' {
|
||||
interface MidwayConfig {
|
||||
book?: PowerPartial<{
|
||||
a: number;
|
||||
b: string;
|
||||
}>;
|
||||
}
|
||||
}
|
||||
7
es/jest.config.js
Normal file
7
es/jest.config.js
Normal file
@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'node',
|
||||
testPathIgnorePatterns: ['<rootDir>/test/fixtures'],
|
||||
coveragePathIgnorePatterns: ['<rootDir>/test/'],
|
||||
setupFilesAfterEnv: ['./jest.setup.js']
|
||||
};
|
||||
1
es/jest.setup.js
Normal file
1
es/jest.setup.js
Normal file
@ -0,0 +1 @@
|
||||
jest.setTimeout(30000);
|
||||
56
es/package.json
Normal file
56
es/package.json
Normal file
@ -0,0 +1,56 @@
|
||||
{
|
||||
"name": "@cool-midway/es",
|
||||
"version": "8.0.0",
|
||||
"description": "cool-js.com elasticsearch",
|
||||
"main": "dist/index.js",
|
||||
"typings": "index.d.ts",
|
||||
"scripts": {
|
||||
"build": "mwtsc --cleanOutDir",
|
||||
"test": "cross-env NODE_ENV=unittest jest",
|
||||
"cov": "jest --coverage",
|
||||
"lint": "mwts check",
|
||||
"lint:fix": "mwts fix"
|
||||
},
|
||||
"keywords": [
|
||||
"cool",
|
||||
"cool-admin",
|
||||
"cooljs"
|
||||
],
|
||||
"author": "COOL",
|
||||
"files": [
|
||||
"dist/**/*.js",
|
||||
"dist/**/*.d.ts",
|
||||
"index.d.ts"
|
||||
],
|
||||
"readme": "README.md",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://cool-js.com"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@cool-midway/core": "8.0.1",
|
||||
"@midwayjs/core": "^3.20.0",
|
||||
"@midwayjs/koa": "^3.20.0",
|
||||
"@midwayjs/logger": "^3.4.2",
|
||||
"@midwayjs/mock": "^3.20.0",
|
||||
"@midwayjs/redis": "^3.20.0",
|
||||
"@midwayjs/typeorm": "^3.20.0",
|
||||
"@types/jest": "^29.5.14",
|
||||
"@types/node": "^22.10.7",
|
||||
"cross-env": "^7.0.3",
|
||||
"jest": "^29.7.0",
|
||||
"lodash": "^4.17.21",
|
||||
"moment": "^2.30.1",
|
||||
"mwts": "^1.3.0",
|
||||
"mwtsc": "^1.15.1",
|
||||
"sqlstring": "^2.3.3",
|
||||
"ts-jest": "^29.2.5",
|
||||
"typeorm": "^0.3.20",
|
||||
"typescript": "^5.7.3",
|
||||
"uuid": "^11.0.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@elastic/elasticsearch": "^8.1.0"
|
||||
}
|
||||
}
|
||||
8161
es/pnpm-lock.yaml
generated
Normal file
8161
es/pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
615
es/src/base.ts
Normal file
615
es/src/base.ts
Normal file
@ -0,0 +1,615 @@
|
||||
import { CoolEventManager } from '@cool-midway/core';
|
||||
import { Client } from '@elastic/elasticsearch';
|
||||
import { WaitForActiveShards } from '@elastic/elasticsearch/lib/api/types';
|
||||
import { Inject, Logger } from '@midwayjs/core';
|
||||
import { ILogger } from '@midwayjs/logger';
|
||||
import { EsConfig } from '.';
|
||||
|
||||
/**
|
||||
* Es索引基类
|
||||
*/
|
||||
export class BaseEsIndex {
|
||||
// 索引
|
||||
public index: string;
|
||||
// es客户端
|
||||
public client: Client;
|
||||
// 日志
|
||||
@Logger()
|
||||
coreLogger: ILogger;
|
||||
// 事件
|
||||
@Inject('cool:coolEventManager')
|
||||
coolEventManager: CoolEventManager;
|
||||
|
||||
/**
|
||||
* 设置索引
|
||||
* @param index
|
||||
*/
|
||||
setIndex(index: string) {
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理es数据变更事件,主要用于同步数据
|
||||
* @param method
|
||||
* @param data
|
||||
*/
|
||||
async handleDataChange(index, method, data) {
|
||||
this.index = index;
|
||||
const {
|
||||
id,
|
||||
ids,
|
||||
bodys,
|
||||
body,
|
||||
type,
|
||||
refresh,
|
||||
waitForActiveShards,
|
||||
properties,
|
||||
config,
|
||||
} = data;
|
||||
switch (method) {
|
||||
case 'upsert':
|
||||
await this.upsert(body, refresh, waitForActiveShards);
|
||||
break;
|
||||
case 'batchIndex':
|
||||
await this.batchIndex(bodys, type, refresh, waitForActiveShards);
|
||||
break;
|
||||
case 'deleteById':
|
||||
await this.deleteById(id, refresh, waitForActiveShards);
|
||||
break;
|
||||
case 'deleteByIds':
|
||||
await this.deleteByIds(ids, refresh, waitForActiveShards);
|
||||
break;
|
||||
case 'deleteByQuery':
|
||||
await this.deleteByQuery(body, refresh, waitForActiveShards);
|
||||
break;
|
||||
case 'updateById':
|
||||
await this.updateById(body, refresh, waitForActiveShards);
|
||||
break;
|
||||
case 'updateByQuery':
|
||||
await this.updateByQuery(body, refresh, waitForActiveShards);
|
||||
break;
|
||||
case 'createIndex':
|
||||
await this.updateByQuery(properties, config);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据更新事件
|
||||
* @param method
|
||||
* @param data
|
||||
*/
|
||||
async esDataChange(method, data) {
|
||||
this.coolEventManager?.emit('esDataChange', this.index, method, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置客户端
|
||||
* @param client
|
||||
*/
|
||||
setClient(client: Client) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
/**
|
||||
* 对象转body
|
||||
* @param condition
|
||||
*/
|
||||
async objToBody(condition: any) {
|
||||
const body = {
|
||||
query: {
|
||||
bool: {
|
||||
must: [],
|
||||
},
|
||||
},
|
||||
};
|
||||
for (const key in condition) {
|
||||
body.query.bool.must.push({
|
||||
term: {
|
||||
[key]: condition[key],
|
||||
},
|
||||
});
|
||||
}
|
||||
return body;
|
||||
}
|
||||
|
||||
/**
|
||||
* 按字段值查找
|
||||
* @param condition
|
||||
* @param size
|
||||
* @returns
|
||||
*/
|
||||
async findBy(condition: any, size?: number) {
|
||||
const body = await this.objToBody(condition);
|
||||
return this.find(body, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按字段值分页查找
|
||||
* @param condition
|
||||
* @param page
|
||||
* @param size
|
||||
*/
|
||||
async findPageBy(condition: any, page?: number, size?: number) {
|
||||
const body = await this.objToBody(condition);
|
||||
return this.findPage(body, page, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询
|
||||
* @param body
|
||||
*/
|
||||
async find(body?: any, size?: number) {
|
||||
if (!body) {
|
||||
body = {};
|
||||
}
|
||||
if (!body.size) {
|
||||
body.size = size ? size : 10000;
|
||||
}
|
||||
return this.client
|
||||
.search({
|
||||
index: this.index,
|
||||
body,
|
||||
})
|
||||
.then(res => {
|
||||
return (
|
||||
res.hits.hits.map(e => {
|
||||
e._source['id'] = e._id;
|
||||
const _source: any = e._source;
|
||||
['_id', '_index', '_score', '_source'].forEach(key => {
|
||||
delete e[key];
|
||||
});
|
||||
return {
|
||||
..._source,
|
||||
...e,
|
||||
};
|
||||
}) || []
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询
|
||||
* @param body
|
||||
* @param page
|
||||
* @param size
|
||||
*/
|
||||
async findPage(body?: any, page?: number, size?: number) {
|
||||
if (!page) {
|
||||
page = 1;
|
||||
}
|
||||
if (!body) {
|
||||
body = {};
|
||||
}
|
||||
if (!size && !body.size) {
|
||||
size = 20;
|
||||
body.size = size;
|
||||
}
|
||||
const total = await this.findCount(body);
|
||||
body.from = (page - 1) * size;
|
||||
return this.client.search({ index: this.index, body }).then(res => {
|
||||
const result =
|
||||
res.hits.hits.map(e => {
|
||||
e._source['id'] = e._id;
|
||||
const _source: any = e._source;
|
||||
['_id', '_index', '_score', '_source'].forEach(key => {
|
||||
delete e[key];
|
||||
});
|
||||
return {
|
||||
..._source,
|
||||
...e,
|
||||
};
|
||||
}) || [];
|
||||
return {
|
||||
list: result,
|
||||
pagination: {
|
||||
page,
|
||||
size,
|
||||
total,
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据ID查询
|
||||
* @param id
|
||||
* @returns
|
||||
*/
|
||||
async findById(id) {
|
||||
return this.client
|
||||
.get({
|
||||
index: this.index,
|
||||
id,
|
||||
})
|
||||
.then(res => {
|
||||
res._source['id'] = res._id;
|
||||
return res._source || undefined;
|
||||
})
|
||||
.catch(e => {
|
||||
return undefined;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据多个ID查询
|
||||
* @param ids
|
||||
* @returns
|
||||
*/
|
||||
async findByIds(ids: string[]) {
|
||||
return this.client
|
||||
.mget({ index: this.index, body: { ids } })
|
||||
.then(res => {
|
||||
const result = res.docs.map((e: any) => {
|
||||
e._source.id = e._id;
|
||||
return e._source || 'undefined';
|
||||
});
|
||||
return result.filter(e => {
|
||||
return e !== 'undefined';
|
||||
});
|
||||
})
|
||||
.catch(e => {
|
||||
return undefined;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 插入与更新
|
||||
* @param body
|
||||
* @param refresh
|
||||
* @param waitForActiveShards
|
||||
* @returns
|
||||
*/
|
||||
async upsert(
|
||||
body: any,
|
||||
refresh?: boolean | 'wait_for',
|
||||
waitForActiveShards?: WaitForActiveShards
|
||||
) {
|
||||
if (refresh == undefined) {
|
||||
refresh = true;
|
||||
}
|
||||
if (body.id) {
|
||||
this.esDataChange('upsert', {
|
||||
body,
|
||||
refresh,
|
||||
waitForActiveShards,
|
||||
});
|
||||
const id = body.id;
|
||||
delete body.id;
|
||||
return this.client.index({
|
||||
id,
|
||||
index: this.index,
|
||||
wait_for_active_shards: waitForActiveShards,
|
||||
refresh,
|
||||
body,
|
||||
});
|
||||
} else {
|
||||
return this.client
|
||||
.index({
|
||||
index: this.index,
|
||||
wait_for_active_shards: waitForActiveShards,
|
||||
refresh,
|
||||
body,
|
||||
})
|
||||
.then(res => {
|
||||
this.esDataChange('upsert', {
|
||||
body: {
|
||||
...body,
|
||||
id: res._id,
|
||||
},
|
||||
refresh,
|
||||
waitForActiveShards,
|
||||
});
|
||||
return res;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量插入更新
|
||||
* @param bodys
|
||||
* @param type
|
||||
* @param refresh
|
||||
* @param waitForActiveShards
|
||||
* @returns
|
||||
*/
|
||||
async batchIndex(
|
||||
bodys: any[],
|
||||
type: 'index' | 'create' | 'delete' | 'update',
|
||||
refresh?: boolean | 'wait_for',
|
||||
waitForActiveShards?: WaitForActiveShards
|
||||
) {
|
||||
this.esDataChange('batchIndex', {
|
||||
bodys,
|
||||
type,
|
||||
refresh,
|
||||
waitForActiveShards,
|
||||
});
|
||||
if (refresh == undefined) {
|
||||
refresh = true;
|
||||
}
|
||||
const list = [];
|
||||
for (const body of bodys) {
|
||||
const typeO = {};
|
||||
typeO[type] = { _index: this.index, _id: body.id };
|
||||
if (body.id) {
|
||||
delete body.id;
|
||||
}
|
||||
list.push(typeO);
|
||||
if (type !== 'delete') {
|
||||
if (type == 'update') {
|
||||
list.push({ doc: body });
|
||||
} else {
|
||||
list.push(body);
|
||||
}
|
||||
}
|
||||
}
|
||||
return this.client.bulk({
|
||||
wait_for_active_shards: waitForActiveShards,
|
||||
index: this.index,
|
||||
refresh,
|
||||
body: list,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除索引
|
||||
* @param id
|
||||
* @param refresh
|
||||
* @param waitForActiveShards
|
||||
* @returns
|
||||
*/
|
||||
async deleteById(
|
||||
id,
|
||||
refresh?: boolean | 'wait_for',
|
||||
waitForActiveShards?: WaitForActiveShards
|
||||
) {
|
||||
this.esDataChange('deleteById', {
|
||||
id,
|
||||
refresh,
|
||||
waitForActiveShards,
|
||||
});
|
||||
if (refresh == undefined) {
|
||||
refresh = true;
|
||||
}
|
||||
try {
|
||||
return this.client.delete({
|
||||
index: this.index,
|
||||
refresh,
|
||||
wait_for_active_shards: waitForActiveShards,
|
||||
id,
|
||||
});
|
||||
} catch {}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除文档
|
||||
* @param ids
|
||||
* @param refresh
|
||||
* @param waitForActiveShards
|
||||
* @returns
|
||||
*/
|
||||
async deleteByIds(
|
||||
ids: string[],
|
||||
refresh?: boolean,
|
||||
waitForActiveShards?: WaitForActiveShards
|
||||
) {
|
||||
this.esDataChange('deleteByIds', {
|
||||
ids,
|
||||
refresh,
|
||||
waitForActiveShards,
|
||||
});
|
||||
if (refresh == undefined) {
|
||||
refresh = true;
|
||||
}
|
||||
const body = {
|
||||
query: {
|
||||
bool: {
|
||||
must: [
|
||||
{
|
||||
terms: {
|
||||
_id: ids,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
return this.client.deleteByQuery({
|
||||
index: this.index,
|
||||
refresh,
|
||||
wait_for_active_shards: waitForActiveShards,
|
||||
body,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据条件批量删除
|
||||
* @param body
|
||||
* @param refresh
|
||||
* @param waitForActiveShards
|
||||
* @returns
|
||||
*/
|
||||
async deleteByQuery(
|
||||
body,
|
||||
refresh?: boolean,
|
||||
waitForActiveShards?: WaitForActiveShards
|
||||
) {
|
||||
this.esDataChange('deleteByQuery', {
|
||||
body,
|
||||
refresh,
|
||||
waitForActiveShards,
|
||||
});
|
||||
if (refresh == undefined) {
|
||||
refresh = true;
|
||||
}
|
||||
return this.client.deleteByQuery({
|
||||
index: this.index,
|
||||
refresh,
|
||||
wait_for_active_shards: waitForActiveShards,
|
||||
body,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新索引
|
||||
* @param body
|
||||
* @param refresh
|
||||
* @param waitForActiveShards
|
||||
* @returns
|
||||
*/
|
||||
async updateById(
|
||||
body,
|
||||
refresh?: boolean | 'wait_for',
|
||||
waitForActiveShards?: WaitForActiveShards
|
||||
) {
|
||||
this.esDataChange('updateById', {
|
||||
body,
|
||||
refresh,
|
||||
waitForActiveShards,
|
||||
});
|
||||
if (refresh == undefined) {
|
||||
refresh = true;
|
||||
}
|
||||
const id = body.id;
|
||||
delete body.id;
|
||||
return this.client.update({
|
||||
wait_for_active_shards: waitForActiveShards,
|
||||
index: this.index,
|
||||
id: id,
|
||||
refresh,
|
||||
body: {
|
||||
doc: body,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据条件更新
|
||||
* @param body
|
||||
* @param refresh
|
||||
* @param waitForActiveShards
|
||||
*/
|
||||
async updateByQuery(
|
||||
body,
|
||||
refresh?: boolean,
|
||||
waitForActiveShards?: WaitForActiveShards
|
||||
) {
|
||||
this.esDataChange('updateByQuery', {
|
||||
body,
|
||||
refresh,
|
||||
waitForActiveShards,
|
||||
});
|
||||
if (refresh == undefined) {
|
||||
refresh = true;
|
||||
}
|
||||
return this.client.updateByQuery({
|
||||
index: this.index,
|
||||
refresh,
|
||||
wait_for_active_shards: waitForActiveShards,
|
||||
body,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询条数
|
||||
* @param body
|
||||
*/
|
||||
async findCount(body?: any) {
|
||||
let _body = Object.assign({}, body || {});
|
||||
delete _body.from;
|
||||
delete _body.size;
|
||||
delete _body.sort;
|
||||
return this.client
|
||||
.count({
|
||||
index: this.index,
|
||||
body: _body,
|
||||
})
|
||||
.then(res => {
|
||||
return res.count;
|
||||
})
|
||||
.catch(e => {
|
||||
return undefined;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建更新索引
|
||||
* @param config 配置
|
||||
*/
|
||||
async createIndex(
|
||||
properties: {},
|
||||
config: EsConfig = {
|
||||
name: '',
|
||||
replicas: 1,
|
||||
shards: 8,
|
||||
analyzers: [],
|
||||
}
|
||||
) {
|
||||
this.esDataChange('createIndex', {
|
||||
properties,
|
||||
config,
|
||||
});
|
||||
const body = {
|
||||
settings: {
|
||||
number_of_shards: config.shards,
|
||||
number_of_replicas: config.replicas,
|
||||
analysis: {
|
||||
analyzer: {
|
||||
comma: { type: 'pattern', pattern: ',' },
|
||||
blank: { type: 'pattern', pattern: ' ' },
|
||||
},
|
||||
},
|
||||
mapping: {
|
||||
nested_fields: {
|
||||
limit: 100,
|
||||
},
|
||||
},
|
||||
},
|
||||
mappings: {
|
||||
properties: {},
|
||||
},
|
||||
};
|
||||
if (config.analyzers) {
|
||||
for (const analyzer of config.analyzers) {
|
||||
for (const key in analyzer) {
|
||||
body.settings.analysis.analyzer[key] = analyzer[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
const param = {
|
||||
index: this.index,
|
||||
body,
|
||||
};
|
||||
param.body = body;
|
||||
param.body.mappings.properties = properties;
|
||||
|
||||
this.client.indices.exists({ index: this.index }).then(async res => {
|
||||
if (!res) {
|
||||
await this.client.indices.create(param).then(res => {
|
||||
if (res.acknowledged) {
|
||||
console.info(
|
||||
'\x1B[36m [cool:core] midwayjs cool elasticsearch ES索引创建成功: ' +
|
||||
this.index +
|
||||
' \x1B[0m'
|
||||
);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
const updateParam = {
|
||||
index: this.index,
|
||||
body: param.body.mappings,
|
||||
};
|
||||
await this.client.indices.putMapping(updateParam).then(res => {
|
||||
if (res.acknowledged) {
|
||||
console.info(
|
||||
'\x1B[36m [cool:core] midwayjs cool elasticsearch ES索引更新成功: ' +
|
||||
this.index +
|
||||
' \x1B[0m'
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
4
es/src/config/config.default.ts
Normal file
4
es/src/config/config.default.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export const customKey = {
|
||||
a: 1,
|
||||
b: 'hello',
|
||||
};
|
||||
19
es/src/configuration.ts
Normal file
19
es/src/configuration.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { Configuration } from '@midwayjs/core';
|
||||
import * as DefaultConfig from './config/config.default';
|
||||
import { IMidwayContainer } from '@midwayjs/core';
|
||||
import { CoolElasticSearch } from './elasticsearch';
|
||||
|
||||
@Configuration({
|
||||
namespace: 'cool:es',
|
||||
importConfigs: [
|
||||
{
|
||||
default: DefaultConfig,
|
||||
},
|
||||
],
|
||||
})
|
||||
export class CoolEsConfiguration {
|
||||
async onReady(container: IMidwayContainer) {
|
||||
await container.getAsync(CoolElasticSearch);
|
||||
// TODO something
|
||||
}
|
||||
}
|
||||
41
es/src/decorator/elasticsearch.ts
Normal file
41
es/src/decorator/elasticsearch.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import {
|
||||
Scope,
|
||||
ScopeEnum,
|
||||
saveClassMetadata,
|
||||
saveModule,
|
||||
} from '@midwayjs/core';
|
||||
|
||||
export const COOL_ES_KEY = 'decorator:cool:es';
|
||||
|
||||
export interface EsConfig {
|
||||
shards?: number;
|
||||
name: string;
|
||||
replicas?: number;
|
||||
analyzers?: any[];
|
||||
}
|
||||
|
||||
/**
|
||||
* 索引
|
||||
* @param config
|
||||
* @returns
|
||||
*/
|
||||
export function CoolEsIndex(
|
||||
config: EsConfig | string = {
|
||||
name: '',
|
||||
replicas: 1,
|
||||
shards: 8,
|
||||
analyzers: [],
|
||||
}
|
||||
): ClassDecorator {
|
||||
if (typeof config == 'string') {
|
||||
config = { name: config, replicas: 1, shards: 8, analyzers: [] };
|
||||
}
|
||||
return (target: any) => {
|
||||
// 将装饰的类,绑定到该装饰器,用于后续能获取到 class
|
||||
saveModule(COOL_ES_KEY, target);
|
||||
// 保存一些元数据信息,任意你希望存的东西
|
||||
saveClassMetadata(COOL_ES_KEY, config, target);
|
||||
// 指定 IoC 容器创建实例的作用域,这里注册为请求作用域,这样能取到 ctx
|
||||
Scope(ScopeEnum.Singleton)(target);
|
||||
};
|
||||
}
|
||||
160
es/src/elasticsearch.ts
Normal file
160
es/src/elasticsearch.ts
Normal file
@ -0,0 +1,160 @@
|
||||
import {
|
||||
Provide,
|
||||
getClassMetadata,
|
||||
App,
|
||||
Logger,
|
||||
Inject,
|
||||
Init,
|
||||
Scope,
|
||||
ScopeEnum,
|
||||
Config,
|
||||
listModule,
|
||||
} from '@midwayjs/core';
|
||||
import { COOL_ES_KEY, EsConfig } from './decorator/elasticsearch';
|
||||
import { IMidwayApplication } from '@midwayjs/core';
|
||||
import { CoolCoreException, CoolEventManager } from '@cool-midway/core';
|
||||
import { ILogger } from '@midwayjs/logger';
|
||||
import { Client } from '@elastic/elasticsearch';
|
||||
import * as _ from 'lodash';
|
||||
import { CoolEsConfig, ICoolEs } from '.';
|
||||
|
||||
/**
|
||||
* 搜索引擎
|
||||
*/
|
||||
@Provide()
|
||||
@Scope(ScopeEnum.Singleton)
|
||||
export class CoolElasticSearch {
|
||||
@App()
|
||||
app: IMidwayApplication;
|
||||
|
||||
@Logger()
|
||||
coreLogger: ILogger;
|
||||
|
||||
@Config('cool.es')
|
||||
esConfig: CoolEsConfig;
|
||||
|
||||
client: Client;
|
||||
|
||||
@Inject('cool:coolEventManager')
|
||||
coolEventManager: CoolEventManager;
|
||||
|
||||
@Init()
|
||||
async init() {
|
||||
if (!this.esConfig?.nodes) {
|
||||
throw new CoolCoreException('es.nodes config is require');
|
||||
}
|
||||
if (this.esConfig.nodes.length == 1) {
|
||||
this.client = new Client({
|
||||
node: this.esConfig.nodes[0],
|
||||
...this.esConfig.options,
|
||||
});
|
||||
} else {
|
||||
this.client = new Client({
|
||||
nodes: this.esConfig.nodes,
|
||||
...this.esConfig.options,
|
||||
});
|
||||
}
|
||||
this.client.ping({}, { requestTimeout: 30000 }).then(res => {
|
||||
if (res) {
|
||||
this.coolEventManager.emit('esReady', this.client);
|
||||
this.scan();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async scan() {
|
||||
const modules = listModule(COOL_ES_KEY);
|
||||
for (let module of modules) {
|
||||
const cls: ICoolEs = await this.app
|
||||
.getApplicationContext()
|
||||
.getAsync(module);
|
||||
const data = getClassMetadata(COOL_ES_KEY, module);
|
||||
this.createIndex(cls, data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据更新事件
|
||||
* @param method
|
||||
* @param data
|
||||
*/
|
||||
async esDataChange(method, data) {
|
||||
//this.coolEventManager.emit('esDataChange', { method, data });
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建索引
|
||||
* @param cls
|
||||
* @param config
|
||||
*/
|
||||
async createIndex(cls, config: EsConfig) {
|
||||
cls.index = config.name;
|
||||
cls.client = this.client;
|
||||
const body = {
|
||||
settings: {
|
||||
number_of_shards: config.shards,
|
||||
number_of_replicas: config.replicas,
|
||||
analysis: {
|
||||
analyzer: {
|
||||
comma: { type: 'pattern', pattern: ',' },
|
||||
blank: { type: 'pattern', pattern: ' ' },
|
||||
},
|
||||
},
|
||||
mapping: {
|
||||
nested_fields: {
|
||||
limit: 100,
|
||||
},
|
||||
},
|
||||
},
|
||||
mappings: {
|
||||
properties: {},
|
||||
},
|
||||
};
|
||||
if (config.analyzers) {
|
||||
for (const analyzer of config.analyzers) {
|
||||
for (const key in analyzer) {
|
||||
body.settings.analysis.analyzer[key] = analyzer[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
const param = {
|
||||
index: config.name,
|
||||
body,
|
||||
};
|
||||
param.body = body;
|
||||
param.body.mappings.properties = cls.indexInfo();
|
||||
|
||||
this.esDataChange('createIndex', {
|
||||
properties: param.body.mappings.properties,
|
||||
config,
|
||||
});
|
||||
|
||||
this.client.indices.exists({ index: config.name }).then(async res => {
|
||||
if (!res) {
|
||||
await this.client.indices.create(param).then(res => {
|
||||
if (res.acknowledged) {
|
||||
this.coreLogger.info(
|
||||
'\x1B[36m [cool:core] midwayjs cool elasticsearch ES索引创建成功: ' +
|
||||
config.name +
|
||||
' \x1B[0m'
|
||||
);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
const updateParam = {
|
||||
index: config.name,
|
||||
body: param.body.mappings,
|
||||
};
|
||||
await this.client.indices.putMapping(updateParam).then(res => {
|
||||
if (res.acknowledged) {
|
||||
this.coreLogger.info(
|
||||
'\x1B[36m [cool:core] midwayjs cool elasticsearch ES索引更新成功: ' +
|
||||
config.name +
|
||||
' \x1B[0m'
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
18
es/src/index.ts
Normal file
18
es/src/index.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { ClientOptions } from '@elastic/elasticsearch';
|
||||
|
||||
export { CoolEsConfiguration as Configuration } from './configuration';
|
||||
|
||||
export * from './elasticsearch';
|
||||
|
||||
export * from './decorator/elasticsearch';
|
||||
|
||||
export * from './base';
|
||||
|
||||
export interface ICoolEs {
|
||||
indexInfo(): Object;
|
||||
}
|
||||
|
||||
export interface CoolEsConfig {
|
||||
nodes: string[];
|
||||
options?: ClientOptions;
|
||||
}
|
||||
28
es/tsconfig.json
Normal file
28
es/tsconfig.json
Normal file
@ -0,0 +1,28 @@
|
||||
{
|
||||
"compileOnSave": true,
|
||||
"compilerOptions": {
|
||||
"target": "es2018",
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
"experimentalDecorators": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"inlineSourceMap":false,
|
||||
"noImplicitThis": true,
|
||||
"noUnusedLocals": true,
|
||||
"stripInternal": true,
|
||||
"skipLibCheck": true,
|
||||
"noImplicitReturns": false,
|
||||
"pretty": true,
|
||||
"declaration": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"outDir": "dist",
|
||||
"rootDir": "src"
|
||||
},
|
||||
"exclude": [
|
||||
"*.js",
|
||||
"*.ts",
|
||||
"dist",
|
||||
"node_modules",
|
||||
"test"
|
||||
]
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user