@pi-r/gcp 0.7.3 → 0.8.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/client/index.js CHANGED
@@ -1,11 +1,29 @@
1
1
  "use strict";
2
- exports.CLOUD_DOWNLOAD_CHUNK = exports.CLOUD_UPLOAD_CHUNK = exports.CLOUD_UPLOAD_STREAM = exports.getProjectId = exports.createBucketRequest = exports.setPredefinedAcl = exports.setPublicRead = exports.executeBatchQuery = exports.executeQuery = exports.deleteObjectsV2 = exports.deleteObjects = exports.setBucketWebsite = exports.setBucketTagging = exports.setBucketPolicy = exports.createBucketV2 = exports.createBucket = exports.createDatabaseClient = exports.createStorageClient = exports.validateDatabase = exports.validateStorage = exports.isFirebaseApp = void 0;
2
+ exports.CLOUD_DOWNLOAD_CHUNK = exports.CLOUD_UPLOAD_CHUNK = exports.CLOUD_UPLOAD_STREAM = void 0;
3
+ exports.isFirebaseApp = isFirebaseApp;
4
+ exports.validateStorage = validateStorage;
5
+ exports.validateDatabase = validateDatabase;
6
+ exports.createStorageClient = createStorageClient;
7
+ exports.createDatabaseClient = createDatabaseClient;
8
+ exports.createBucket = createBucket;
9
+ exports.createBucketV2 = createBucketV2;
10
+ exports.setBucketPolicy = setBucketPolicy;
11
+ exports.setBucketTagging = setBucketTagging;
12
+ exports.setBucketWebsite = setBucketWebsite;
13
+ exports.deleteObjects = deleteObjects;
14
+ exports.deleteObjectsV2 = deleteObjectsV2;
15
+ exports.executeQuery = executeQuery;
16
+ exports.executeBatchQuery = executeBatchQuery;
17
+ exports.setPublicRead = setPublicRead;
18
+ exports.setPredefinedAcl = setPredefinedAcl;
19
+ exports.createBucketRequest = createBucketRequest;
20
+ exports.getProjectId = getProjectId;
3
21
  const path = require("path");
4
- const storage = require("@google-cloud/storage");
5
22
  const firestore_1 = require("@google-cloud/firestore");
23
+ const storage_1 = require("@google-cloud/storage");
24
+ const Cloud = require("@e-mc/cloud");
6
25
  const util_1 = require("@e-mc/cloud/util");
7
26
  const types_1 = require("@e-mc/types");
8
- const Cloud = require("@e-mc/cloud");
9
27
  const FIREBASE_DB = {};
10
28
  const FIREBASE_STORAGE = {};
11
29
  const ADMIN_DB = {};
@@ -109,15 +127,12 @@ const hasGoogleAuth = (credential) => (0, types_1.isString)(credential.keyFilena
109
127
  function isFirebaseApp(credential, store, admin) {
110
128
  return !!(credential.apiKey && credential.authDomain && (store || credential.databaseURL) || credential.product === "firebase" && process.env.GOOGLE_APPLICATION_CREDENTIALS) && (!admin || !credential.admin);
111
129
  }
112
- exports.isFirebaseApp = isFirebaseApp;
113
130
  function validateStorage(credential) {
114
131
  return hasGoogleAuth(credential) || isFirebaseApp(credential, true);
115
132
  }
116
- exports.validateStorage = validateStorage;
117
133
  function validateDatabase(credential, data) {
118
134
  return hasGoogleAuth(credential) && !!(data.product || data.database || data.table || data.query || data.id || data.keys || data.kind || data.options?.query) || isFirebaseApp(credential);
119
135
  }
120
- exports.validateDatabase = validateDatabase;
121
136
  function createStorageClient(credential, bucket) {
122
137
  if (isFirebaseApp(credential, true)) {
123
138
  let packageName = '';
@@ -134,9 +149,8 @@ function createStorageClient(credential, bucket) {
134
149
  }
135
150
  }
136
151
  getProjectId(credential, false);
137
- return new storage.Storage(credential);
152
+ return new storage_1.Storage(credential);
138
153
  }
139
- exports.createStorageClient = createStorageClient;
140
154
  function createDatabaseClient(credential, data) {
141
155
  let packageName = '';
142
156
  try {
@@ -171,11 +185,9 @@ function createDatabaseClient(credential, data) {
171
185
  }
172
186
  return new firestore_1.Firestore(credential);
173
187
  }
174
- exports.createDatabaseClient = createDatabaseClient;
175
188
  async function createBucket(credential, bucket, publicRead, service = 'gcp') {
176
189
  return createBucketV2.call(this, credential, bucket, publicRead ? 'publicRead' : undefined, createBucketRequest(credential), service);
177
190
  }
178
- exports.createBucket = createBucket;
179
191
  async function createBucketV2(credential, bucket, acl, options, service = 'gcp') {
180
192
  if (isFirebaseApp(credential, true, true)) {
181
193
  return false;
@@ -203,7 +215,6 @@ async function createBucketV2(credential, bucket, acl, options, service = 'gcp')
203
215
  return false;
204
216
  });
205
217
  }
206
- exports.createBucketV2 = createBucketV2;
207
218
  async function setBucketPolicy(credential, bucket, options, service = 'gcp') {
208
219
  if (isFirebaseApp(credential, true, true)) {
209
220
  return false;
@@ -247,17 +258,16 @@ async function setBucketPolicy(credential, bucket, options, service = 'gcp') {
247
258
  break;
248
259
  }
249
260
  }
250
- if (options.acl && (options.acl = options.acl.filter(user => (0, types_1.isString)(user.entity))).length) {
261
+ if (options.acl && (options.acl = options.acl.filter(user => (0, types_1.isString)(user.entity))).length > 0) {
251
262
  errors.push(...await updatePredefinedAcl(client.acl, options.acl, options.metadata));
252
263
  }
253
- if (errors.length) {
264
+ if (errors.length > 0) {
254
265
  this.formatFail(64, service, ["Unable to update bucket policy", bucket], errors[0], { ...Cloud.LOG_CLOUD_FAIL, fatal: false });
255
266
  return false;
256
267
  }
257
268
  this.formatMessage(64, service, ["Bucket ACL configured", bucket], (0, types_1.isString)(acl) ? acl : '', { ...Cloud.LOG_CLOUD_COMMAND });
258
269
  return true;
259
270
  }
260
- exports.setBucketPolicy = setBucketPolicy;
261
271
  async function setBucketTagging(credential, bucket, labels, service = 'gcp') {
262
272
  if (isFirebaseApp(credential, true, true) || !(0, types_1.isPlainObject)(labels)) {
263
273
  return false;
@@ -284,7 +294,6 @@ async function setBucketTagging(credential, bucket, labels, service = 'gcp') {
284
294
  return false;
285
295
  });
286
296
  }
287
- exports.setBucketTagging = setBucketTagging;
288
297
  async function setBucketWebsite(credential, bucket, options, service = 'gcp') {
289
298
  if (isFirebaseApp(credential, true, true)) {
290
299
  return false;
@@ -307,11 +316,9 @@ async function setBucketWebsite(credential, bucket, options, service = 'gcp') {
307
316
  return false;
308
317
  });
309
318
  }
310
- exports.setBucketWebsite = setBucketWebsite;
311
319
  async function deleteObjects(credential, Bucket, service) {
312
320
  return deleteObjectsV2.call(this, credential, Bucket, true, service);
313
321
  }
314
- exports.deleteObjects = deleteObjects;
315
322
  async function deleteObjectsV2(credential, bucket, recursive = true, service = 'gcp') {
316
323
  const instance = createStorageClient.call(this, credential, bucket);
317
324
  const errors = [];
@@ -322,10 +329,10 @@ async function deleteObjectsV2(credential, bucket, recursive = true, service = '
322
329
  await (async function recurse(prefix) {
323
330
  try {
324
331
  const { items, prefixes } = await listAll(ref(instance, prefix));
325
- if (items.length) {
332
+ if (items.length > 0) {
326
333
  files.push(...items.map(value => value.fullPath));
327
334
  }
328
- if (recursive && prefixes.length) {
335
+ if (recursive && prefixes.length > 0) {
329
336
  for (const { name } of prefixes) {
330
337
  await recurse(Cloud.joinPath(prefix, name));
331
338
  }
@@ -335,7 +342,7 @@ async function deleteObjectsV2(credential, bucket, recursive = true, service = '
335
342
  errors.push(err);
336
343
  }
337
344
  })('');
338
- if (files.length) {
345
+ if (files.length > 0) {
339
346
  promise = Promise.allSettled(files.map(async (value) => deleteObject(ref(instance, value))));
340
347
  }
341
348
  }
@@ -343,27 +350,31 @@ async function deleteObjectsV2(credential, bucket, recursive = true, service = '
343
350
  const client = instance.bucket(bucket);
344
351
  if (await hasBucket(client)) {
345
352
  if (recursive) {
346
- return client.deleteFiles({ force: true }).then(() => this.formatMessage(64, service, "Bucket emptied" + ' (recursive)', bucket, { ...Cloud.LOG_CLOUD_COMMAND }));
353
+ return client.deleteFiles({ force: true }).then(() => {
354
+ this.formatMessage(64, service, "Bucket emptied" + ' (recursive)', bucket, { ...Cloud.LOG_CLOUD_COMMAND });
355
+ });
347
356
  }
348
357
  const tasks = [];
349
358
  try {
350
359
  const result = await client.getFiles();
351
360
  for (const { name } of result[0]) {
352
361
  if (!name.includes('/')) {
353
- tasks.push(client.file(name).delete({ ignoreNotFound: true }).catch((err) => this.formatFail(64, service, ["Delete failed", name], err, { ...Cloud.LOG_CLOUD_FAIL, fatal: false })));
362
+ tasks.push(client.file(name).delete({ ignoreNotFound: true }).catch((err) => {
363
+ this.formatFail(64, service, ["Delete failed", name], err, { ...Cloud.LOG_CLOUD_FAIL, fatal: false });
364
+ }));
354
365
  }
355
366
  }
356
367
  }
357
368
  catch (err) {
358
369
  errors.push(err);
359
370
  }
360
- if (tasks.length) {
371
+ if (tasks.length > 0) {
361
372
  promise = Promise.allSettled(tasks);
362
373
  }
363
374
  }
364
375
  }
365
376
  const checkErrors = () => {
366
- if (errors.length) {
377
+ if (errors.length > 0) {
367
378
  this.formatFail(64, service, ["Unable to empty bucket" + (recursive ? ' (recursive)' : ''), errors.length + ' errors'], errors[0], { ...Cloud.LOG_CLOUD_FAIL, fatal: false });
368
379
  return true;
369
380
  }
@@ -383,11 +394,9 @@ async function deleteObjectsV2(credential, bucket, recursive = true, service = '
383
394
  }
384
395
  checkErrors();
385
396
  }
386
- exports.deleteObjectsV2 = deleteObjectsV2;
387
397
  async function executeQuery(credential, data, sessionKey) {
388
398
  return (await executeBatchQuery.call(this, credential, [data], sessionKey))[0] || [];
389
399
  }
390
- exports.executeQuery = executeQuery;
391
400
  async function executeBatchQuery(credential, batch, sessionKey) {
392
401
  const length = batch.length;
393
402
  const result = new Array(length);
@@ -407,8 +416,7 @@ async function executeBatchQuery(credential, batch, sessionKey) {
407
416
  const closeClient = () => {
408
417
  const fs = clients[3];
409
418
  if (fs) {
410
- fs.terminate();
411
- return;
419
+ void fs.terminate();
412
420
  }
413
421
  const sp = clients[5];
414
422
  if (sp) {
@@ -438,12 +446,6 @@ async function executeBatchQuery(credential, batch, sessionKey) {
438
446
  const item = batch[i];
439
447
  const { service, product, name, database, table, id, query, limit = 0, update, ignoreCache } = item;
440
448
  const useCache = caching && ignoreCache !== true;
441
- const getCache = (value) => {
442
- if (ignoreCache !== 1) {
443
- cacheValue.renewCache = ignoreCache === 0;
444
- return this.getQueryResult(service, credential, value, cacheValue);
445
- }
446
- };
447
449
  cacheValue.exclusiveOf = Array.isArray(ignoreCache) ? ignoreCache : undefined;
448
450
  let rows, queryString = '';
449
451
  if (product === "firebase" || isFirebaseApp(credential)) {
@@ -454,7 +456,7 @@ async function executeBatchQuery(credential, batch, sessionKey) {
454
456
  const orderBy = item.orderBy;
455
457
  if (useCache) {
456
458
  queryString = query + Cloud.asString(orderBy, true);
457
- if (!update && (rows = getCache(queryString))) {
459
+ if (!update && (rows = this.getCacheResult(service, credential, queryString, cacheValue, ignoreCache))) {
458
460
  result[i] = rows;
459
461
  continue;
460
462
  }
@@ -495,7 +497,7 @@ async function executeBatchQuery(credential, batch, sessionKey) {
495
497
  if ((0, types_1.isPlainObject)(update)) {
496
498
  await updateDB(ref(db, query), update);
497
499
  }
498
- const snapshot = await (constraints.length ? get(queryDB(ref(db, query), ...constraints)) : get(child(ref(db), query)));
500
+ const snapshot = await (constraints.length > 0 ? get(queryDB(ref(db, query), ...constraints)) : get(child(ref(db), query)));
499
501
  if (snapshot.exists()) {
500
502
  const val = snapshot.val();
501
503
  const group = limiter === 1 && Object.keys(val);
@@ -514,8 +516,8 @@ async function executeBatchQuery(credential, batch, sessionKey) {
514
516
  }
515
517
  const { updateType, options = {} } = item;
516
518
  if (useCache) {
517
- queryString = name + '_' + database + (table ? '_' + table + (columns ? Cloud.asString(columns, true) : '') : '') + '_' + Cloud.asString(query, true) + (limit > 0 ? limit : '');
518
- if (!update && (rows = getCache(queryString))) {
519
+ queryString = name + '_' + database + (table ? '_' + table + (columns ? Cloud.asString(columns, true) : '') : '') + '_' + Cloud.asString(query, true) + (limit > 0 ? '_' + limit : '');
520
+ if (!update && (rows = this.getCacheResult(service, credential, queryString, cacheValue, ignoreCache))) {
519
521
  result[i] = rows;
520
522
  continue;
521
523
  }
@@ -547,10 +549,12 @@ async function executeBatchQuery(credential, batch, sessionKey) {
547
549
  transaction.runUpdate(update)
548
550
  .then(async () => {
549
551
  transaction.commit()
550
- .then(() => resolve())
551
- .catch((error) => reject(error));
552
+ .then(() => {
553
+ resolve();
554
+ })
555
+ .catch(reject);
552
556
  })
553
- .catch((error) => reject(error));
557
+ .catch(reject);
554
558
  }
555
559
  });
556
560
  });
@@ -577,7 +581,7 @@ async function executeBatchQuery(credential, batch, sessionKey) {
577
581
  }
578
582
  if (useCache) {
579
583
  queryString = name + '_' + table + ((0, types_1.isString)(id) ? '_' + id + ((0, types_1.isArray)(columns) ? '_' + Cloud.asString(columns, true) : '') : '') + Cloud.asString(options, true);
580
- if (!(update && id) && (rows = getCache(queryString))) {
584
+ if (!(update && id) && (rows = this.getCacheResult(service, credential, queryString, cacheValue, ignoreCache))) {
581
585
  result[i] = rows;
582
586
  continue;
583
587
  }
@@ -601,7 +605,9 @@ async function executeBatchQuery(credential, batch, sessionKey) {
601
605
  rows = [];
602
606
  await new Promise((resolve, reject) => {
603
607
  db.createReadStream(options)
604
- .on('data', row => rows.push(getRowData(row.id, row.data)))
608
+ .on('data', row => {
609
+ rows.push(getRowData(row.id, row.data));
610
+ })
605
611
  .on('error', reject)
606
612
  .on('end', resolve);
607
613
  });
@@ -612,6 +618,10 @@ async function executeBatchQuery(credential, batch, sessionKey) {
612
618
  if ((0, types_1.isString)(query)) {
613
619
  options.query = query;
614
620
  }
621
+ else if (!options.query) {
622
+ closeClient();
623
+ throw (0, util_1.formatError)(item, "Missing database query");
624
+ }
615
625
  if ((0, types_1.isObject)(params)) {
616
626
  options.params = params;
617
627
  }
@@ -619,14 +629,13 @@ async function executeBatchQuery(credential, batch, sessionKey) {
619
629
  options.maxResults = limit;
620
630
  }
621
631
  if (useCache) {
622
- queryString = query + (database ? '_' + database + (table ? '_' + table : '') : '') + Cloud.asString(options, true);
623
- if (!update && (rows = getCache(queryString))) {
632
+ queryString = (database ? database + '_' + (table ? table + '_' : '') : '') + Cloud.asString(options, true);
633
+ if (!update && (rows = this.getCacheResult(service, credential, queryString, cacheValue, ignoreCache))) {
624
634
  result[i] = rows;
625
635
  continue;
626
636
  }
627
637
  }
628
638
  const instance = createClient(item, 1);
629
- let job;
630
639
  if (database) {
631
640
  const dataset = instance.dataset(database);
632
641
  let target = dataset;
@@ -639,12 +648,12 @@ async function executeBatchQuery(credential, batch, sessionKey) {
639
648
  metadata.view = update;
640
649
  await target.setMetadata(metadata);
641
650
  }
642
- [job] = await dataset.createQueryJob(options);
651
+ const job = (await dataset.createQueryJob(options))[0];
652
+ [rows] = await job.getQueryResults();
643
653
  }
644
654
  else {
645
- [job] = await instance.createQueryJob(options);
655
+ [rows] = await instance.query(options);
646
656
  }
647
- [rows] = await job.getQueryResults();
648
657
  }
649
658
  else if (product === "datastore" || !product && (item.keys || item.kind || query && !table && !id)) {
650
659
  const { keys, kind, options } = item;
@@ -654,7 +663,7 @@ async function executeBatchQuery(credential, batch, sessionKey) {
654
663
  }
655
664
  if (useCache) {
656
665
  queryString = (keys ? Cloud.asString(keys, true) : (kind ? (name ? '_' + name : '') + '_' + Cloud.asString(kind, true) : '') + '_' + Cloud.asString(query, true)) + (limit > 0 ? '_' + limit : 0) + (options ? Cloud.asString(options, true) : '');
657
- if (!update && (rows = getCache(queryString))) {
666
+ if (!update && (rows = this.getCacheResult(service, credential, queryString, cacheValue, ignoreCache))) {
658
667
  result[i] = rows;
659
668
  continue;
660
669
  }
@@ -702,13 +711,17 @@ async function executeBatchQuery(credential, batch, sessionKey) {
702
711
  db.runQuery(task.select('__key__'), options).then(entities => {
703
712
  if ((0, types_1.isArray)(entities)) {
704
713
  const items = entities.map((entity) => db.key(entity[db.KEY]));
705
- db.save({ key: items, data: update }).then(() => resolve()).catch((err) => reject(err));
714
+ db.save({ key: items, data: update })
715
+ .then(() => {
716
+ resolve();
717
+ })
718
+ .catch(reject);
706
719
  }
707
720
  else {
708
721
  resolve();
709
722
  }
710
723
  })
711
- .catch((err) => reject(err));
724
+ .catch(reject);
712
725
  });
713
726
  }
714
727
  [rows] = await db.runQuery(task, options);
@@ -723,7 +736,7 @@ async function executeBatchQuery(credential, batch, sessionKey) {
723
736
  const options = Array.isArray(id) ? item.options : null;
724
737
  if (useCache) {
725
738
  queryString = table + '_' + id + (options ? Cloud.asString(options, true) : '');
726
- if ((!update || Array.isArray(id)) && (rows = getCache(queryString))) {
739
+ if ((!update || Array.isArray(id)) && (rows = this.getCacheResult(service, credential, queryString, cacheValue, ignoreCache))) {
727
740
  result[i] = rows;
728
741
  continue;
729
742
  }
@@ -739,7 +752,7 @@ async function executeBatchQuery(credential, batch, sessionKey) {
739
752
  else {
740
753
  const doc = db.collection(table).doc(id);
741
754
  if ((0, types_1.isPlainObject)(update)) {
742
- const pattern = /^__(delete|serverTimestamp|increment)(?:<(.+)>)?__$/;
755
+ const pattern = /^__(delete|serverTimestamp|increment|vector|(?:array)(?:Union|Remove))(?:<(.+)>)?__$/s;
743
756
  for (const attr in update) {
744
757
  const match = pattern.exec(attr);
745
758
  if (match) {
@@ -752,6 +765,41 @@ async function executeBatchQuery(credential, batch, sessionKey) {
752
765
  case 'increment':
753
766
  update[attr] = firestore_1.FieldValue.increment(match[2] ? +match[2] : 1);
754
767
  break;
768
+ case 'vector':
769
+ if (match[2]) {
770
+ update[attr] = firestore_1.FieldValue.vector(match[2].split(',').map(unit => parseFloat(unit)));
771
+ }
772
+ break;
773
+ case 'arrayUnion':
774
+ case 'arrayRemove':
775
+ if (match[2]) {
776
+ update[attr] = firestore_1.FieldValue[method](...match[2].trim().split(/(?<!\\)\s*,\s*/).map(unit => {
777
+ switch (unit) {
778
+ case 'true':
779
+ return true;
780
+ case 'false':
781
+ return false;
782
+ case 'undefined':
783
+ return undefined;
784
+ case 'null':
785
+ return null;
786
+ }
787
+ if (isNaN(+unit)) {
788
+ return +unit;
789
+ }
790
+ const a = unit[0];
791
+ const b = unit[unit.length - 1];
792
+ if (a === '[' && b === ']' || a === '{' && b === '}') {
793
+ try {
794
+ return JSON.parse(unit.replace(/\\,/g, ','));
795
+ }
796
+ catch {
797
+ }
798
+ }
799
+ return unit;
800
+ }));
801
+ }
802
+ break;
755
803
  }
756
804
  }
757
805
  }
@@ -775,61 +823,76 @@ async function executeBatchQuery(credential, batch, sessionKey) {
775
823
  }
776
824
  }
777
825
  else if (Array.isArray(query)) {
778
- const orderBy = item.orderBy;
779
- if (useCache && (rows = getCache(queryString = table + '_' + Cloud.asString(query, true) + '_' + Cloud.asString(orderBy, true) + (limit > 0 ? '_' + limit : '')))) {
780
- result[i] = rows;
781
- continue;
782
- }
783
- let db = createClient(item, 3).collection(table);
784
- for (const args of query) {
785
- if ((0, types_1.isArray)(args)) {
786
- const method = args[0];
787
- const params = args.slice(1);
788
- switch (method) {
789
- case 'whereAnd':
790
- case 'whereOr':
791
- if (!params.every(p => (0, types_1.isArray)(p))) {
792
- throw (0, types_1.errorMessage)(method, 'Conditionals are not in array format', Cloud.asString(params));
793
- }
794
- db = db.where(firestore_1.Filter[method === 'whereAnd' ? 'and' : 'or'](...params.map((p) => firestore_1.Filter.where(p[0], p[1], p[2]))));
795
- break;
796
- case 'where':
797
- case 'orderBy':
798
- params[0] = asFieldPath(params[0]);
799
- db = db[method].apply(db, params);
800
- case 'select':
801
- params.forEach((field, index) => {
802
- params[index] = asFieldPath(field);
803
- });
804
- db = db.select.apply(db, params);
805
- break;
806
- case 'endAt':
807
- case 'endBefore':
808
- case 'limit':
809
- case 'limitToLast':
810
- case 'offset':
811
- case 'startAfter':
812
- case 'startAt':
813
- case 'withConverter':
814
- db = db[method].apply(db, params);
815
- break;
816
- }
826
+ const db = createClient(item, 3).collection(table);
827
+ if (item.params && query.every(value => typeof value === 'number')) {
828
+ const options = item.options;
829
+ if (useCache && (rows = this.getCacheResult(service, credential, queryString = table + '_' + Cloud.asString(item.params, true) + '_' + Cloud.asString(query, true) + (options ? Cloud.asString(options, true) : ''), cacheValue, ignoreCache))) {
830
+ result[i] = rows;
831
+ continue;
817
832
  }
833
+ rows = (await db.findNearest(asFieldPath(item.params), firestore_1.FieldValue.vector(query), options).get()).docs.map(doc => doc.data());
818
834
  }
819
- if (Array.isArray(orderBy)) {
820
- for (const order of orderBy) {
821
- if ((0, types_1.isArray)(order)) {
822
- db = db.orderBy(asFieldPath(order[0]), order[1]);
835
+ else {
836
+ const orderBy = item.orderBy;
837
+ if (useCache && (rows = this.getCacheResult(service, credential, queryString = table + '_' + Cloud.asString(query, true) + '_' + Cloud.asString(orderBy, true) + (limit > 0 ? '_' + limit : ''), cacheValue, ignoreCache))) {
838
+ result[i] = rows;
839
+ continue;
840
+ }
841
+ let target = db;
842
+ for (const args of query) {
843
+ if ((0, types_1.isArray)(args)) {
844
+ const method = args[0];
845
+ const params = args.slice(1);
846
+ switch (method) {
847
+ case 'whereAnd':
848
+ case 'whereOr':
849
+ if (!params.every(p => (0, types_1.isArray)(p))) {
850
+ throw (0, types_1.errorMessage)(method, 'Conditionals are not in array format', Cloud.asString(params));
851
+ }
852
+ target = target.where(firestore_1.Filter[method === 'whereAnd' ? 'and' : 'or'](...params.map((p) => firestore_1.Filter.where(p[0], p[1], p[2]))));
853
+ break;
854
+ case 'findNearest':
855
+ params[0] = asFieldPath(params[0]);
856
+ target = target.findNearest.apply(target, params).query;
857
+ break;
858
+ case 'where':
859
+ case 'orderBy':
860
+ params[0] = asFieldPath(params[0]);
861
+ target = target[method].apply(target, params);
862
+ case 'select':
863
+ params.forEach((field, index) => {
864
+ params[index] = asFieldPath(field);
865
+ });
866
+ target = target.select.apply(target, params);
867
+ break;
868
+ case 'endAt':
869
+ case 'endBefore':
870
+ case 'limit':
871
+ case 'limitToLast':
872
+ case 'offset':
873
+ case 'startAfter':
874
+ case 'startAt':
875
+ case 'withConverter':
876
+ target = target[method].apply(target, params);
877
+ break;
878
+ }
823
879
  }
824
- else if ((0, types_1.isString)(order)) {
825
- db = db.orderBy(order);
880
+ }
881
+ if (Array.isArray(orderBy)) {
882
+ for (const order of orderBy) {
883
+ if ((0, types_1.isArray)(order)) {
884
+ target = target.orderBy(asFieldPath(order[0]), order[1]);
885
+ }
886
+ else if ((0, types_1.isString)(order)) {
887
+ target = target.orderBy(order);
888
+ }
826
889
  }
827
890
  }
891
+ if (limit > 0) {
892
+ target = target.limit(limit);
893
+ }
894
+ rows = (await target.get()).docs.map(doc => doc.data());
828
895
  }
829
- if (limit > 0) {
830
- db = db.limit(limit);
831
- }
832
- rows = (await db.get()).docs.map(doc => doc.data());
833
896
  }
834
897
  else {
835
898
  closeClient();
@@ -845,7 +908,6 @@ async function executeBatchQuery(credential, batch, sessionKey) {
845
908
  closeClient();
846
909
  return result;
847
910
  }
848
- exports.executeBatchQuery = executeBatchQuery;
849
911
  function setPublicRead(acl, pathname, requested, service = 'gcp') {
850
912
  acl.add({ entity: 'allUsers', role: 'READER' })
851
913
  .then(() => {
@@ -859,7 +921,6 @@ function setPublicRead(acl, pathname, requested, service = 'gcp') {
859
921
  }
860
922
  });
861
923
  }
862
- exports.setPublicRead = setPublicRead;
863
924
  async function setPredefinedAcl(target, value, bucket, pathname = '', metadata = {}, requested = true, service = 'gcp') {
864
925
  let revoke;
865
926
  if (metadata === true) {
@@ -929,7 +990,7 @@ async function setPredefinedAcl(target, value, bucket, pathname = '', metadata =
929
990
  }
930
991
  }
931
992
  return updatePredefinedAcl(target, items, metadata).then(errors => {
932
- if (errors.length) {
993
+ if (errors.length > 0) {
933
994
  this.formatMessage(64, service, [`Unable to ${revoke ? 'revoke' : 'grant'} ` + value, bucket && pathname ? bucket.name + '/' + pathname : bucket ? bucket.name : pathname], errors[0], { ...Cloud.LOG_CLOUD_WARN });
934
995
  }
935
996
  else if (requested && (bucket || pathname)) {
@@ -937,36 +998,58 @@ async function setPredefinedAcl(target, value, bucket, pathname = '', metadata =
937
998
  }
938
999
  });
939
1000
  }
940
- exports.setPredefinedAcl = setPredefinedAcl;
941
1001
  function createBucketRequest(credential) {
942
1002
  const options = {};
943
1003
  for (const attr in credential) {
944
1004
  switch (attr) {
945
1005
  case 'archive':
946
- case 'autoclass':
947
1006
  case 'coldline':
948
- case 'cors':
949
- case 'customPlacementConfig':
1007
+ case 'dataLocations':
950
1008
  case 'dra':
951
1009
  case 'enableObjectRetention':
952
- case 'location':
953
1010
  case 'multiRegional':
954
1011
  case 'nearline':
1012
+ case 'predefinedAcl':
1013
+ case 'predefinedDefaultObjectAcl':
1014
+ case 'projection':
955
1015
  case 'regional':
956
1016
  case 'requesterPays':
1017
+ case 'standard':
1018
+ case 'userProject':
1019
+ case 'acl':
1020
+ case 'autoclass':
1021
+ case 'billing':
1022
+ case 'cors':
1023
+ case 'customPlacementConfig':
1024
+ case 'defaultEventBasedHold':
1025
+ case 'defaultObjectAcl':
1026
+ case 'encryption':
1027
+ case 'hierarchicalNamespace':
1028
+ case 'iamConfiguration':
1029
+ case 'labels':
1030
+ case 'lifecycle':
1031
+ case 'location':
1032
+ case 'locationType':
1033
+ case 'logging':
1034
+ case 'metageneration':
1035
+ case 'name':
1036
+ case 'objectRetention':
1037
+ case 'owner':
1038
+ case 'projectNumber':
957
1039
  case 'retentionPolicy':
958
1040
  case 'rpo':
959
- case 'standard':
1041
+ case 'softDeletePolicy':
960
1042
  case 'storageClass':
961
- case 'userProject':
1043
+ case 'timeCreated':
1044
+ case 'updated':
962
1045
  case 'versioning':
1046
+ case 'website':
963
1047
  options[attr] = credential[attr];
964
1048
  break;
965
1049
  }
966
1050
  }
967
1051
  return options;
968
1052
  }
969
- exports.createBucketRequest = createBucketRequest;
970
1053
  function getProjectId(credential, cache) {
971
1054
  let projectId = credential.projectId;
972
1055
  if (!cache && projectId) {
@@ -994,7 +1077,6 @@ function getProjectId(credential, cache) {
994
1077
  }
995
1078
  return projectId;
996
1079
  }
997
- exports.getProjectId = getProjectId;
998
1080
  exports.CLOUD_UPLOAD_STREAM = true;
999
1081
  exports.CLOUD_UPLOAD_CHUNK = true;
1000
1082
  exports.CLOUD_DOWNLOAD_CHUNK = true;
package/download/index.js CHANGED
@@ -2,10 +2,11 @@
2
2
  const path = require("path");
3
3
  const fs = require("fs");
4
4
  const https = require("https");
5
+ const storage_1 = require("@google-cloud/storage");
5
6
  const types_1 = require("@e-mc/types");
6
7
  const Cloud = require("@e-mc/cloud");
7
8
  const client_1 = require("@pi-r/gcp");
8
- module.exports = function download(credential, service = 'gcp') {
9
+ function download(credential, service = 'gcp') {
9
10
  const storage = client_1.createStorageClient.call(this, credential);
10
11
  return (data, callback) => {
11
12
  const { bucket: Bucket, download: target } = data;
@@ -14,7 +15,9 @@ module.exports = function download(credential, service = 'gcp') {
14
15
  const downloadResponse = (err, url = null) => {
15
16
  callback(err, url);
16
17
  if (tempDir) {
17
- queueMicrotask(() => Cloud.removeDir(tempDir));
18
+ queueMicrotask(() => {
19
+ Cloud.removeDir(tempDir);
20
+ });
18
21
  }
19
22
  };
20
23
  if (!Bucket || !Key) {
@@ -27,25 +30,29 @@ module.exports = function download(credential, service = 'gcp') {
27
30
  }
28
31
  const location = Cloud.joinPath(Bucket, Key);
29
32
  const destination = path.join(tempDir, path.basename(target.filename || Key));
30
- const deleteMessage = () => this.formatMessage(64, service, "Delete success", location, { ...Cloud.LOG_CLOUD_DELETE });
33
+ const deleteMessage = () => {
34
+ this.formatMessage(64, service, "Delete success", location, { ...Cloud.LOG_CLOUD_DELETE });
35
+ };
31
36
  if ((0, client_1.isFirebaseApp)(credential, true, true)) {
32
37
  const { ref, getDownloadURL, deleteObject } = require('@firebase/storage');
33
38
  const objectRef = ref(storage, Key);
34
- getDownloadURL(objectRef).then(url => {
39
+ void getDownloadURL(objectRef).then(url => {
35
40
  https.get(url, res => {
36
41
  const statusCode = res.statusCode;
37
42
  if (statusCode >= 200 && statusCode < 300) {
38
- res.on('error', err => downloadResponse(err));
43
+ res.on('error', downloadResponse);
39
44
  res.pipe(fs.createWriteStream(destination)
40
45
  .on('finish', () => {
41
46
  downloadResponse(null, destination);
42
47
  if (target.deleteObject) {
43
48
  deleteObject(objectRef)
44
- .then(() => deleteMessage())
45
- .catch((err) => this.formatFail(64, service, ["Delete failed", location], err, { ...Cloud.LOG_CLOUD_FAIL, fatal: !!target.active }));
49
+ .then(deleteMessage)
50
+ .catch((err) => {
51
+ this.formatFail(64, service, ["Delete failed", location], err, { ...Cloud.LOG_CLOUD_FAIL, fatal: !!target.active });
52
+ });
46
53
  }
47
54
  })
48
- .on('error', err => downloadResponse(err)));
55
+ .on('error', downloadResponse));
49
56
  }
50
57
  else {
51
58
  downloadResponse((0, types_1.errorMessage)(statusCode, 'Invalid HTTP request', location));
@@ -57,18 +64,8 @@ module.exports = function download(credential, service = 'gcp') {
57
64
  const { flags = 0 } = target;
58
65
  const bucket = storage.bucket(Bucket);
59
66
  const file = bucket.file(Key, { generation: target.versionId });
60
- const chunkSize = flags & 4 ? (0, types_1.alignSize)(target.chunkSize, 1024) : 0;
61
- let manager;
62
- if (chunkSize > 0) {
63
- const { TransferManager } = require('@google-cloud/storage');
64
- let concurrencyLimit = target.chunkLimit;
65
- if (!concurrencyLimit && target.options) {
66
- ({ concurrencyLimit } = target.options);
67
- }
68
- manager = new TransferManager(bucket).downloadFileInChunks(file, { destination, chunkSizeBytes: chunkSize, concurrencyLimit });
69
- }
70
- (manager || file.download({ destination }))
71
- .then(() => {
67
+ const chunkSizeBytes = flags & 4 ? (0, types_1.alignSize)(target.chunkSize, 1024) : 0;
68
+ const fileDownload = () => {
72
69
  downloadResponse(null, destination);
73
70
  const deleteObject = target.deleteObject;
74
71
  if (deleteObject) {
@@ -81,7 +78,27 @@ module.exports = function download(credential, service = 'gcp') {
81
78
  }
82
79
  });
83
80
  }
84
- })
85
- .catch((err) => downloadResponse(err));
81
+ };
82
+ if (chunkSizeBytes > 0) {
83
+ new storage_1.TransferManager(bucket).downloadFileInChunks(file, {
84
+ destination,
85
+ chunkSizeBytes,
86
+ concurrencyLimit: target.chunkLimit || target.options?.concurrencyLimit
87
+ })
88
+ .then(fileDownload)
89
+ .catch(downloadResponse);
90
+ }
91
+ else if (target.chunkLimit === 1 && !target.chunkSize) {
92
+ file.createReadStream()
93
+ .pipe(fs.createWriteStream(destination))
94
+ .on('finish', fileDownload)
95
+ .on('error', downloadResponse);
96
+ }
97
+ else {
98
+ file.download({ destination })
99
+ .then(fileDownload)
100
+ .catch(downloadResponse);
101
+ }
86
102
  };
87
- };
103
+ }
104
+ module.exports = download;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-r/gcp",
3
- "version": "0.7.3",
3
+ "version": "0.8.1",
4
4
  "description": "Google (GCP) cloud functions for E-mc.",
5
5
  "main": "client/index.js",
6
6
  "publishConfig": {
@@ -20,10 +20,10 @@
20
20
  "license": "MIT",
21
21
  "homepage": "https://github.com/anpham6/pi-r#readme",
22
22
  "dependencies": {
23
- "@e-mc/cloud": "^0.9.6",
24
- "@e-mc/module": "^0.9.6",
25
- "@e-mc/types": "^0.9.6",
23
+ "@e-mc/cloud": "^0.10.0",
24
+ "@e-mc/module": "^0.10.0",
25
+ "@e-mc/types": "^0.10.0",
26
26
  "@google-cloud/firestore": "^7.9.0",
27
- "@google-cloud/storage": "^7.12.0"
27
+ "@google-cloud/storage": "^7.12.1"
28
28
  }
29
29
  }
package/types/index.d.ts CHANGED
@@ -12,7 +12,7 @@ export type GCPStorage = CloudStorage<GCPStorageCredential, "gcp | gcloud">;
12
12
 
13
13
  export interface GCPStorageCredential extends StorageOptions, IFirebaseOptions {}
14
14
 
15
- export interface GCPDatabaseQuery<T = PlainObject> extends Omit<CloudDatabase<unknown, T, unknown, unknown[] | StandardMap, GCPDatabaseCredential>, "id"> {
15
+ export interface GCPDatabaseQuery<T = PlainObject> extends Omit<CloudDatabase<unknown, T, unknown, string | unknown[] | StandardMap, GCPDatabaseCredential>, "id"> {
16
16
  source: "cloud";
17
17
  service: "gcp" | "gcloud";
18
18
  product?: "firestore" | "firebase" | "bigquery" | "bigtable" | "datastore" | "spanner";
package/upload/index.js CHANGED
@@ -2,14 +2,14 @@
2
2
  const path = require("path");
3
3
  const fs = require("fs");
4
4
  const stream = require("stream");
5
+ const Cloud = require("@e-mc/cloud");
5
6
  const util_1 = require("@e-mc/cloud/util");
6
7
  const types_1 = require("@e-mc/types");
7
- const Cloud = require("@e-mc/cloud");
8
8
  const client_1 = require("@pi-r/gcp");
9
9
  const BUCKET_SESSION = new Set();
10
10
  const BUCKET_RESPONSE = {};
11
11
  const getBucketKey = (credential, bucket, acl = '') => Cloud.asString(credential, true) + bucket + '_' + acl;
12
- module.exports = function upload(credential, service = 'gcp') {
12
+ function upload(credential, service = 'gcp') {
13
13
  const storage = client_1.createStorageClient.call(this, credential);
14
14
  return async (data, callback) => {
15
15
  const firebase = (0, client_1.isFirebaseApp)(credential, true, true);
@@ -25,7 +25,11 @@ module.exports = function upload(credential, service = 'gcp') {
25
25
  }
26
26
  callback(err, url);
27
27
  };
28
- const addLog = (err) => err instanceof Error && this.addLog(this.statusType.WARN, err, service, bucket);
28
+ const addLog = (err) => {
29
+ if (err instanceof Error) {
30
+ this.addLog(this.statusType.WARN, err, service, bucket);
31
+ }
32
+ };
29
33
  if (firebase) {
30
34
  const { ref, listAll } = require('@firebase/storage');
31
35
  bucketClient = ref(storage, bucket);
@@ -53,11 +57,17 @@ module.exports = function upload(credential, service = 'gcp') {
53
57
  bucketClient = storage.bucket(bucket);
54
58
  if (configBucket) {
55
59
  let { cors, lifecycle, retentionPolicy } = configBucket;
56
- const commandMessage = (feature, message) => this.formatMessage(64, service, ["Bucket configured" + ` (${feature})`, bucket], message, { ...Cloud.LOG_CLOUD_COMMAND });
60
+ const commandMessage = (feature, message) => {
61
+ this.formatMessage(64, service, ["Bucket configured" + ` (${feature})`, bucket], message, { ...Cloud.LOG_CLOUD_COMMAND });
62
+ };
57
63
  if (typeof retentionPolicy === 'number') {
58
64
  bucketClient.setRetentionPeriod(retentionPolicy)
59
- .then(([response]) => commandMessage('Retention Policy', response.retentionPolicy?.effectiveTime))
60
- .catch((err) => addLog(err));
65
+ .then(([response]) => {
66
+ commandMessage('Retention Policy', response.retentionPolicy?.effectiveTime);
67
+ })
68
+ .catch((err) => {
69
+ addLog(err);
70
+ });
61
71
  }
62
72
  if ((0, types_1.isObject)(cors)) {
63
73
  bucketClient.setCorsConfiguration(Array.isArray(cors) ? cors : [cors])
@@ -65,7 +75,9 @@ module.exports = function upload(credential, service = 'gcp') {
65
75
  const length = response.cors?.length;
66
76
  commandMessage('CORS', length ? length + ' rules' : null);
67
77
  })
68
- .catch((err) => addLog(err));
78
+ .catch((err) => {
79
+ addLog(err);
80
+ });
69
81
  }
70
82
  if ((0, types_1.isObject)(lifecycle)) {
71
83
  let append;
@@ -86,7 +98,9 @@ module.exports = function upload(credential, service = 'gcp') {
86
98
  const length = response.lifecycle?.rule?.length;
87
99
  commandMessage('Lifecycle', length ? length + ' rules' : null);
88
100
  })
89
- .catch((err) => addLog(err));
101
+ .catch((err) => {
102
+ addLog(err);
103
+ });
90
104
  }
91
105
  }
92
106
  if (flags & 4) {
@@ -175,7 +189,7 @@ module.exports = function upload(credential, service = 'gcp') {
175
189
  }
176
190
  else if ((flags & 2) && !firebase) {
177
191
  try {
178
- Stream.push(data.buffer.length ? stream.Readable.from(data.buffer) : fs.createReadStream(localUri, { signal: this.signal }));
192
+ Stream.push(data.buffer.length > 0 ? stream.Readable.from(data.buffer) : fs.createReadStream(localUri, { signal: this.signal }));
179
193
  if (fileGroup) {
180
194
  const [key, body, type] = (0, util_1.createKeyAndBody)(filename, fileGroup, 0, addLog, 2);
181
195
  Key.push(...key);
@@ -317,10 +331,12 @@ module.exports = function upload(credential, service = 'gcp') {
317
331
  uploadResponse(null, url);
318
332
  }
319
333
  if (Path[i]) {
320
- file.setMetadata(params).catch((err) => addLog(err));
334
+ file.setMetadata(params).catch((err) => {
335
+ addLog(err);
336
+ });
321
337
  }
322
338
  if (ACL) {
323
- client_1.setPredefinedAcl.call(this, file.acl, ACL, file.bucket, file.name, revoke || (await file.getMetadata())[0], true);
339
+ void client_1.setPredefinedAcl.call(this, file.acl, ACL, file.bucket, file.name, revoke || (await file.getMetadata())[0], true);
324
340
  }
325
341
  })
326
342
  .catch((err) => {
@@ -334,4 +350,5 @@ module.exports = function upload(credential, service = 'gcp') {
334
350
  }
335
351
  }
336
352
  };
337
- };
353
+ }
354
+ module.exports = upload;