@nocobase/plugin-data-visualization 0.13.0-alpha.1 → 0.13.0-alpha.10

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.
@@ -1,10 +1,147 @@
1
- 'use strict';
2
-
3
- var database = require('@nocobase/database');
4
- var formatter = require('./formatter');
5
-
6
- const parseFieldAndAssociations = (ctx, params) => {
7
- const { collection: collectionName, measures, dimensions, orders, filter } = params;
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
+ // If the importer is in node compatibility mode or this is not an ESM
21
+ // file that has been converted to a CommonJS file using a Babel-
22
+ // compatible transform (i.e. "__esModule" has not been set), then set
23
+ // "default" to the CommonJS "module.exports" for node compatibility.
24
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
+ mod
26
+ ));
27
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
+ var query_exports = {};
29
+ __export(query_exports, {
30
+ cacheMiddleware: () => cacheMiddleware,
31
+ parseBuilder: () => parseBuilder,
32
+ parseFieldAndAssociations: () => parseFieldAndAssociations,
33
+ parseVariables: () => parseVariables,
34
+ postProcess: () => postProcess,
35
+ query: () => query,
36
+ queryData: () => queryData
37
+ });
38
+ module.exports = __toCommonJS(query_exports);
39
+ var import_database = require("@nocobase/database");
40
+ var import_formatter = require("./formatter");
41
+ var import_koa_compose = __toESM(require("koa-compose"));
42
+ var import_utils = require("@nocobase/utils");
43
+ const postProcess = async (ctx, next) => {
44
+ const { sequelize } = ctx.db;
45
+ const dialect = sequelize.getDialect();
46
+ const { data, fieldMap } = ctx.action.params.values;
47
+ switch (dialect) {
48
+ case "postgres":
49
+ ctx.body = data.map((record) => {
50
+ const result = {};
51
+ Object.entries(record).forEach(([key, value]) => {
52
+ const { type } = fieldMap[key] || {};
53
+ switch (type) {
54
+ case "bigInt":
55
+ case "integer":
56
+ case "float":
57
+ case "double":
58
+ value = Number(value);
59
+ break;
60
+ }
61
+ result[key] = value;
62
+ });
63
+ return result;
64
+ });
65
+ break;
66
+ default:
67
+ ctx.body = data;
68
+ }
69
+ await next();
70
+ };
71
+ const queryData = async (ctx, next) => {
72
+ const { collection, queryParams, fieldMap } = ctx.action.params.values;
73
+ const model = ctx.db.getModel(collection);
74
+ const data = await model.findAll(queryParams);
75
+ ctx.action.params.values = {
76
+ data,
77
+ fieldMap
78
+ };
79
+ await next();
80
+ };
81
+ const parseBuilder = async (ctx, next) => {
82
+ const { sequelize } = ctx.db;
83
+ const { measures, dimensions, orders, include, where, limit } = ctx.action.params.values;
84
+ const attributes = [];
85
+ const group = [];
86
+ const order = [];
87
+ const fieldMap = {};
88
+ let hasAgg = false;
89
+ measures.forEach((measure) => {
90
+ const { field, aggregation, alias } = measure;
91
+ const attribute = [];
92
+ const col = sequelize.col(field);
93
+ if (aggregation) {
94
+ hasAgg = true;
95
+ attribute.push(sequelize.fn(aggregation, col));
96
+ } else {
97
+ attribute.push(col);
98
+ }
99
+ if (alias) {
100
+ attribute.push(alias);
101
+ }
102
+ attributes.push(attribute.length > 1 ? attribute : attribute[0]);
103
+ fieldMap[alias || field] = measure;
104
+ });
105
+ dimensions.forEach((dimension) => {
106
+ const { field, format, alias, type } = dimension;
107
+ const attribute = [];
108
+ const col = sequelize.col(field);
109
+ if (format) {
110
+ attribute.push((0, import_formatter.formatter)(sequelize, type, field, format));
111
+ } else {
112
+ attribute.push(col);
113
+ }
114
+ if (alias) {
115
+ attribute.push(alias);
116
+ }
117
+ attributes.push(attribute.length > 1 ? attribute : attribute[0]);
118
+ if (hasAgg) {
119
+ group.push(attribute[0]);
120
+ }
121
+ fieldMap[alias || field] = dimension;
122
+ });
123
+ orders.forEach((item) => {
124
+ const alias = sequelize.getQueryInterface().quoteIdentifier(item.alias);
125
+ const name = hasAgg ? sequelize.literal(alias) : sequelize.col(item.field);
126
+ order.push([name, item.order || "ASC"]);
127
+ });
128
+ ctx.action.params.values = {
129
+ ...ctx.action.params.values,
130
+ queryParams: {
131
+ where,
132
+ attributes,
133
+ include,
134
+ group,
135
+ order,
136
+ limit: limit > 2e3 ? 2e3 : limit,
137
+ raw: true
138
+ },
139
+ fieldMap
140
+ };
141
+ await next();
142
+ };
143
+ const parseFieldAndAssociations = async (ctx, next) => {
144
+ const { collection: collectionName, measures, dimensions, orders, filter } = ctx.action.params.values;
8
145
  const collection = ctx.db.getCollection(collectionName);
9
146
  const fields = collection.fields;
10
147
  const underscored = ctx.db.options.underscored;
@@ -20,7 +157,7 @@ const parseFieldAndAssociations = (ctx, params) => {
20
157
  } else if (selected.field.length > 1) {
21
158
  [target, name] = selected.field;
22
159
  }
23
- let field = underscored ? database.snakeCase(name) : name;
160
+ let field = underscored ? (0, import_database.snakeCase)(name) : name;
24
161
  let fieldType = (_a = fields.get(name)) == null ? void 0 : _a.type;
25
162
  if (target) {
26
163
  const targetField = fields.get(target);
@@ -52,7 +189,7 @@ const parseFieldAndAssociations = (ctx, params) => {
52
189
  attributes: [],
53
190
  ...type === "belongsToMany" ? { through: { attributes: [] } } : {}
54
191
  }));
55
- const filterParser = new database.FilterParser(filter, {
192
+ const filterParser = new import_database.FilterParser(filter, {
56
193
  collection
57
194
  });
58
195
  const { where, include: filterInclude } = filterParser.toSequelizeParams();
@@ -63,149 +200,103 @@ const parseFieldAndAssociations = (ctx, params) => {
63
200
  }
64
201
  return item;
65
202
  });
66
- return {
203
+ ctx.action.params.values = {
204
+ ...ctx.action.params.values,
67
205
  where,
68
206
  measures: parsedMeasures,
69
207
  dimensions: parsedDimensions,
70
208
  orders: parsedOrders,
71
209
  include: [...include, ...parsedFilterInclude || []]
72
210
  };
211
+ await next();
73
212
  };
74
- const parseBuilder = (ctx, builder) => {
75
- const { sequelize } = ctx.db;
76
- const { limit } = builder;
77
- const { measures, dimensions, orders, include, where } = parseFieldAndAssociations(ctx, builder);
78
- const attributes = [];
79
- const group = [];
80
- const order = [];
81
- const fieldMap = {};
82
- let hasAgg = false;
83
- measures.forEach((measure) => {
84
- const { field, aggregation, alias } = measure;
85
- const attribute = [];
86
- const col = sequelize.col(field);
87
- if (aggregation) {
88
- hasAgg = true;
89
- attribute.push(sequelize.fn(aggregation, col));
90
- } else {
91
- attribute.push(col);
92
- }
93
- if (alias) {
94
- attribute.push(alias);
95
- }
96
- attributes.push(attribute.length > 1 ? attribute : attribute[0]);
97
- fieldMap[alias || field] = measure;
98
- });
99
- dimensions.forEach((dimension) => {
100
- const { field, format, alias, type } = dimension;
101
- const attribute = [];
102
- const col = sequelize.col(field);
103
- if (format) {
104
- attribute.push(formatter.formatter(sequelize, type, field, format));
105
- } else {
106
- attribute.push(col);
107
- }
108
- if (alias) {
109
- attribute.push(alias);
110
- }
111
- attributes.push(attribute.length > 1 ? attribute : attribute[0]);
112
- if (hasAgg) {
113
- group.push(attribute[0]);
114
- }
115
- fieldMap[alias || field] = dimension;
116
- });
117
- orders.forEach((item) => {
118
- const alias = sequelize.getQueryInterface().quoteIdentifier(item.alias);
119
- const name = hasAgg ? sequelize.literal(alias) : sequelize.col(item.field);
120
- order.push([name, item.order || "ASC"]);
121
- });
122
- return {
123
- queryParams: {
124
- where,
125
- attributes,
126
- include,
127
- group,
128
- order,
129
- limit: limit > 2e3 ? 2e3 : limit,
130
- raw: true
131
- },
132
- fieldMap
213
+ const parseVariables = async (ctx, next) => {
214
+ const { filter } = ctx.action.params.values;
215
+ if (!filter) {
216
+ return next();
217
+ }
218
+ const isNumeric = (str) => {
219
+ if (typeof str === "number")
220
+ return true;
221
+ if (typeof str != "string")
222
+ return false;
223
+ return !isNaN(str) && !isNaN(parseFloat(str));
133
224
  };
134
- };
135
- const processData = (ctx, data, fieldMap) => {
136
- const { sequelize } = ctx.db;
137
- const dialect = sequelize.getDialect();
138
- switch (dialect) {
139
- case "postgres":
140
- return data.map((record) => {
141
- const result = {};
142
- Object.entries(record).forEach(([key, value]) => {
143
- const { type } = fieldMap[key] || {};
144
- switch (type) {
145
- case "bigInt":
146
- case "integer":
147
- case "float":
148
- case "double":
149
- value = Number(value);
150
- break;
151
- }
152
- result[key] = value;
153
- });
154
- return result;
225
+ const getUser = () => {
226
+ return async ({ fields }) => {
227
+ var _a, _b;
228
+ const userFields = fields.filter((f) => f && ctx.db.getFieldByPath("users." + f));
229
+ (_a = ctx.logger) == null ? void 0 : _a.info("filter-parse: ", { userFields });
230
+ if (!ctx.state.currentUser) {
231
+ return;
232
+ }
233
+ if (!userFields.length) {
234
+ return;
235
+ }
236
+ const user = await ctx.db.getRepository("users").findOne({
237
+ filterByTk: ctx.state.currentUser.id,
238
+ fields: userFields
155
239
  });
156
- default:
157
- return data;
158
- }
159
- };
160
- const queryData = async (ctx, builder) => {
161
- const { collection, measures, dimensions, orders, filter, limit, sql } = builder;
162
- const model = ctx.db.getModel(collection);
163
- const { queryParams, fieldMap } = parseBuilder(ctx, { collection, measures, dimensions, orders, filter, limit });
164
- const data = await model.findAll(queryParams);
165
- return processData(ctx, data, fieldMap);
240
+ (_b = ctx.logger) == null ? void 0 : _b.info("filter-parse: ", {
241
+ $user: user == null ? void 0 : user.toJSON()
242
+ });
243
+ return user;
244
+ };
245
+ };
246
+ ctx.action.params.values.filter = await (0, import_utils.parseFilter)(filter, {
247
+ timezone: ctx.get("x-timezone"),
248
+ now: (/* @__PURE__ */ new Date()).toISOString(),
249
+ getField: (path) => {
250
+ const fieldPath = path.split(".").filter((p) => !p.startsWith("$") && !isNumeric(p)).join(".");
251
+ const { resourceName } = ctx.action;
252
+ return ctx.db.getFieldByPath(`${resourceName}.${fieldPath}`);
253
+ },
254
+ vars: {
255
+ $nDate: (0, import_utils.getDateVars)(),
256
+ $user: getUser()
257
+ }
258
+ });
259
+ await next();
166
260
  };
167
- const cacheWrap = async (cache, options) => {
168
- const { func, key, ttl, useCache, refresh } = options;
261
+ const cacheMiddleware = async (ctx, next) => {
262
+ const { uid, cache: cacheConfig, refresh } = ctx.action.params.values;
263
+ const plugin = ctx.app.getPlugin("data-visualization");
264
+ const cache = plugin.cache;
265
+ const useCache = (cacheConfig == null ? void 0 : cacheConfig.enabled) && uid;
169
266
  if (useCache && !refresh) {
170
- const data2 = await cache.get(key);
171
- if (data2) {
172
- return data2;
267
+ const data = await cache.get(uid);
268
+ if (data) {
269
+ ctx.body = data;
270
+ return;
173
271
  }
174
272
  }
175
- const data = await func();
273
+ await next();
176
274
  if (useCache) {
177
- await cache.set(key, data, ttl);
275
+ console.log(uid, ctx.body);
276
+ await cache.set(uid, ctx.body, (cacheConfig == null ? void 0 : cacheConfig.ttl) || 30);
277
+ console.log(cache.get(uid));
178
278
  }
179
- return data;
180
279
  };
181
- const query = async (ctx, next) => {
182
- const {
183
- uid,
184
- collection,
185
- measures,
186
- dimensions,
187
- orders,
188
- filter,
189
- limit,
190
- sql,
191
- cache: cacheConfig,
192
- refresh
193
- } = ctx.action.params.values;
280
+ const checkPermission = (ctx, next) => {
281
+ const { collection } = ctx.action.params.values;
194
282
  const roleName = ctx.state.currentRole || "anonymous";
195
283
  const can = ctx.app.acl.can({ role: roleName, resource: collection, action: "list" });
196
284
  if (!can && roleName !== "root") {
197
285
  ctx.throw(403, "No permissions");
198
286
  }
199
- const plugin = ctx.app.getPlugin("data-visualization");
200
- const cache = plugin.cache;
201
- const useCache = (cacheConfig == null ? void 0 : cacheConfig.enabled) && uid;
287
+ return next();
288
+ };
289
+ const query = async (ctx, next) => {
202
290
  try {
203
- ctx.body = await cacheWrap(cache, {
204
- func: async () => await queryData(ctx, { collection, measures, dimensions, orders, filter, limit, sql }),
205
- key: uid,
206
- ttl: (cacheConfig == null ? void 0 : cacheConfig.ttl) || 30,
207
- useCache: useCache ? true : false,
208
- refresh
291
+ await (0, import_koa_compose.default)([
292
+ checkPermission,
293
+ cacheMiddleware,
294
+ parseVariables,
295
+ parseFieldAndAssociations,
296
+ parseBuilder,
297
+ queryData,
298
+ postProcess
299
+ ])(ctx, async () => {
209
300
  });
210
301
  } catch (err) {
211
302
  ctx.app.logger.error("charts query: ", err);
@@ -213,10 +304,13 @@ const query = async (ctx, next) => {
213
304
  }
214
305
  await next();
215
306
  };
216
-
217
- exports.cacheWrap = cacheWrap;
218
- exports.parseBuilder = parseBuilder;
219
- exports.parseFieldAndAssociations = parseFieldAndAssociations;
220
- exports.processData = processData;
221
- exports.query = query;
222
- exports.queryData = queryData;
307
+ // Annotate the CommonJS export names for ESM import in node:
308
+ 0 && (module.exports = {
309
+ cacheMiddleware,
310
+ parseBuilder,
311
+ parseFieldAndAssociations,
312
+ parseVariables,
313
+ postProcess,
314
+ query,
315
+ queryData
316
+ });
@@ -1,11 +1,33 @@
1
- 'use strict';
2
-
3
- var plugin = require('./plugin');
4
-
5
- function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
6
-
7
- var plugin__default = /*#__PURE__*/_interopDefault(plugin);
8
-
9
-
10
-
11
- module.exports = plugin__default.default;
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
+ // If the importer is in node compatibility mode or this is not an ESM
21
+ // file that has been converted to a CommonJS file using a Babel-
22
+ // compatible transform (i.e. "__esModule" has not been set), then set
23
+ // "default" to the CommonJS "module.exports" for node compatibility.
24
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
+ mod
26
+ ));
27
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
+ var server_exports = {};
29
+ __export(server_exports, {
30
+ default: () => import_plugin.default
31
+ });
32
+ module.exports = __toCommonJS(server_exports);
33
+ var import_plugin = __toESM(require("./plugin"));
@@ -1,12 +1,30 @@
1
- 'use strict';
2
-
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
- var cache = require('@nocobase/cache');
6
- var server = require('@nocobase/server');
7
- var query = require('./actions/query');
8
-
9
- class DataVisualizationPlugin extends server.Plugin {
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 plugin_exports = {};
19
+ __export(plugin_exports, {
20
+ DataVisualizationPlugin: () => DataVisualizationPlugin,
21
+ default: () => plugin_default
22
+ });
23
+ module.exports = __toCommonJS(plugin_exports);
24
+ var import_cache = require("@nocobase/cache");
25
+ var import_server = require("@nocobase/server");
26
+ var import_query = require("./actions/query");
27
+ class DataVisualizationPlugin extends import_server.Plugin {
10
28
  cache;
11
29
  afterAdd() {
12
30
  }
@@ -14,13 +32,13 @@ class DataVisualizationPlugin extends server.Plugin {
14
32
  this.app.resource({
15
33
  name: "charts",
16
34
  actions: {
17
- query: query.query
35
+ query: import_query.query
18
36
  }
19
37
  });
20
38
  this.app.acl.allow("charts", "query", "loggedIn");
21
39
  }
22
40
  async load() {
23
- this.cache = cache.createCache({
41
+ this.cache = (0, import_cache.createCache)({
24
42
  ttl: 30,
25
43
  // seconds
26
44
  max: 1e3,
@@ -37,6 +55,7 @@ class DataVisualizationPlugin extends server.Plugin {
37
55
  }
38
56
  }
39
57
  var plugin_default = DataVisualizationPlugin;
40
-
41
- exports.DataVisualizationPlugin = DataVisualizationPlugin;
42
- exports.default = plugin_default;
58
+ // Annotate the CommonJS export names for ESM import in node:
59
+ 0 && (module.exports = {
60
+ DataVisualizationPlugin
61
+ });
@@ -1,5 +1,25 @@
1
- 'use strict';
2
-
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 swagger_exports = {};
19
+ __export(swagger_exports, {
20
+ default: () => swagger_default
21
+ });
22
+ module.exports = __toCommonJS(swagger_exports);
3
23
  var swagger_default = {
4
24
  info: {
5
25
  title: "NocoBase API - Data visualization plugin"
@@ -7,5 +27,3 @@ var swagger_default = {
7
27
  tags: [],
8
28
  paths: {}
9
29
  };
10
-
11
- module.exports = swagger_default;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nocobase/plugin-data-visualization",
3
- "version": "0.13.0-alpha.1",
3
+ "version": "0.13.0-alpha.10",
4
4
  "displayName": "Data Visualization",
5
5
  "displayName.zh-CN": "数据可视化",
6
6
  "description": "Provides business intelligence and data visualization features",
@@ -17,11 +17,12 @@
17
17
  "@testing-library/react": "^14.0.0",
18
18
  "antd": "5.x",
19
19
  "classnames": "^2.3.1",
20
+ "koa-compose": "^4.1.0",
20
21
  "lodash": "^4.17.21",
21
22
  "react": "^18.2.0",
22
23
  "react-error-boundary": "^4.0.10",
23
24
  "react-i18next": "^11.15.1",
24
- "vitest": "^0.33.0"
25
+ "vitest": "0.x"
25
26
  },
26
27
  "peerDependencies": {
27
28
  "@nocobase/actions": "0.x",
@@ -32,5 +33,5 @@
32
33
  "@nocobase/test": "0.x",
33
34
  "@nocobase/utils": "0.x"
34
35
  },
35
- "gitHead": "0ebd4e85a1b0b0d0943768ab6cb5c3d824562239"
36
+ "gitHead": "5360ed81650f6895f3ed39aede2706467d55862c"
36
37
  }