startgg-helper 1.0.3 → 2.0.1
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/package.json +1 -1
- package/src/jsUtil.js +29 -10
- package/src/query.js +122 -16
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "startgg-helper",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "A set of functions and classes useful to communicate with the start.gg API, using any client (YOU NEED TO PROVIDE A CLIENT YOURSELF, SEE README)",
|
|
5
5
|
"main": "main.js",
|
|
6
6
|
"scripts": {
|
package/src/jsUtil.js
CHANGED
|
@@ -1,12 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
*
|
|
3
|
-
* @param {{}} obj
|
|
4
|
-
* @param {string} path
|
|
5
|
-
* @param {*} def
|
|
6
|
-
* @returns
|
|
7
|
-
*/
|
|
8
|
-
export function deep_get(obj, path, def = null){
|
|
9
|
-
//https://stackoverflow.com/a/8817473
|
|
1
|
+
function processObjectPath(path){
|
|
10
2
|
path = path=path.split('.');
|
|
11
3
|
for (let i = 0; i < path.length; i++){
|
|
12
4
|
if (/^\d/.test(path[i])){
|
|
@@ -16,10 +8,37 @@ export function deep_get(obj, path, def = null){
|
|
|
16
8
|
}
|
|
17
9
|
}
|
|
18
10
|
}
|
|
11
|
+
return path;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
*
|
|
16
|
+
* @param {{}} obj
|
|
17
|
+
* @param {string} path
|
|
18
|
+
* @param {*} def
|
|
19
|
+
* @returns
|
|
20
|
+
*/
|
|
21
|
+
export function deep_get(obj, path, def = null){
|
|
22
|
+
//https://stackoverflow.com/a/8817473
|
|
23
|
+
path = processObjectPath(path);
|
|
19
24
|
|
|
20
25
|
for (var i=0, len=path.length; i<len; i++){
|
|
21
26
|
obj = obj[path[i]];
|
|
22
27
|
if (obj == undefined) return def;
|
|
23
28
|
};
|
|
24
29
|
return obj;
|
|
25
|
-
};
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export function deep_set(obj, path, value){
|
|
33
|
+
path = processObjectPath(path);
|
|
34
|
+
|
|
35
|
+
let finalName = path.pop();
|
|
36
|
+
for (let elt of path){
|
|
37
|
+
obj = obj[elt];
|
|
38
|
+
if (!(obj instanceof Object)){
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
obj[finalName] = value;
|
|
43
|
+
return true;
|
|
44
|
+
}
|
package/src/query.js
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { GraphQLClient } from 'graphql-request';
|
|
2
|
+
import { deep_get, deep_set } from './jsUtil.js';
|
|
2
3
|
import { TimedQuerySemaphore } from './queryLimiter.js'
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
* In a real use case, the user will have their own client class.
|
|
7
|
-
*/
|
|
8
|
-
class Client {
|
|
9
|
-
request(){}
|
|
5
|
+
function isConnection(val){
|
|
6
|
+
return val instanceof Object && val.nodes instanceof Array
|
|
10
7
|
}
|
|
11
8
|
|
|
12
9
|
export class Query {
|
|
@@ -44,7 +41,7 @@ export class Query {
|
|
|
44
41
|
|
|
45
42
|
/**
|
|
46
43
|
*
|
|
47
|
-
* @param {
|
|
44
|
+
* @param {GraphQLClient} client
|
|
48
45
|
* @param {{[varName: string]: value}} params
|
|
49
46
|
* @param {number} tries How many tries in are we
|
|
50
47
|
* @param {TimedQuerySemaphore} limiter
|
|
@@ -73,7 +70,7 @@ export class Query {
|
|
|
73
70
|
|
|
74
71
|
/**
|
|
75
72
|
* Executes the query with given parameters and client
|
|
76
|
-
* @param {
|
|
73
|
+
* @param {GraphQLClient} client
|
|
77
74
|
* @param {{[varName: string]: value}} params
|
|
78
75
|
* @param {TimedQuerySemaphore} limiter
|
|
79
76
|
* @param {boolean} silentErrors
|
|
@@ -84,29 +81,124 @@ export class Query {
|
|
|
84
81
|
return await this.#execute_(client, params, 0, limiter, silentErrors, maxTries);
|
|
85
82
|
}
|
|
86
83
|
|
|
84
|
+
static IWQModes = {
|
|
85
|
+
DONT: 0,
|
|
86
|
+
INLINE: 1,
|
|
87
|
+
DUPLICATE: 2,
|
|
88
|
+
OUT: 3
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Executes a query containing a paginated collection (of a *Connection type) repeatedly, increasing the page index each time until nothing is returned, returning an aggregation of all the pages.
|
|
93
|
+
* @param {GraphQLClient} client
|
|
94
|
+
* @param {{[varName: string]: value}} params
|
|
95
|
+
* @param {string} connectionPathInQuery JSON path to the paginated collection that must aggregated in the query (JSON path : property names separated by dots)
|
|
96
|
+
* @param {TimedQuerySemaphore} limiter
|
|
97
|
+
* @param {{pageParamName?: string, perPageParamName?: string, perPage?: number, delay?: number, maxElements?: number, includeWholeQuery?: number}} config
|
|
98
|
+
* @param {boolean} silentErrors
|
|
99
|
+
* @param {number} maxTries
|
|
100
|
+
* @returns
|
|
101
|
+
*/
|
|
102
|
+
async executePaginated(client, params, connectionPathInQuery, limiter = null, config = {}, silentErrors = false, maxTries = null){
|
|
103
|
+
let result = [];
|
|
104
|
+
//delay = null, perPage = undefined, pageParamName = "page", perPageParamName = "perPage", silentErrors = false, maxTries = null
|
|
105
|
+
const pageParamName = config.pageParamName ?? "page";
|
|
106
|
+
const perPageParamName = config.perPageParamName ?? "perPage";
|
|
107
|
+
const perPage = config.perPage ?? params[perPageParamName];
|
|
108
|
+
const delay = config.delay;
|
|
109
|
+
const maxElements = config.maxElements ?? undefined; //eliminating null
|
|
110
|
+
|
|
111
|
+
let currentPage = 1;
|
|
112
|
+
|
|
113
|
+
params = Object.assign({}, params);
|
|
114
|
+
params[pageParamName] = currentPage;
|
|
115
|
+
params[perPageParamName] = perPage;
|
|
116
|
+
|
|
117
|
+
let data;
|
|
118
|
+
while (true){
|
|
119
|
+
if (result.length >= maxElements) break;
|
|
120
|
+
|
|
121
|
+
console.log("Querying page", params[pageParamName], `(${result.length} elements loaded)`);
|
|
122
|
+
data = await this.execute(client, params, limiter, silentErrors, maxTries);
|
|
123
|
+
|
|
124
|
+
if (!data) throw (this.#getLog("error", params) ?? "Request failed.") + "(in paginated execution, at page " + params[pageParamName] + ")";
|
|
125
|
+
|
|
126
|
+
let connection = deep_get(data, connectionPathInQuery);
|
|
127
|
+
|
|
128
|
+
if (!connection) {
|
|
129
|
+
console.warn(`The given path ${connectionPathInQuery} does not point to anything.`);
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (!isConnection(connection)) throw "The given path does not point to a connection type"
|
|
134
|
+
console.log(connection);
|
|
135
|
+
|
|
136
|
+
let localResult = connection.nodes;
|
|
137
|
+
if (connection.pageInfo && connection.pageInfo.totalPages){
|
|
138
|
+
let totalPages = connection.pageInfo.totalPages;
|
|
139
|
+
if (currentPage >= totalPages) {
|
|
140
|
+
result = result.concat(localResult);
|
|
141
|
+
break;
|
|
142
|
+
}
|
|
143
|
+
} else {
|
|
144
|
+
if (localResult.length < 1) break;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
result = result.concat(localResult);
|
|
148
|
+
currentPage++;
|
|
149
|
+
params[pageParamName] = currentPage;
|
|
150
|
+
|
|
151
|
+
if (delay)
|
|
152
|
+
await new Promise(r => setTimeout(r, delay));
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (maxElements) result = result.slice(0, maxElements);
|
|
156
|
+
|
|
157
|
+
if (config.includeWholeQuery == Query.IWQModes.DUPLICATE || config.includeWholeQuery == Query.IWQModes.INLINE){
|
|
158
|
+
deep_set(data, connectionPathInQuery + ".nodes", result);
|
|
159
|
+
} else if (config.includeWholeQuery == Query.IWQModes.OUT){
|
|
160
|
+
deep_set(data, connectionPathInQuery + ".nodes", null);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (config.includeWholeQuery == Query.IWQModes.DUPLICATE || config.includeWholeQuery == Query.IWQModes.OUT){
|
|
164
|
+
return [result, data]
|
|
165
|
+
} else if (config.includeWholeQuery == Query.IWQModes.INLINE){
|
|
166
|
+
return data;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return result;
|
|
170
|
+
}
|
|
171
|
+
|
|
87
172
|
/**
|
|
88
173
|
* Executes a query containing a paginated collection, repeatedly, increasing the page index each time until nothing is returned, returning an aggregation of all the pages.
|
|
89
|
-
* @param {
|
|
174
|
+
* @param {GraphQLClient} client
|
|
90
175
|
* @param {{[varName: string]: value}} params
|
|
91
176
|
* @param {string} collectionPathInQuery JSON path to the paginated collection that must aggregated in the query (JSON path : property names separated by dots)
|
|
92
177
|
* @param {TimedQuerySemaphore} limiter
|
|
93
|
-
* @param {
|
|
94
|
-
* @param {string} pageParamName Name of the query parameter that must be updated with a page index for each query
|
|
178
|
+
* @param {{pageParamName?: string, perPageParamName?: string, perPage?: number, delay?: number, maxElements?: number, includeWholeQuery?: number}} config
|
|
95
179
|
* @param {boolean} silentErrors
|
|
96
180
|
* @param {number} maxTries
|
|
97
181
|
* @returns
|
|
98
182
|
*/
|
|
99
|
-
async
|
|
183
|
+
async executePaginatedLegacy(client, params, collectionPathInQuery, limiter = null, config = {}, silentErrors = false, maxTries = null){
|
|
100
184
|
let result = [];
|
|
101
|
-
|
|
185
|
+
//delay = null, perPage = undefined, pageParamName = "page", perPageParamName = "perPage", silentErrors = false, maxTries = null
|
|
186
|
+
const pageParamName = config.pageParamName ?? "page";
|
|
187
|
+
const perPageParamName = config.perPageParamName ?? "perPage";
|
|
188
|
+
const perPage = config.perPage ?? params[perPageParamName];
|
|
189
|
+
const delay = config.delay;
|
|
190
|
+
const maxElements = config.maxElements ?? undefined; //eliminating null
|
|
102
191
|
|
|
103
192
|
params = Object.assign({}, params);
|
|
104
193
|
params[pageParamName] = 1;
|
|
105
|
-
params[perPageParamName] = perPage
|
|
194
|
+
params[perPageParamName] = perPage;
|
|
106
195
|
|
|
196
|
+
let data;
|
|
107
197
|
while (true){
|
|
198
|
+
if (result.length >= maxElements) break;
|
|
199
|
+
|
|
108
200
|
console.log("Querying page", params[pageParamName], `(${result.length} elements loaded)`);
|
|
109
|
-
|
|
201
|
+
data = await this.execute(client, params, limiter, silentErrors, maxTries);
|
|
110
202
|
|
|
111
203
|
if (!data) throw (this.#getLog("error", params) ?? "Request failed.") + "(in paginated execution, at page " + params[pageParamName] + ")";
|
|
112
204
|
|
|
@@ -128,6 +220,20 @@ export class Query {
|
|
|
128
220
|
await new Promise(r => setTimeout(r, delay));
|
|
129
221
|
}
|
|
130
222
|
|
|
223
|
+
if (maxElements) result = result.slice(0, maxElements);
|
|
224
|
+
|
|
225
|
+
if (config.includeWholeQuery == Query.IWQModes.DUPLICATE || config.includeWholeQuery == Query.IWQModes.INLINE){
|
|
226
|
+
deep_set(data, collectionPathInQuery, result);
|
|
227
|
+
} else if (config.includeWholeQuery == Query.IWQModes.OUT){
|
|
228
|
+
deep_set(data, collectionPathInQuery, null);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (config.includeWholeQuery == Query.IWQModes.DUPLICATE || config.includeWholeQuery == Query.IWQModes.OUT){
|
|
232
|
+
return [result, data]
|
|
233
|
+
} else if (config.includeWholeQuery == Query.IWQModes.INLINE){
|
|
234
|
+
return data;
|
|
235
|
+
}
|
|
236
|
+
|
|
131
237
|
return result;
|
|
132
238
|
}
|
|
133
239
|
}
|