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.
Files changed (3) hide show
  1. package/package.json +1 -1
  2. package/src/jsUtil.js +29 -10
  3. package/src/query.js +122 -16
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "startgg-helper",
3
- "version": "1.0.3",
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 { deep_get } from './jsUtil.js';
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
- * Dummy client class that's only used in the JSDoc.
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 {Client} client
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 {Client} client
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 {Client} client
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 {number} delay Adds a delay between calls (does not interact with the limiter)
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 executePaginated(client, params, collectionPathInQuery, limiter = null, delay = null, perPage = undefined, pageParamName = "page", perPageParamName = "perPage", silentErrors = false, maxTries = null){
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 ?? params[perPageParamName];
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
- let data = await this.execute(client, params, limiter, silentErrors, maxTries);
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
  }