slonik-interceptor-query-cache 2.0.1 → 2.2.0
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/LICENSE +1 -1
- package/README.md +22 -52
- package/dist/src/Logger.d.ts +1 -0
- package/dist/src/Logger.js +7 -0
- package/dist/src/factories/createQueryCacheInterceptor.d.ts +14 -0
- package/dist/src/factories/createQueryCacheInterceptor.js +58 -0
- package/dist/src/factories/index.d.ts +1 -0
- package/dist/src/factories/index.js +5 -0
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.js +5 -0
- package/dist/src/utilities/extractCacheAttributes.d.ts +4 -0
- package/dist/src/utilities/extractCacheAttributes.js +19 -0
- package/dist/src/utilities/index.d.ts +1 -0
- package/dist/src/utilities/index.js +5 -0
- package/package.json +29 -55
- package/src/Logger.ts +7 -0
- package/src/factories/createQueryCacheInterceptor.ts +102 -0
- package/src/{index.js → factories/index.ts} +1 -3
- package/{dist/index.js.flow → src/index.ts} +0 -2
- package/src/utilities/extractCacheAttributes.ts +18 -0
- package/src/utilities/index.ts +3 -0
- package/tsconfig.json +26 -0
- package/.flowconfig +0 -3
- package/dist/Logger.js +0 -17
- package/dist/Logger.js.flow +0 -7
- package/dist/Logger.js.map +0 -1
- package/dist/factories/createQueryCacheInterceptor.js +0 -67
- package/dist/factories/createQueryCacheInterceptor.js.flow +0 -83
- package/dist/factories/createQueryCacheInterceptor.js.map +0 -1
- package/dist/factories/index.js +0 -16
- package/dist/factories/index.js.flow +0 -3
- package/dist/factories/index.js.map +0 -1
- package/dist/index.js +0 -14
- package/dist/index.js.map +0 -1
- package/dist/utilities/extractCacheAttributes.js +0 -22
- package/dist/utilities/extractCacheAttributes.js.flow +0 -13
- package/dist/utilities/extractCacheAttributes.js.map +0 -1
- package/dist/utilities/index.js +0 -16
- package/dist/utilities/index.js.flow +0 -3
- package/dist/utilities/index.js.map +0 -1
- package/src/Logger.js +0 -7
- package/src/factories/createQueryCacheInterceptor.js +0 -83
- package/src/factories/index.js +0 -3
- package/src/utilities/extractCacheAttributes.js +0 -13
- package/src/utilities/index.js +0 -3
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -1,55 +1,30 @@
|
|
|
1
1
|
# slonik-interceptor-query-cache
|
|
2
2
|
|
|
3
|
-
[](https://travis-ci.
|
|
3
|
+
[](https://travis-ci.com/github/gajus/slonik-interceptor-query-cache)
|
|
4
4
|
[](https://coveralls.io/github/gajus/slonik-interceptor-query-cache)
|
|
5
5
|
[](https://www.npmjs.org/package/slonik-interceptor-query-cache)
|
|
6
6
|
[](https://github.com/gajus/canonical)
|
|
7
7
|
[](https://twitter.com/kuizinas)
|
|
8
8
|
|
|
9
|
-
Caches [Slonik](https://github.com/gajus/slonik)
|
|
9
|
+
Caches [Slonik](https://github.com/gajus/slonik) query results.
|
|
10
10
|
|
|
11
11
|
## Usage
|
|
12
12
|
|
|
13
13
|
Query cache interceptor is initialised using a custom storage service. The [Example Usage](#example-usage) documentation shows how to create a compatible storage service using [`node-cache`](https://www.npmjs.com/package/node-cache).
|
|
14
14
|
|
|
15
|
-
Which queries are cached is controlled using cache attributes. Cache attributes are comments starting with
|
|
15
|
+
Which queries are cached is controlled using cache attributes. Cache attributes are comments starting with `-- @cache-` prefix. Only queries with cache attributes are cached (see [Cache attributes](#cache-attributes))
|
|
16
16
|
|
|
17
|
-
##
|
|
17
|
+
## Behavior
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
createQueryCacheInterceptor
|
|
22
|
-
} from 'slonik-interceptor-query-cache';
|
|
23
|
-
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
```js
|
|
27
|
-
type CacheAttributesType = {|
|
|
28
|
-
+ttl: number,
|
|
29
|
-
|};
|
|
30
|
-
|
|
31
|
-
type StorageType = {|
|
|
32
|
-
+get: (query: QueryType, cacheAttributes: CacheAttributesType) => Promise<QueryResultType<QueryResultRowType> | null>,
|
|
33
|
-
+set: (query: QueryType, cacheAttributes: CacheAttributesType, queryResult: QueryResultType<QueryResultRowType>) => Promise<void>,
|
|
34
|
-
|};
|
|
35
|
-
|
|
36
|
-
type ConfigurationInputType = {|
|
|
37
|
-
+storage: StorageType,
|
|
38
|
-
|};
|
|
39
|
-
|
|
40
|
-
type ConfigurationType = {|
|
|
41
|
-
+storage: StorageType,
|
|
42
|
-
|};
|
|
43
|
-
|
|
44
|
-
(configurationInput: ConfigurationInputType) => InterceptorType;
|
|
45
|
-
|
|
46
|
-
```
|
|
19
|
+
* Does not cache queries inside of a transaction.
|
|
20
|
+
* Does not take into account the query parameters.
|
|
47
21
|
|
|
48
22
|
## Cache attributes
|
|
49
23
|
|
|
50
24
|
|Cache attribute|Description|Required?|Default|
|
|
51
25
|
|---|---|---|---|
|
|
52
26
|
|`@cache-ttl`|Number (in seconds) to cache the query for.|Yes|N/A|
|
|
27
|
+
|`@cache-key`|Key (`/^[A-Za-z0-9\-_:]+$/`) that uniquely identifies the query.|Yes|N/A|
|
|
53
28
|
|
|
54
29
|
### Example usage
|
|
55
30
|
|
|
@@ -70,29 +45,25 @@ const nodeCache = new NodeCache({
|
|
|
70
45
|
useClones: false,
|
|
71
46
|
});
|
|
72
47
|
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
cache.set(hashQuery(query), queryResult, cacheAttributes.ttl);
|
|
48
|
+
const pool = await createPool('postgres://', {
|
|
49
|
+
interceptors: [
|
|
50
|
+
createQueryCacheInterceptor({
|
|
51
|
+
storage: {
|
|
52
|
+
get: (query, cacheAttributes) => {
|
|
53
|
+
// Returning null results in the query being executed.
|
|
54
|
+
return cache.get(cacheAttributes.key) || null;
|
|
55
|
+
},
|
|
56
|
+
set: (query, cacheAttributes, queryResult) => {
|
|
57
|
+
cache.set(cacheAttributes.key, queryResult, cacheAttributes.ttl);
|
|
58
|
+
},
|
|
85
59
|
},
|
|
86
|
-
},
|
|
87
|
-
|
|
88
|
-
];
|
|
89
|
-
|
|
90
|
-
const pool = createPool('postgres://', {
|
|
91
|
-
interceptors
|
|
60
|
+
}),
|
|
61
|
+
]
|
|
92
62
|
});
|
|
93
63
|
|
|
94
64
|
await connection.any(sql`
|
|
95
65
|
-- @cache-ttl 60
|
|
66
|
+
-- @cache-key foo
|
|
96
67
|
SELECT
|
|
97
68
|
id,
|
|
98
69
|
code_alpha_2
|
|
@@ -100,5 +71,4 @@ await connection.any(sql`
|
|
|
100
71
|
WHERE
|
|
101
72
|
code_alpha_2 = ${countryCode}
|
|
102
73
|
`);
|
|
103
|
-
|
|
104
|
-
```
|
|
74
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const Logger: import("roarr").Logger<import("roarr/dist/src/types").JsonObject>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Interceptor, Query, QueryResultRow, QueryResult } from 'slonik';
|
|
2
|
+
declare type CacheAttributes = {
|
|
3
|
+
key: string;
|
|
4
|
+
ttl: number;
|
|
5
|
+
};
|
|
6
|
+
declare type Storage = {
|
|
7
|
+
get: (query: Query, cacheAttributes: CacheAttributes) => Promise<QueryResult<QueryResultRow> | null>;
|
|
8
|
+
set: (query: Query, cacheAttributes: CacheAttributes, queryResult: QueryResult<QueryResultRow>) => Promise<void>;
|
|
9
|
+
};
|
|
10
|
+
declare type ConfigurationInput = {
|
|
11
|
+
storage: Storage;
|
|
12
|
+
};
|
|
13
|
+
export declare const createQueryCacheInterceptor: (configurationInput: ConfigurationInput) => Interceptor;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createQueryCacheInterceptor = void 0;
|
|
4
|
+
const Logger_1 = require("../Logger");
|
|
5
|
+
const utilities_1 = require("../utilities");
|
|
6
|
+
const log = Logger_1.Logger.child({
|
|
7
|
+
namespace: 'createQueryCacheInterceptor',
|
|
8
|
+
});
|
|
9
|
+
const createQueryCacheInterceptor = (configurationInput) => {
|
|
10
|
+
const configuration = {
|
|
11
|
+
...configurationInput,
|
|
12
|
+
};
|
|
13
|
+
return {
|
|
14
|
+
beforeQueryExecution: async (context, query) => {
|
|
15
|
+
var _a;
|
|
16
|
+
if (context.transactionId) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
const cacheAttributes = (_a = context.sandbox.cache) === null || _a === void 0 ? void 0 : _a.cacheAttributes;
|
|
20
|
+
if (!cacheAttributes) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
const maybeResult = await configuration.storage.get(query, cacheAttributes);
|
|
24
|
+
if (maybeResult) {
|
|
25
|
+
log.info({
|
|
26
|
+
queryId: context.queryId,
|
|
27
|
+
}, 'query is served from cache');
|
|
28
|
+
return maybeResult;
|
|
29
|
+
}
|
|
30
|
+
return null;
|
|
31
|
+
},
|
|
32
|
+
beforeQueryResult: async (context, query, result) => {
|
|
33
|
+
var _a;
|
|
34
|
+
if (context.transactionId) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
const cacheAttributes = (_a = context.sandbox.cache) === null || _a === void 0 ? void 0 : _a.cacheAttributes;
|
|
38
|
+
if (cacheAttributes) {
|
|
39
|
+
await configuration.storage.set(query, cacheAttributes, result);
|
|
40
|
+
}
|
|
41
|
+
return null;
|
|
42
|
+
},
|
|
43
|
+
beforeTransformQuery: async (context, query) => {
|
|
44
|
+
if (context.transactionId) {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
const cacheAttributes = (0, utilities_1.extractCacheAttributes)(query.sql);
|
|
48
|
+
if (!cacheAttributes) {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
context.sandbox.cache = {
|
|
52
|
+
cacheAttributes,
|
|
53
|
+
};
|
|
54
|
+
return null;
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
exports.createQueryCacheInterceptor = createQueryCacheInterceptor;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { createQueryCacheInterceptor, } from './createQueryCacheInterceptor';
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createQueryCacheInterceptor = void 0;
|
|
4
|
+
var createQueryCacheInterceptor_1 = require("./createQueryCacheInterceptor");
|
|
5
|
+
Object.defineProperty(exports, "createQueryCacheInterceptor", { enumerable: true, get: function () { return createQueryCacheInterceptor_1.createQueryCacheInterceptor; } });
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { createQueryCacheInterceptor, } from './factories';
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createQueryCacheInterceptor = void 0;
|
|
4
|
+
var factories_1 = require("./factories");
|
|
5
|
+
Object.defineProperty(exports, "createQueryCacheInterceptor", { enumerable: true, get: function () { return factories_1.createQueryCacheInterceptor; } });
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.extractCacheAttributes = void 0;
|
|
4
|
+
const extractCacheAttributes = (subject) => {
|
|
5
|
+
var _a, _b;
|
|
6
|
+
const ttl = (_a = /-- @cache-ttl (\d+)/u.exec(subject)) === null || _a === void 0 ? void 0 : _a[1];
|
|
7
|
+
if (ttl) {
|
|
8
|
+
const key = (_b = /-- @cache-key ([a-zA-Z0-9\-_:/]+)/ui.exec(subject)) === null || _b === void 0 ? void 0 : _b[1];
|
|
9
|
+
if (!key) {
|
|
10
|
+
throw new Error('@cache-key must be specified when @cache-ttl is specified.');
|
|
11
|
+
}
|
|
12
|
+
return {
|
|
13
|
+
key,
|
|
14
|
+
ttl: Number(ttl),
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
return null;
|
|
18
|
+
};
|
|
19
|
+
exports.extractCacheAttributes = extractCacheAttributes;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { extractCacheAttributes, } from './extractCacheAttributes';
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.extractCacheAttributes = void 0;
|
|
4
|
+
var extractCacheAttributes_1 = require("./extractCacheAttributes");
|
|
5
|
+
Object.defineProperty(exports, "extractCacheAttributes", { enumerable: true, get: function () { return extractCacheAttributes_1.extractCacheAttributes; } });
|
package/package.json
CHANGED
|
@@ -5,44 +5,31 @@
|
|
|
5
5
|
"url": "http://gajus.com"
|
|
6
6
|
},
|
|
7
7
|
"ava": {
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
|
|
11
|
-
]
|
|
12
|
-
},
|
|
8
|
+
"extensions": [
|
|
9
|
+
"ts"
|
|
10
|
+
],
|
|
13
11
|
"files": [
|
|
14
12
|
"test/slonik-interceptor-query-cache/**/*"
|
|
15
13
|
],
|
|
16
14
|
"require": [
|
|
17
|
-
"
|
|
15
|
+
"ts-node/register/transpile-only"
|
|
18
16
|
]
|
|
19
17
|
},
|
|
20
|
-
"
|
|
21
|
-
"roarr": "^2.15.2",
|
|
22
|
-
"slonik": "^22.4.0"
|
|
23
|
-
},
|
|
24
|
-
"description": "Caches Slonik queries.",
|
|
18
|
+
"description": "Cache Slonik query results.",
|
|
25
19
|
"devDependencies": {
|
|
26
|
-
"@
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"babel-plugin-istanbul": "^6.0.0",
|
|
34
|
-
"babel-plugin-macros": "^2.8.0",
|
|
35
|
-
"babel-plugin-transform-export-default-name": "^2.0.4",
|
|
36
|
-
"coveralls": "^3.0.9",
|
|
37
|
-
"eslint": "^6.8.0",
|
|
38
|
-
"eslint-config-canonical": "^18.1.1",
|
|
39
|
-
"flow-bin": "^0.118.0",
|
|
40
|
-
"flow-copy-source": "^2.0.9",
|
|
41
|
-
"husky": "^4.2.3",
|
|
20
|
+
"@istanbuljs/nyc-config-typescript": "^1.0.2",
|
|
21
|
+
"ava": "^3.15.0",
|
|
22
|
+
"coveralls": "^3.1.1",
|
|
23
|
+
"del-cli": "^4.0.1",
|
|
24
|
+
"eslint": "^8.4.1",
|
|
25
|
+
"eslint-config-canonical": "^32.46.0",
|
|
26
|
+
"husky": "^7.0.4",
|
|
42
27
|
"inline-loops.macro": "^1.2.2",
|
|
43
|
-
"nyc": "^15.
|
|
44
|
-
"semantic-release": "^
|
|
45
|
-
"sinon": "^
|
|
28
|
+
"nyc": "^15.1.0",
|
|
29
|
+
"semantic-release": "^18.0.1",
|
|
30
|
+
"sinon": "^12.0.1",
|
|
31
|
+
"ts-node": "^10.4.0",
|
|
32
|
+
"typescript": "^4.7.4"
|
|
46
33
|
},
|
|
47
34
|
"engines": {
|
|
48
35
|
"node": ">=8.0"
|
|
@@ -55,39 +42,26 @@
|
|
|
55
42
|
"keywords": [
|
|
56
43
|
"postgresql",
|
|
57
44
|
"interceptor",
|
|
58
|
-
"
|
|
45
|
+
"format"
|
|
59
46
|
],
|
|
60
47
|
"license": "BSD-3-Clause",
|
|
61
|
-
"main": "./dist/index.js",
|
|
48
|
+
"main": "./dist/src/index.js",
|
|
62
49
|
"name": "slonik-interceptor-query-cache",
|
|
63
|
-
"nyc": {
|
|
64
|
-
"all": true,
|
|
65
|
-
"exclude": [
|
|
66
|
-
"src/bin",
|
|
67
|
-
"src/queries/*.js"
|
|
68
|
-
],
|
|
69
|
-
"include": [
|
|
70
|
-
"src/**/*.js"
|
|
71
|
-
],
|
|
72
|
-
"instrument": false,
|
|
73
|
-
"reporter": [
|
|
74
|
-
"html",
|
|
75
|
-
"text-summary"
|
|
76
|
-
],
|
|
77
|
-
"require": [
|
|
78
|
-
"@babel/register"
|
|
79
|
-
],
|
|
80
|
-
"silent": true,
|
|
81
|
-
"sourceMap": false
|
|
82
|
-
},
|
|
83
50
|
"repository": {
|
|
84
51
|
"type": "git",
|
|
85
52
|
"url": "https://github.com/gajus/slonik-interceptor-query-cache"
|
|
86
53
|
},
|
|
87
54
|
"scripts": {
|
|
88
|
-
"build": "
|
|
89
|
-
"lint": "eslint ./src ./test &&
|
|
55
|
+
"build": "del-cli ./dist && tsc",
|
|
56
|
+
"lint": "eslint ./src ./test && tsc --noEmit",
|
|
90
57
|
"test": "NODE_ENV=test nyc ava --verbose --serial"
|
|
91
58
|
},
|
|
92
|
-
"
|
|
59
|
+
"typings": "./dist/src/index.d.ts",
|
|
60
|
+
"version": "2.2.0",
|
|
61
|
+
"peerDependencies": {
|
|
62
|
+
"slonik": ">=27.0.0"
|
|
63
|
+
},
|
|
64
|
+
"dependencies": {
|
|
65
|
+
"roarr": "^7.14.0"
|
|
66
|
+
}
|
|
93
67
|
}
|
package/src/Logger.ts
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
Interceptor,
|
|
3
|
+
Query,
|
|
4
|
+
QueryResultRow,
|
|
5
|
+
QueryResult,
|
|
6
|
+
} from 'slonik';
|
|
7
|
+
import {
|
|
8
|
+
Logger,
|
|
9
|
+
} from '../Logger';
|
|
10
|
+
import {
|
|
11
|
+
extractCacheAttributes,
|
|
12
|
+
} from '../utilities';
|
|
13
|
+
|
|
14
|
+
const log = Logger.child({
|
|
15
|
+
namespace: 'createQueryCacheInterceptor',
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
type Sandbox = {
|
|
19
|
+
cache: {
|
|
20
|
+
cacheAttributes: CacheAttributes,
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
type CacheAttributes = {
|
|
25
|
+
key: string,
|
|
26
|
+
ttl: number,
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
type Storage = {
|
|
30
|
+
get: (query: Query, cacheAttributes: CacheAttributes) => Promise<QueryResult<QueryResultRow> | null>,
|
|
31
|
+
set: (query: Query, cacheAttributes: CacheAttributes, queryResult: QueryResult<QueryResultRow>) => Promise<void>,
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
type ConfigurationInput = {
|
|
35
|
+
storage: Storage,
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
type Configuration = {
|
|
39
|
+
storage: Storage,
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export const createQueryCacheInterceptor = (configurationInput: ConfigurationInput): Interceptor => {
|
|
43
|
+
const configuration: Configuration = {
|
|
44
|
+
...configurationInput,
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
beforeQueryExecution: async (context, query) => {
|
|
49
|
+
if (context.transactionId) {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const cacheAttributes = (context.sandbox as Sandbox).cache?.cacheAttributes;
|
|
54
|
+
|
|
55
|
+
if (!cacheAttributes) {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const maybeResult = await configuration.storage.get(query, cacheAttributes);
|
|
60
|
+
|
|
61
|
+
if (maybeResult) {
|
|
62
|
+
log.info({
|
|
63
|
+
queryId: context.queryId,
|
|
64
|
+
}, 'query is served from cache');
|
|
65
|
+
|
|
66
|
+
return maybeResult;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return null;
|
|
70
|
+
},
|
|
71
|
+
beforeQueryResult: async (context, query, result) => {
|
|
72
|
+
if (context.transactionId) {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const cacheAttributes = (context.sandbox as Sandbox).cache?.cacheAttributes;
|
|
77
|
+
|
|
78
|
+
if (cacheAttributes) {
|
|
79
|
+
await configuration.storage.set(query, cacheAttributes, result);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return null;
|
|
83
|
+
},
|
|
84
|
+
beforeTransformQuery: async (context, query) => {
|
|
85
|
+
if (context.transactionId) {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const cacheAttributes = extractCacheAttributes(query.sql);
|
|
90
|
+
|
|
91
|
+
if (!cacheAttributes) {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
context.sandbox.cache = {
|
|
96
|
+
cacheAttributes,
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
return null;
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export const extractCacheAttributes = (subject: string) => {
|
|
2
|
+
const ttl = /-- @cache-ttl (\d+)/u.exec(subject)?.[1];
|
|
3
|
+
|
|
4
|
+
if (ttl) {
|
|
5
|
+
const key = /-- @cache-key ([a-zA-Z0-9\-_:/]+)/ui.exec(subject)?.[1];
|
|
6
|
+
|
|
7
|
+
if (!key) {
|
|
8
|
+
throw new Error('@cache-key must be specified when @cache-ttl is specified.');
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
return {
|
|
12
|
+
key,
|
|
13
|
+
ttl: Number(ttl),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return null;
|
|
18
|
+
};
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"allowSyntheticDefaultImports": true,
|
|
4
|
+
"declaration": true,
|
|
5
|
+
"esModuleInterop": true,
|
|
6
|
+
"forceConsistentCasingInFileNames": true,
|
|
7
|
+
"module": "commonjs",
|
|
8
|
+
"moduleResolution": "node",
|
|
9
|
+
"noImplicitAny": false,
|
|
10
|
+
"noImplicitReturns": true,
|
|
11
|
+
"noUnusedLocals": true,
|
|
12
|
+
"noUnusedParameters": false,
|
|
13
|
+
"outDir": "dist",
|
|
14
|
+
"skipLibCheck": true,
|
|
15
|
+
"strict": true,
|
|
16
|
+
"target": "es2018"
|
|
17
|
+
},
|
|
18
|
+
"exclude": [
|
|
19
|
+
"dist",
|
|
20
|
+
"node_modules"
|
|
21
|
+
],
|
|
22
|
+
"include": [
|
|
23
|
+
"src",
|
|
24
|
+
"test"
|
|
25
|
+
]
|
|
26
|
+
}
|
package/.flowconfig
DELETED
package/dist/Logger.js
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.default = void 0;
|
|
7
|
-
|
|
8
|
-
var _roarr = _interopRequireDefault(require("roarr"));
|
|
9
|
-
|
|
10
|
-
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
11
|
-
|
|
12
|
-
var _default = _roarr.default.child({
|
|
13
|
-
package: 'slonik-interceptor-query-cache'
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
exports.default = _default;
|
|
17
|
-
//# sourceMappingURL=Logger.js.map
|
package/dist/Logger.js.flow
DELETED
package/dist/Logger.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/Logger.js"],"names":["Logger","child","package"],"mappings":";;;;;;;AAEA;;;;eAEeA,eAAOC,KAAP,CAAa;AAC1BC,EAAAA,OAAO,EAAE;AADiB,CAAb,C","sourcesContent":["// @flow\n\nimport Logger from 'roarr';\n\nexport default Logger.child({\n package: 'slonik-interceptor-query-cache',\n});\n"],"file":"Logger.js"}
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.default = void 0;
|
|
7
|
-
|
|
8
|
-
var _utilities = require("../utilities");
|
|
9
|
-
|
|
10
|
-
var _Logger = _interopRequireDefault(require("../Logger"));
|
|
11
|
-
|
|
12
|
-
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
13
|
-
|
|
14
|
-
// eslint-disable-next-line flowtype/no-weak-types
|
|
15
|
-
const defaultConfiguration = {};
|
|
16
|
-
|
|
17
|
-
const createQueryCacheInterceptor = configurationInput => {
|
|
18
|
-
const configuration = { ...defaultConfiguration,
|
|
19
|
-
...configurationInput
|
|
20
|
-
};
|
|
21
|
-
return {
|
|
22
|
-
beforeQueryExecution: async (context, query) => {
|
|
23
|
-
const cacheAttributes = context.sandbox.cache && context.sandbox.cache.cacheAttributes;
|
|
24
|
-
|
|
25
|
-
if (!cacheAttributes) {
|
|
26
|
-
return null;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const maybeResult = await configuration.storage.get(query, cacheAttributes);
|
|
30
|
-
|
|
31
|
-
if (maybeResult) {
|
|
32
|
-
_Logger.default.info({
|
|
33
|
-
queryId: context.queryId
|
|
34
|
-
}, 'query is served from cache');
|
|
35
|
-
|
|
36
|
-
return maybeResult;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
return null;
|
|
40
|
-
},
|
|
41
|
-
beforeQueryResult: async (context, query, result) => {
|
|
42
|
-
const cacheAttributes = context.sandbox.cache && context.sandbox.cache.cacheAttributes;
|
|
43
|
-
|
|
44
|
-
if (cacheAttributes) {
|
|
45
|
-
await configuration.storage.set(query, cacheAttributes, result);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
return null;
|
|
49
|
-
},
|
|
50
|
-
beforeTransformQuery: async (context, query) => {
|
|
51
|
-
const cacheAttributes = (0, _utilities.extractCacheAttributes)(query.sql);
|
|
52
|
-
|
|
53
|
-
if (!cacheAttributes) {
|
|
54
|
-
return null;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
context.sandbox.cache = {
|
|
58
|
-
cacheAttributes
|
|
59
|
-
};
|
|
60
|
-
return null;
|
|
61
|
-
}
|
|
62
|
-
};
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
var _default = createQueryCacheInterceptor;
|
|
66
|
-
exports.default = _default;
|
|
67
|
-
//# sourceMappingURL=createQueryCacheInterceptor.js.map
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
// @flow
|
|
2
|
-
|
|
3
|
-
import type {
|
|
4
|
-
InterceptorType,
|
|
5
|
-
QueryType,
|
|
6
|
-
QueryResultRowType,
|
|
7
|
-
QueryResultType,
|
|
8
|
-
} from 'slonik';
|
|
9
|
-
import {
|
|
10
|
-
extractCacheAttributes,
|
|
11
|
-
} from '../utilities';
|
|
12
|
-
import log from '../Logger';
|
|
13
|
-
|
|
14
|
-
type CacheAttributesType = {|
|
|
15
|
-
+ttl: number,
|
|
16
|
-
|};
|
|
17
|
-
|
|
18
|
-
type StorageType = {|
|
|
19
|
-
+get: (query: QueryType, cacheAttributes: CacheAttributesType) => Promise<QueryResultType<QueryResultRowType> | null>,
|
|
20
|
-
+set: (query: QueryType, cacheAttributes: CacheAttributesType, queryResult: QueryResultType<QueryResultRowType>) => Promise<void>,
|
|
21
|
-
|};
|
|
22
|
-
|
|
23
|
-
type ConfigurationInputType = {|
|
|
24
|
-
+storage: StorageType,
|
|
25
|
-
|};
|
|
26
|
-
|
|
27
|
-
type ConfigurationType = {|
|
|
28
|
-
+storage: StorageType,
|
|
29
|
-
|};
|
|
30
|
-
|
|
31
|
-
// eslint-disable-next-line flowtype/no-weak-types
|
|
32
|
-
const defaultConfiguration: Object = {};
|
|
33
|
-
|
|
34
|
-
export default (configurationInput?: ConfigurationInputType): InterceptorType => {
|
|
35
|
-
const configuration: ConfigurationType = {
|
|
36
|
-
...defaultConfiguration,
|
|
37
|
-
...configurationInput,
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
return {
|
|
41
|
-
beforeQueryExecution: async (context, query) => {
|
|
42
|
-
const cacheAttributes = context.sandbox.cache && context.sandbox.cache.cacheAttributes;
|
|
43
|
-
|
|
44
|
-
if (!cacheAttributes) {
|
|
45
|
-
return null;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const maybeResult = await configuration.storage.get(query, cacheAttributes);
|
|
49
|
-
|
|
50
|
-
if (maybeResult) {
|
|
51
|
-
log.info({
|
|
52
|
-
queryId: context.queryId,
|
|
53
|
-
}, 'query is served from cache');
|
|
54
|
-
|
|
55
|
-
return maybeResult;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return null;
|
|
59
|
-
},
|
|
60
|
-
beforeQueryResult: async (context, query, result) => {
|
|
61
|
-
const cacheAttributes = context.sandbox.cache && context.sandbox.cache.cacheAttributes;
|
|
62
|
-
|
|
63
|
-
if (cacheAttributes) {
|
|
64
|
-
await configuration.storage.set(query, cacheAttributes, result);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
return null;
|
|
68
|
-
},
|
|
69
|
-
beforeTransformQuery: async (context, query) => {
|
|
70
|
-
const cacheAttributes = extractCacheAttributes(query.sql);
|
|
71
|
-
|
|
72
|
-
if (!cacheAttributes) {
|
|
73
|
-
return null;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
context.sandbox.cache = {
|
|
77
|
-
cacheAttributes,
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
return null;
|
|
81
|
-
},
|
|
82
|
-
};
|
|
83
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/factories/createQueryCacheInterceptor.js"],"names":["defaultConfiguration","configurationInput","configuration","beforeQueryExecution","context","query","cacheAttributes","sandbox","cache","maybeResult","storage","get","log","info","queryId","beforeQueryResult","result","set","beforeTransformQuery","sql"],"mappings":";;;;;;;AAQA;;AAGA;;;;AAmBA;AACA,MAAMA,oBAA4B,GAAG,EAArC;;oCAEgBC,kB,IAAiE;AAC/E,QAAMC,aAAgC,GAAG,EACvC,GAAGF,oBADoC;AAEvC,OAAGC;AAFoC,GAAzC;AAKA,SAAO;AACLE,IAAAA,oBAAoB,EAAE,OAAOC,OAAP,EAAgBC,KAAhB,KAA0B;AAC9C,YAAMC,eAAe,GAAGF,OAAO,CAACG,OAAR,CAAgBC,KAAhB,IAAyBJ,OAAO,CAACG,OAAR,CAAgBC,KAAhB,CAAsBF,eAAvE;;AAEA,UAAI,CAACA,eAAL,EAAsB;AACpB,eAAO,IAAP;AACD;;AAED,YAAMG,WAAW,GAAG,MAAMP,aAAa,CAACQ,OAAd,CAAsBC,GAAtB,CAA0BN,KAA1B,EAAiCC,eAAjC,CAA1B;;AAEA,UAAIG,WAAJ,EAAiB;AACfG,wBAAIC,IAAJ,CAAS;AACPC,UAAAA,OAAO,EAAEV,OAAO,CAACU;AADV,SAAT,EAEG,4BAFH;;AAIA,eAAOL,WAAP;AACD;;AAED,aAAO,IAAP;AACD,KAnBI;AAoBLM,IAAAA,iBAAiB,EAAE,OAAOX,OAAP,EAAgBC,KAAhB,EAAuBW,MAAvB,KAAkC;AACnD,YAAMV,eAAe,GAAGF,OAAO,CAACG,OAAR,CAAgBC,KAAhB,IAAyBJ,OAAO,CAACG,OAAR,CAAgBC,KAAhB,CAAsBF,eAAvE;;AAEA,UAAIA,eAAJ,EAAqB;AACnB,cAAMJ,aAAa,CAACQ,OAAd,CAAsBO,GAAtB,CAA0BZ,KAA1B,EAAiCC,eAAjC,EAAkDU,MAAlD,CAAN;AACD;;AAED,aAAO,IAAP;AACD,KA5BI;AA6BLE,IAAAA,oBAAoB,EAAE,OAAOd,OAAP,EAAgBC,KAAhB,KAA0B;AAC9C,YAAMC,eAAe,GAAG,uCAAuBD,KAAK,CAACc,GAA7B,CAAxB;;AAEA,UAAI,CAACb,eAAL,EAAsB;AACpB,eAAO,IAAP;AACD;;AAEDF,MAAAA,OAAO,CAACG,OAAR,CAAgBC,KAAhB,GAAwB;AACtBF,QAAAA;AADsB,OAAxB;AAIA,aAAO,IAAP;AACD;AAzCI,GAAP;AA2CD,C","sourcesContent":["// @flow\n\nimport type {\n InterceptorType,\n QueryType,\n QueryResultRowType,\n QueryResultType,\n} from 'slonik';\nimport {\n extractCacheAttributes,\n} from '../utilities';\nimport log from '../Logger';\n\ntype CacheAttributesType = {|\n +ttl: number,\n|};\n\ntype StorageType = {|\n +get: (query: QueryType, cacheAttributes: CacheAttributesType) => Promise<QueryResultType<QueryResultRowType> | null>,\n +set: (query: QueryType, cacheAttributes: CacheAttributesType, queryResult: QueryResultType<QueryResultRowType>) => Promise<void>,\n|};\n\ntype ConfigurationInputType = {|\n +storage: StorageType,\n|};\n\ntype ConfigurationType = {|\n +storage: StorageType,\n|};\n\n// eslint-disable-next-line flowtype/no-weak-types\nconst defaultConfiguration: Object = {};\n\nexport default (configurationInput?: ConfigurationInputType): InterceptorType => {\n const configuration: ConfigurationType = {\n ...defaultConfiguration,\n ...configurationInput,\n };\n\n return {\n beforeQueryExecution: async (context, query) => {\n const cacheAttributes = context.sandbox.cache && context.sandbox.cache.cacheAttributes;\n\n if (!cacheAttributes) {\n return null;\n }\n\n const maybeResult = await configuration.storage.get(query, cacheAttributes);\n\n if (maybeResult) {\n log.info({\n queryId: context.queryId,\n }, 'query is served from cache');\n\n return maybeResult;\n }\n\n return null;\n },\n beforeQueryResult: async (context, query, result) => {\n const cacheAttributes = context.sandbox.cache && context.sandbox.cache.cacheAttributes;\n\n if (cacheAttributes) {\n await configuration.storage.set(query, cacheAttributes, result);\n }\n\n return null;\n },\n beforeTransformQuery: async (context, query) => {\n const cacheAttributes = extractCacheAttributes(query.sql);\n\n if (!cacheAttributes) {\n return null;\n }\n\n context.sandbox.cache = {\n cacheAttributes,\n };\n\n return null;\n },\n };\n};\n"],"file":"createQueryCacheInterceptor.js"}
|
package/dist/factories/index.js
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
Object.defineProperty(exports, "createQueryCacheInterceptor", {
|
|
7
|
-
enumerable: true,
|
|
8
|
-
get: function () {
|
|
9
|
-
return _createQueryCacheInterceptor.default;
|
|
10
|
-
}
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
var _createQueryCacheInterceptor = _interopRequireDefault(require("./createQueryCacheInterceptor"));
|
|
14
|
-
|
|
15
|
-
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
16
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/factories/index.js"],"names":[],"mappings":";;;;;;;;;;;;AAEA","sourcesContent":["// @flow\n\nexport {default as createQueryCacheInterceptor} from './createQueryCacheInterceptor';\n"],"file":"index.js"}
|
package/dist/index.js
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
Object.defineProperty(exports, "createQueryCacheInterceptor", {
|
|
7
|
-
enumerable: true,
|
|
8
|
-
get: function () {
|
|
9
|
-
return _factories.createQueryCacheInterceptor;
|
|
10
|
-
}
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
var _factories = require("./factories");
|
|
14
|
-
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.js"],"names":[],"mappings":";;;;;;;;;;;;AAEA","sourcesContent":["// @flow\n\nexport {\n createQueryCacheInterceptor,\n} from './factories';\n"],"file":"index.js"}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.default = void 0;
|
|
7
|
-
|
|
8
|
-
const extractCacheAttributes = subject => {
|
|
9
|
-
const matches = subject.match(/@cache-ttl (\d+)/);
|
|
10
|
-
|
|
11
|
-
if (matches) {
|
|
12
|
-
return {
|
|
13
|
-
ttl: Number(matches[1])
|
|
14
|
-
};
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
return null;
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
var _default = extractCacheAttributes;
|
|
21
|
-
exports.default = _default;
|
|
22
|
-
//# sourceMappingURL=extractCacheAttributes.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utilities/extractCacheAttributes.js"],"names":["subject","matches","match","ttl","Number"],"mappings":";;;;;;;+BAEgBA,O,IAAoB;AAClC,QAAMC,OAAO,GAAGD,OAAO,CAACE,KAAR,CAAc,kBAAd,CAAhB;;AAEA,MAAID,OAAJ,EAAa;AACX,WAAO;AACLE,MAAAA,GAAG,EAAEC,MAAM,CAACH,OAAO,CAAC,CAAD,CAAR;AADN,KAAP;AAGD;;AAED,SAAO,IAAP;AACD,C","sourcesContent":["// @flow\n\nexport default (subject: string) => {\n const matches = subject.match(/@cache-ttl (\\d+)/);\n\n if (matches) {\n return {\n ttl: Number(matches[1]),\n };\n }\n\n return null;\n};\n"],"file":"extractCacheAttributes.js"}
|
package/dist/utilities/index.js
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
Object.defineProperty(exports, "extractCacheAttributes", {
|
|
7
|
-
enumerable: true,
|
|
8
|
-
get: function () {
|
|
9
|
-
return _extractCacheAttributes.default;
|
|
10
|
-
}
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
var _extractCacheAttributes = _interopRequireDefault(require("./extractCacheAttributes"));
|
|
14
|
-
|
|
15
|
-
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
16
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utilities/index.js"],"names":[],"mappings":";;;;;;;;;;;;AAEA","sourcesContent":["// @flow\n\nexport {default as extractCacheAttributes} from './extractCacheAttributes';\n"],"file":"index.js"}
|
package/src/Logger.js
DELETED
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
// @flow
|
|
2
|
-
|
|
3
|
-
import type {
|
|
4
|
-
InterceptorType,
|
|
5
|
-
QueryType,
|
|
6
|
-
QueryResultRowType,
|
|
7
|
-
QueryResultType,
|
|
8
|
-
} from 'slonik';
|
|
9
|
-
import {
|
|
10
|
-
extractCacheAttributes,
|
|
11
|
-
} from '../utilities';
|
|
12
|
-
import log from '../Logger';
|
|
13
|
-
|
|
14
|
-
type CacheAttributesType = {|
|
|
15
|
-
+ttl: number,
|
|
16
|
-
|};
|
|
17
|
-
|
|
18
|
-
type StorageType = {|
|
|
19
|
-
+get: (query: QueryType, cacheAttributes: CacheAttributesType) => Promise<QueryResultType<QueryResultRowType> | null>,
|
|
20
|
-
+set: (query: QueryType, cacheAttributes: CacheAttributesType, queryResult: QueryResultType<QueryResultRowType>) => Promise<void>,
|
|
21
|
-
|};
|
|
22
|
-
|
|
23
|
-
type ConfigurationInputType = {|
|
|
24
|
-
+storage: StorageType,
|
|
25
|
-
|};
|
|
26
|
-
|
|
27
|
-
type ConfigurationType = {|
|
|
28
|
-
+storage: StorageType,
|
|
29
|
-
|};
|
|
30
|
-
|
|
31
|
-
// eslint-disable-next-line flowtype/no-weak-types
|
|
32
|
-
const defaultConfiguration: Object = {};
|
|
33
|
-
|
|
34
|
-
export default (configurationInput?: ConfigurationInputType): InterceptorType => {
|
|
35
|
-
const configuration: ConfigurationType = {
|
|
36
|
-
...defaultConfiguration,
|
|
37
|
-
...configurationInput,
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
return {
|
|
41
|
-
beforeQueryExecution: async (context, query) => {
|
|
42
|
-
const cacheAttributes = context.sandbox.cache && context.sandbox.cache.cacheAttributes;
|
|
43
|
-
|
|
44
|
-
if (!cacheAttributes) {
|
|
45
|
-
return null;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const maybeResult = await configuration.storage.get(query, cacheAttributes);
|
|
49
|
-
|
|
50
|
-
if (maybeResult) {
|
|
51
|
-
log.info({
|
|
52
|
-
queryId: context.queryId,
|
|
53
|
-
}, 'query is served from cache');
|
|
54
|
-
|
|
55
|
-
return maybeResult;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return null;
|
|
59
|
-
},
|
|
60
|
-
beforeQueryResult: async (context, query, result) => {
|
|
61
|
-
const cacheAttributes = context.sandbox.cache && context.sandbox.cache.cacheAttributes;
|
|
62
|
-
|
|
63
|
-
if (cacheAttributes) {
|
|
64
|
-
await configuration.storage.set(query, cacheAttributes, result);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
return null;
|
|
68
|
-
},
|
|
69
|
-
beforeTransformQuery: async (context, query) => {
|
|
70
|
-
const cacheAttributes = extractCacheAttributes(query.sql);
|
|
71
|
-
|
|
72
|
-
if (!cacheAttributes) {
|
|
73
|
-
return null;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
context.sandbox.cache = {
|
|
77
|
-
cacheAttributes,
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
return null;
|
|
81
|
-
},
|
|
82
|
-
};
|
|
83
|
-
};
|
package/src/factories/index.js
DELETED
package/src/utilities/index.js
DELETED