@steedos/service-api 2.6.1-beta.7 → 2.6.2-beta.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.
Files changed (2) hide show
  1. package/index.js +59 -21
  2. package/package.json +6 -6
package/index.js CHANGED
@@ -18,6 +18,7 @@ const { LRUMap } = require('lru_map');
18
18
  const validator = require('validator');
19
19
  const enablePlayground = validator.toBoolean(process.env.STEEDOS_GRAPHQL_ENABLE_CONSOLE || 'true', true);
20
20
  const openBrowser = require('react-dev-utils/openBrowser');
21
+ const requestIp = require('request-ip');
21
22
  const mixinOptions = {
22
23
 
23
24
  // Global GraphQL typeDefs
@@ -86,7 +87,7 @@ const mixinOptions = {
86
87
  introspection: enablePlayground
87
88
  }
88
89
  }
89
-
90
+ const ObjectDataLoaderMapKeys = {};
90
91
  /**
91
92
  * @typedef {import('moleculer').Context} Context Moleculer's Context
92
93
  * @typedef {import('http').IncomingMessage} IncomingRequest Incoming HTTP Request
@@ -94,7 +95,6 @@ const mixinOptions = {
94
95
  */
95
96
  module.exports = {
96
97
  name: "api",
97
- projectStarted: false,
98
98
  mixins: [ApiGateway,
99
99
  // GraphQL Apollo Server
100
100
  ApolloService(mixinOptions),
@@ -171,10 +171,13 @@ module.exports = {
171
171
  * @param {ServerResponse} res
172
172
  * @param {Object} data
173
173
  *
174
+ *
175
+ */
174
176
  onBeforeCall(ctx, route, req, res) {
175
177
  // Set request headers to context meta
176
178
  ctx.meta.userAgent = req.headers["user-agent"];
177
- }, */
179
+ ctx.meta.clientIp = requestIp.getClientIp(req);
180
+ },
178
181
 
179
182
  /**
180
183
  * After call hook. You can modify the data.
@@ -325,9 +328,14 @@ module.exports = {
325
328
  * @param {Object.<string, any>} args - Arguments passed to GraphQL child resolver
326
329
  * @returns {string} Key to the dataloader instance
327
330
  */
328
- getObjectDataLoaderMapKey(objectName) {
331
+ getObjectDataLoaderMapKey(objectName, referenceToField = '_id', spaceId) {
329
332
  if (objectName) {
330
- return `object:${objectName}`;
333
+ const key = `${spaceId}_object:${objectName}.${referenceToField}`;
334
+ if(!ObjectDataLoaderMapKeys[objectName]){
335
+ ObjectDataLoaderMapKeys[objectName] = [] ;
336
+ }
337
+ ObjectDataLoaderMapKeys[objectName].push(key);
338
+ return key;
331
339
  }
332
340
  // 如果没有objectName,则抛出错误信息
333
341
  throw new Error("objectName is required");
@@ -337,8 +345,12 @@ module.exports = {
337
345
  async objectDataLoaderHandler(actionName, staticParams, rootParams, graphqlCtx) {
338
346
  const rootKeys = Object.keys(rootParams);
339
347
  const {root, args, context, resolveInfo} = graphqlCtx;
348
+ const userSession = context.ctx.meta.user;
349
+ const spaceId = userSession.spaceId;
340
350
  const dataLoaderMapKey = this.getObjectDataLoaderMapKey(
341
351
  staticParams.__objectName || staticParams.objectName
352
+ , staticParams.referenceToField || '_id'
353
+ , spaceId
342
354
  );
343
355
  const objectDataLoaders = this.objectDataLoaders;
344
356
  // if a dataLoader batching parameter is specified, then all root params can be data loaded;
@@ -361,7 +373,8 @@ module.exports = {
361
373
  batchedParamKey,
362
374
  staticParams,
363
375
  args,
364
- { hashCacheKey: dataLoaderUseAllRootKeys } // must hash the cache key if not loading scalar
376
+ { hashCacheKey: dataLoaderUseAllRootKeys }, // must hash the cache key if not loading scalar
377
+ spaceId
365
378
  );
366
379
  objectDataLoaders.set(dataLoaderMapKey, dataLoader);
367
380
  }
@@ -456,10 +469,13 @@ module.exports = {
456
469
  if(useObjectDataLoader){
457
470
  return await this.objectDataLoaderHandler(actionName, staticParams, rootParams, {root, args, context, resolveInfo});
458
471
  }else if (useDataLoader) {
472
+ const userSession = context.ctx.meta.user;
473
+ const spaceId = userSession.spaceId;
459
474
  const dataLoaderMapKey = this.getDataLoaderMapKey(
460
475
  actionName,
461
476
  staticParams,
462
- args
477
+ args,
478
+ spaceId
463
479
  );
464
480
  // if a dataLoader batching parameter is specified, then all root params can be data loaded;
465
481
  // otherwise use only the primary rootParam
@@ -481,7 +497,8 @@ module.exports = {
481
497
  batchedParamKey,
482
498
  staticParams,
483
499
  args,
484
- { hashCacheKey: dataLoaderUseAllRootKeys } // must hash the cache key if not loading scalar
500
+ { hashCacheKey: dataLoaderUseAllRootKeys }, // must hash the cache key if not loading scalar
501
+ spaceId
485
502
  );
486
503
  context.dataLoaders.set(dataLoaderMapKey, dataLoader);
487
504
  }
@@ -894,6 +911,25 @@ module.exports = {
894
911
  }
895
912
  },
896
913
 
914
+ /**
915
+ * Get the unique key assigned to the DataLoader map
916
+ * @param {string} actionName - Fully qualified action name to bind to dataloader
917
+ * @param {Object.<string, any>} staticParams - Static parameters to use in dataloader
918
+ * @param {Object.<string, any>} args - Arguments passed to GraphQL child resolver
919
+ * @returns {string} Key to the dataloader instance
920
+ */
921
+ getDataLoaderMapKey(actionName, staticParams, args, spaceId) {
922
+ if (Object.keys(staticParams).length > 0 || Object.keys(args).length > 0) {
923
+ // create a unique hash of the static params and the arguments to ensure a unique DataLoader instance
924
+ const actionParams = _.defaultsDeep({}, args, staticParams);
925
+ const paramsHash = hash(actionParams);
926
+ return `${spaceId}_${actionName}:${paramsHash}`;
927
+ }
928
+
929
+ // if no static params or arguments are present then the action name can serve as the key
930
+ return actionName;
931
+ },
932
+
897
933
  /**
898
934
  * Build a DataLoader instance
899
935
  *
@@ -912,11 +948,13 @@ module.exports = {
912
948
  batchedParamKey,
913
949
  staticParams,
914
950
  args,
915
- { hashCacheKey = false } = {}
951
+ { hashCacheKey = false } = {},
952
+ spaceId
916
953
  ) {
917
954
  const batchLoadFn = keys => {
918
955
  const rootParams = { [batchedParamKey]: keys };
919
- return ctx.call(actionName, _.defaultsDeep({}, args, rootParams, staticParams));
956
+ // !!! 这里的ctx是buildDataLoader时传进来的参数,在后续触发执行batchLoadFn时ctx.meta中的信息依然是旧的,故此函数体中代码不要使用ctx.meta中的信息
957
+ return ctx.call(actionName, _.defaultsDeep({}, args, rootParams, staticParams), { meta: { ...ctx.meta, spaceId } });
920
958
  };
921
959
 
922
960
  const dataLoaderOptions = this.dataLoaderOptions.get(actionName) || {};
@@ -938,19 +976,19 @@ module.exports = {
938
976
  '@objectRecordEvent.*.*': function(ctx){
939
977
  const { objectApiName, isUpdate, isDelete, id, doc } = ctx.params;
940
978
  if(objectApiName && (isUpdate || isDelete)){
941
- const key = this.getObjectDataLoaderMapKey(
942
- objectApiName
943
- );
979
+ const keys = ObjectDataLoaderMapKeys[objectApiName] || [];
944
980
  let dataLoaderKeys = [id];
945
981
  if(objectApiName === 'space_users'){
946
982
  dataLoaderKeys.push(doc.user)
947
983
  }
948
- const loader = this.objectDataLoaders.get(key);
949
- if(loader){
950
- for(const dataLoaderKey of dataLoaderKeys){
951
- loader.clear(dataLoaderKey);
984
+ _.each(keys, (key)=>{
985
+ const loader = this.objectDataLoaders.get(key);
986
+ if(loader){
987
+ for(const dataLoaderKey of dataLoaderKeys){
988
+ loader.clear(dataLoaderKey);
989
+ }
952
990
  }
953
- }
991
+ })
954
992
  }
955
993
  },
956
994
  'service-ui.started': function(){
@@ -995,9 +1033,9 @@ module.exports = {
995
1033
  // });
996
1034
  // }
997
1035
 
998
- // this.broker.waitForServices('~packages-@steedos/service-ui').then(() => {
999
- // this.app.use("/", this.express());
1000
- // })
1036
+ this.broker.waitForServices('~packages-@steedos/service-ui').then(() => {
1037
+ this.app.use("/", this.express());
1038
+ })
1001
1039
 
1002
1040
  global.SteedosApi = {
1003
1041
  express: this.express
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@steedos/service-api",
3
- "version": "2.6.1-beta.7",
3
+ "version": "2.6.2-beta.10",
4
4
  "main": "index.js",
5
5
  "license": "MIT",
6
6
  "dependencies": {
7
- "@steedos/auth": "2.6.1-beta.7",
8
- "@steedos/router": "2.6.1-beta.7",
9
- "@steedos/service-object-graphql": "2.6.1-beta.7",
10
- "@steedos/service-ui": "2.6.1-beta.7",
7
+ "@steedos/auth": "2.6.2-beta.10",
8
+ "@steedos/router": "2.6.2-beta.10",
9
+ "@steedos/service-object-graphql": "2.6.2-beta.10",
10
+ "@steedos/service-ui": "2.6.2-beta.10",
11
11
  "graphql": "^15.8.0",
12
12
  "graphql-iso-date": "^3.6.1",
13
13
  "graphql-type-json": "^0.3.2",
@@ -22,7 +22,7 @@
22
22
  "publishConfig": {
23
23
  "access": "public"
24
24
  },
25
- "gitHead": "b12f271460ef3686face095e875aa38e8ddc4c7f",
25
+ "gitHead": "afbd1c34d1516e44494b5d5a192bbce80e48af93",
26
26
  "devDependencies": {
27
27
  "@types/graphql-iso-date": "^3.4.0",
28
28
  "@types/react-dev-utils": "^9.0.11"