diff --git a/.eslintrc.js b/.eslintrc.js index 5638fbfb3..c9a789df1 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,5 +1,9 @@ -/* eslint max-len: [0] */ +// Ignore checking the js file generated by ts +const buckets = ['dataIndex.js']; +const ignorePatterns = ['lib/common/utils/*.js'].concat(buckets.map(item => `lib/common/bucket/${item}`)); + module.exports = { + ignorePatterns, extends: ['airbnb', 'eslint-config-ali/typescript', 'prettier'], parserOptions: { ecmaFeatures: { @@ -16,7 +20,6 @@ module.exports = { }, rules: { indent: ['error', 2], - // override default options 'no-underscore-dangle': [0], 'no-plusplus': [0], 'no-return-await': [0], diff --git a/README.md b/README.md index c6e09a521..0bdd1ddbf 100644 --- a/README.md +++ b/README.md @@ -126,6 +126,11 @@ All operation use es7 async/await to implement. All api is async function. - [.extendBucketWorm(name, wormId, days[, options])](#extendBucketWormname-wormId-days-options) - [.getBucketWorm(name[, options])](#getBucketWormname-options) - [.initiateBucketWorm(name, days[, options])](#initiateBucketWormname-days-options) + - Data Indexing + - [.openMetaQuery(bucketName[, options])](#openMetaQueryBucketName-options) + - [.getMetaQueryStatus(bucketName[, options])](#getMetaQueryStatusBucketName-options) + - [.doMetaQuery(bucketName, queryParam[, options])](#doMetaQueryBucketName-queryParam-options) + - [.closeMetaQuery(bucketName[, options])](#closeMetaQueryBucketName-options) - [Object Operations](#object-operations) - [.list(query[, options])](#listquery-options) @@ -1653,6 +1658,129 @@ Success will return: --- +### .openMetaQuery(bucketName[, options]) + +Enables the metadata management feature for a bucket. + +parameters: + +- bucketName {String} bucket name +- [options] {Object} optional args + +Success will return: + +- status {Number} response status +- res {Object} response info + +--- + +### .getMetaQueryStatus(bucketName[, options]) + +Queries the information about the metadata index library of a bucket. + +parameters: + +- bucketName {String} bucket name +- [options] {Object} optional args + +Success will return: + +- status {Number} response status +- res {Object} response info +- phase {String} the scan type +- state {String} he status of the metadata index library +- createTime {Date} the time when the metadata index library was created +- updateTime {Date} the time when the metadata index library was updated + +--- + +### .doMetaQuery(bucketName, queryParam[, options]) + +Query files (Objects) that meet the specified conditions and list file information according to the specified fields and sorting method. + +parameters: + +- bucketName {String} the bucket name +- queryParam {Object} query parameters + - nextToken {String} The token that is used for the next query when the total number of objects exceeds the value of MaxResults. The object information is returned in alphabetical order starting from the value of NextToken. When this operation is called for the first time, set this field to null. + - maxResults {Number} The maximum number of objects to return. Valid values: 0 to 100. If this parameter is not set or is set to 0, 100 objects are returned. + - query {Object} query criteria + - field {String} Field name. Please refer to Appendix: Support List for Fields and Operators. + - value {String} The value of the field. + - operation {String} The operators. Valid values: eq (equal to), gt (greater than), gte (greater than or equal to), lt (less than), lte (less than or equal to), match (fuzzy query), prefix (prefix query), and (AND), or (OR), and not (NOT). + - subQueries {Array} The subquery conditions. Options that are included in this element are the same as those of simple query. You must set subquery conditions only when Operation is set to AND, OR, or NOT. + - sort {String} The field based on which the results are sorted. For more information about the fields that can be sorted. Please refer to Appendix: Support List for Fields and Operators. + - order {String} `asc` | `desc` The order in which you want to sort the queried data. Default value: desc. + - aggregations {Object} The container for the information about aggregate operations. + - field {String} The name of the field. For more information about supported fields and supported operators. Please refer to Appendix: Support List for Fields and Operators. + - operation {String} The operator for aggregate operations. Valid values:min,max,average,sum,count,distinct,group. +- [options] {Object} optional parameters + - [timeout] {Number} the operation timeout (ms) + +Success will return: + +- status {Number} response status +- res {Object} response info, including + - status {Number} response status + - headers {Object} response headers + - size {Number} response size + - rt {Number} request total use time (ms) +- nextToken {String} the token that is used for the next query when the total number of objects exceeds the value of MaxResults +- files {Array} the container for the information about objects +- aggregations {Array} the container for the information about aggregate operations + +--- + +example: + +```js +const result = await store.put('test.txt', 'hello world'); +console.log(result); +``` + +--- + +###.get(name[, options]) + +Get the object content. + +parameters: + +- name {String} object name store on OSS + +--- + +example: + +```js +const queryParam = { + maxResults: 2, + query: { operation: 'and', subQueries: [{ field: 'Size', value: '1048575', operation: 'lt' }] }, + sort: 'Size', + order: 'asc' +}; +const result = await store.doMetaQuery(bucket, queryParam); +console.log(result); +``` + +--- + +### .closeMetaQuery(bucketName[, options]) + +Disables the metadata management feature for a bucket. + +parameters: + +- bucketName {String} bucket name +- [options] {Object} optional args + +Success will return: + +- status {Number} response status +- res {Object} response info + +--- + ## Object Operations All operations function return Promise, except `signatureUrl`. diff --git a/lib/browser/client.js b/lib/browser/client.js index 482222bae..1acdee32d 100644 --- a/lib/browser/client.js +++ b/lib/browser/client.js @@ -105,6 +105,9 @@ merge(proto, require('../common/bucket/getBucketWebsite')); merge(proto, require('../common/bucket/putBucketWebsite')); merge(proto, require('../common/bucket/deleteBucketWebsite')); +// bucket data index +merge(proto, require('../common/bucket/dataIndex')); + // lifecycle merge(proto, require('../common/bucket/getBucketLifecycle')); merge(proto, require('../common/bucket/putBucketLifecycle')); diff --git a/lib/common/bucket/dataIndex.d.ts b/lib/common/bucket/dataIndex.d.ts new file mode 100644 index 000000000..ab8f10509 --- /dev/null +++ b/lib/common/bucket/dataIndex.d.ts @@ -0,0 +1,59 @@ +export declare function openMetaQuery( + this: any, + bucketName: string, + options?: {} +): Promise<{ + res: any; + status: any; +}>; +export declare function getMetaQueryStatus( + this: any, + bucketName: string, + options?: {} +): Promise<{ + res: any; + status: any; + phase: any; + state: any; + createTime: any; + updateTime: any; +}>; +interface ISubQuerie { + field?: string; + value?: string; + operation: string; + subQueries?: ISubQuerie[]; +} +interface IAggregation { + field: string; + operation: string; +} +interface IMetaQuery { + nextToken?: string; + maxResults?: number; + query: ISubQuerie; + sort?: string; + order?: 'asc' | 'desc'; + aggregations?: IAggregation[]; +} +export declare function doMetaQuery( + this: any, + bucketName: string, + queryParam: IMetaQuery, + options?: {} +): Promise<{ + res: any; + status: any; + nextToken: any; + files: any; + aggregations: any; +}>; +export declare function closeMetaQuery( + this: any, + bucketName: string, + options?: {} +): Promise<{ + res: any; + status: any; +}>; +export {}; diff --git a/lib/common/bucket/dataIndex.js b/lib/common/bucket/dataIndex.js new file mode 100644 index 000000000..26719908c --- /dev/null +++ b/lib/common/bucket/dataIndex.js @@ -0,0 +1,146 @@ +'use strict'; +Object.defineProperty(exports, '__esModule', { value: true }); +exports.closeMetaQuery = exports.doMetaQuery = exports.getMetaQueryStatus = exports.openMetaQuery = void 0; +/* eslint-disable max-len */ +// https://help.aliyun.com/zh/oss/developer-reference/data-indexing +const checkBucketName_1 = require('../utils/checkBucketName'); +const obj2xml_1 = require('../utils/obj2xml'); +const formatObjKey_1 = require('../utils/formatObjKey'); +async function openMetaQuery(bucketName, options = {}) { + checkBucketName_1.checkBucketName(bucketName); + const params = this._bucketRequestParams('POST', bucketName, { metaQuery: '', comp: 'add' }, options); + const result = await this.request(params); + if (result.status === 200) { + return { + res: result.res, + status: result.status + }; + } + throw await this.requestError(result); +} +exports.openMetaQuery = openMetaQuery; +async function getMetaQueryStatus(bucketName, options = {}) { + checkBucketName_1.checkBucketName(bucketName); + const params = this._bucketRequestParams('GET', bucketName, 'metaQuery', options); + const result = await this.request(params); + if (result.status === 200) { + const data = await this.parseXML(result.data); + return { + res: result.res, + status: result.status, + phase: data.Phase, + state: data.State, + createTime: data.CreateTime, + updateTime: data.UpdateTime + }; + } + throw await this.requestError(result); +} +exports.getMetaQueryStatus = getMetaQueryStatus; +async function doMetaQuery(bucketName, queryParam, options = {}) { + checkBucketName_1.checkBucketName(bucketName); + const params = this._bucketRequestParams('POST', bucketName, { metaQuery: '', comp: 'query' }, options); + const { aggregations } = queryParam; + let Aggregations; + if (aggregations && aggregations.length > 0) { + Aggregations = { + Aggregation: aggregations.map(item => ({ Field: item.field, Operation: item.operation })) + }; + } + const paramXMLObj = { + MetaQuery: { + NextToken: queryParam.nextToken, + MaxResults: queryParam.maxResults, + Query: JSON.stringify(formatObjKey_1.formatObjKey(queryParam.query, 'firstUpperCase')), + Sort: queryParam.sort, + Order: queryParam.order, + Aggregations + } + }; + params.mime = 'xml'; + params.content = obj2xml_1.obj2xml(paramXMLObj, { headers: true, firstUpperCase: true }); + const result = await this.request(params); + if (result.status === 200) { + const { NextToken, Files, Aggregations: aggRes } = await this.parseXML(result.data); + let files; + if (Files && Files.File) { + const getFileObject = item => { + var _a, _b; + return { + fileName: item.Filename, + size: item.Size, + fileModifiedTime: item.FileModifiedTime, + ossObjectType: item.OSSObjectType, + ossStorageClass: item.OSSStorageClass, + objectACL: item.ObjectACL, + eTag: item.ETag, + ossTaggingCount: item.OSSTaggingCount, + ossTagging: + (_a = item.OSSTagging) === null || _a === void 0 + ? void 0 + : _a.map(tagging => ({ + key: tagging.Key, + value: tagging.Value + })), + ossUserMeta: + (_b = item.OSSUserMeta) === null || _b === void 0 + ? void 0 + : _b.map(meta => ({ + key: meta.Key, + value: meta.Value + })), + ossCRC64: item.OSSCRC64, + serverSideEncryption: item.ServerSideEncryption, + serverSideEncryptionCustomerAlgorithm: item.ServerSideEncryptionCustomerAlgorithm + }; + }; + if (Files.File instanceof Array) { + files = Files.File.map(getFileObject); + } else { + files = [getFileObject(Files.File)]; + } + } + let aggList; + if (aggRes) { + const getAggregationObject = item => { + var _a; + return { + field: item.Field, + operation: item.Operation, + value: item.Value, + groups: + (_a = item.Groups) === null || _a === void 0 + ? void 0 + : _a.map(group => ({ + value: group.Value, + count: group.Count + })) + }; + }; + if (aggRes.Aggregation instanceof Array) { + aggList = aggRes.Aggregation.map(getAggregationObject); + } else { + aggList = [getAggregationObject(aggRes.Aggregation)]; + } + } + return { + res: result.res, + status: result.status, + nextToken: NextToken, + files, + aggregations: aggList + }; + } + throw await this.requestError(result); +} +exports.doMetaQuery = doMetaQuery; +async function closeMetaQuery(bucketName, options = {}) { + checkBucketName_1.checkBucketName(bucketName); + const params = this._bucketRequestParams('POST', bucketName, { metaQuery: '', comp: 'delete' }, options); + const result = await this.request(params); + return { + res: result.res, + status: result.status + }; +} +exports.closeMetaQuery = closeMetaQuery; diff --git a/lib/common/bucket/dataIndex.ts b/lib/common/bucket/dataIndex.ts new file mode 100644 index 000000000..c7dbcaae9 --- /dev/null +++ b/lib/common/bucket/dataIndex.ts @@ -0,0 +1,175 @@ +/* eslint-disable max-len */ +// https://help.aliyun.com/zh/oss/developer-reference/data-indexing +import { checkBucketName } from '../utils/checkBucketName'; +import { obj2xml } from '../utils/obj2xml'; +import { formatObjKey } from '../utils/formatObjKey'; + +export async function openMetaQuery(this: any, bucketName: string, options = {}) { + checkBucketName(bucketName); + const params = this._bucketRequestParams('POST', bucketName, { metaQuery: '', comp: 'add' }, options); + + const result = await this.request(params); + + if (result.status === 200) { + return { + res: result.res, + status: result.status + }; + } + + throw await this.requestError(result); +} + +export async function getMetaQueryStatus(this: any, bucketName: string, options = {}) { + checkBucketName(bucketName); + const params = this._bucketRequestParams('GET', bucketName, 'metaQuery', options); + + const result = await this.request(params); + + if (result.status === 200) { + const data = await this.parseXML(result.data); + return { + res: result.res, + status: result.status, + phase: data.Phase, + state: data.State, + createTime: data.CreateTime, + updateTime: data.UpdateTime + }; + } + + throw await this.requestError(result); +} + +// https://help.aliyun.com/zh/oss/developer-reference/appendix-supported-fields-and-operators +interface ISubQuerie { + // the fields. For more information about supported fields and supported operators + field?: string; + // the value of the field. + value?: string; + // the operators. Valid values: eq (equal to), gt (greater than), gte (greater than or equal to), lt (less than), lte (less than or equal to), match (fuzzy query), prefix (prefix query), and (AND), or (OR), and not (NOT). + operation: string; + // the subquery conditions. Options that are included in this element are the same as those of simple query. You must set subquery conditions only when Operation is set to AND, OR, or NOT. + subQueries?: ISubQuerie[]; +} + +interface IAggregation { + // The name of the field. For more information about supported fields and supported operators + field: string; + // The operator for aggregate operations. Valid values:min,max,average,sum,count,distinct,group + operation: string; +} + +interface IMetaQuery { + // The token that is used for the next query when the total number of objects exceeds the value of MaxResults. The object information is returned in alphabetical order starting from the value of NextToken. When this operation is called for the first time, set this field to null. + nextToken?: string; + // The maximum number of objects to return. Valid values: 0 to 100. If this parameter is not set or is set to 0, 100 objects are returned. + maxResults?: number; + query: ISubQuerie; + // The field based on which the results are sorted. For more information about the fields that can be sorted + sort?: string; + // The order in which you want to sort the queried data. Default value: desc. + order?: 'asc' | 'desc'; + // The container for the information about aggregate operations. + aggregations?: IAggregation[]; +} + +export async function doMetaQuery(this: any, bucketName: string, queryParam: IMetaQuery, options = {}) { + checkBucketName(bucketName); + const params = this._bucketRequestParams('POST', bucketName, { metaQuery: '', comp: 'query' }, options); + + const { aggregations } = queryParam; + let Aggregations; + if (aggregations && aggregations.length > 0) { + Aggregations = { + Aggregation: aggregations.map(item => ({ Field: item.field, Operation: item.operation })) + }; + } + + const paramXMLObj = { + MetaQuery: { + NextToken: queryParam.nextToken, + MaxResults: queryParam.maxResults, + Query: JSON.stringify(formatObjKey(queryParam.query, 'firstUpperCase')), + Sort: queryParam.sort, + Order: queryParam.order, + Aggregations + } + }; + params.mime = 'xml'; + params.content = obj2xml(paramXMLObj, { headers: true, firstUpperCase: true }); + + const result = await this.request(params); + if (result.status === 200) { + const { NextToken, Files, Aggregations: aggRes } = await this.parseXML(result.data); + + let files; + if (Files && Files.File) { + const getFileObject = item => ({ + fileName: item.Filename, + size: item.Size, + fileModifiedTime: item.FileModifiedTime, + ossObjectType: item.OSSObjectType, + ossStorageClass: item.OSSStorageClass, + objectACL: item.ObjectACL, + eTag: item.ETag, + ossTaggingCount: item.OSSTaggingCount, + ossTagging: item.OSSTagging?.map(tagging => ({ + key: tagging.Key, + value: tagging.Value + })), + ossUserMeta: item.OSSUserMeta?.map(meta => ({ + key: meta.Key, + value: meta.Value + })), + ossCRC64: item.OSSCRC64, + serverSideEncryption: item.ServerSideEncryption, + serverSideEncryptionCustomerAlgorithm: item.ServerSideEncryptionCustomerAlgorithm + }); + if (Files.File instanceof Array) { + files = Files.File.map(getFileObject); + } else { + files = [getFileObject(Files.File)]; + } + } + + let aggList; + if (aggRes) { + const getAggregationObject = item => ({ + field: item.Field, + operation: item.Operation, + value: item.Value, + groups: item.Groups?.map(group => ({ + value: group.Value, + count: group.Count + })) + }); + if (aggRes.Aggregation instanceof Array) { + aggList = aggRes.Aggregation.map(getAggregationObject); + } else { + aggList = [getAggregationObject(aggRes.Aggregation)]; + } + } + + return { + res: result.res, + status: result.status, + nextToken: NextToken, + files, + aggregations: aggList + }; + } + + throw await this.requestError(result); +} + +export async function closeMetaQuery(this: any, bucketName: string, options = {}) { + checkBucketName(bucketName); + const params = this._bucketRequestParams('POST', bucketName, { metaQuery: '', comp: 'delete' }, options); + + const result = await this.request(params); + return { + res: result.res, + status: result.status + }; +} diff --git a/lib/common/bucket/index.js b/lib/common/bucket/index.js index 3e394e079..296000f63 100644 --- a/lib/common/bucket/index.js +++ b/lib/common/bucket/index.js @@ -32,3 +32,4 @@ merge(proto, require('./extendBucketWorm')); merge(proto, require('./getBucketWorm')); merge(proto, require('./initiateBucketWorm')); merge(proto, require('./getBucketStat')); +merge(proto, require('./dataIndex')); diff --git a/test/browser/browser.test.js b/test/browser/browser.test.js index 75c4ea897..8ab22bb80 100644 --- a/test/browser/browser.test.js +++ b/test/browser/browser.test.js @@ -38,8 +38,8 @@ const cleanBucket = async store => { const uploads = result.uploads || []; await Promise.all(uploads.map(_ => store.abortMultipartUpload(_.name, _.uploadId))); }; + describe('browser', () => { - /* eslint require-yield: [0] */ before(() => { ossConfig = { region: stsConfig.region, @@ -48,14 +48,8 @@ describe('browser', () => { stsToken: stsConfig.Credentials.SecurityToken, bucket: stsConfig.bucket }; - // this.store = oss({ - // region: stsConfig.region, - // accessKeyId: creds.AccessKeyId, - // accessKeySecret: creds.AccessKeySecret, - // stsToken: creds.SecurityToken, - // bucket: stsConfig.bucket - // }); }); + after(async () => { const store = oss(ossConfig); await cleanBucket(store); @@ -1625,7 +1619,6 @@ describe('browser', () => { // } // }); // assert.equal(result.res.status, 200); - // assert.equal(result.data.Status, 'OK'); // }); // TODO fix callback server @@ -1647,7 +1640,6 @@ describe('browser', () => { // } // }); // assert.equal(result.res.status, 200); - // assert.equal(result.data.Status, 'OK'); // }); // TODO fix callback server @@ -2509,4 +2501,132 @@ describe('browser', () => { } }); }); + + describe('bucket data index', () => { + let store; + const { bucket } = stsConfig; + before(async () => { + store = oss({ ...ossConfig, refreshSTSTokenInterval: 1000 }); + await store.put('test-doMetaQuery--1', Buffer.from('test-doMetaQuery')); + await store.put('test-doMetaQuery--2', Buffer.from('test-doMetaQuery')); + await store.put('test-doMetaQuery--3', Buffer.from('test-doMetaQuery')); + await store.put('test-doMetaQuery--4', Buffer.from('test-doMetaQuery')); + }); + + it('open meta query of bucket', async () => { + try { + const result = await store.openMetaQuery(bucket); + assert.strictEqual(result.status, 200); + } catch (error) { + if (!['MetaQueryNotReady', 'MetaQueryAlreadyExist'].includes(error.code)) assert.fail(error); + } + }); + + it('getMetaQueryStatus()', async () => { + try { + const result = await store.getMetaQueryStatus(bucket); + assert.strictEqual(result.status, 200); + assert(result.phase.length > -1); + } catch (error) { + if (error.name !== 'MetaQueryNotExistError') assert.fail(error); + } + }); + + it('doMetaQuery()', async () => { + try { + const maxResults = 2; + const queryParam = { + maxResults, + sort: 'Size', + order: 'asc', + query: { + operation: 'and', + subQueries: [ + { field: 'Filename', value: 'test-doMetaQuery', operation: 'match' }, + { field: 'Size', value: '1048576', operation: 'lt' } + ] + } + }; + + const { status, files, nextToken } = await store.doMetaQuery(bucket, queryParam); + assert.strictEqual(status, 200); + if (nextToken) { + assert.strictEqual(files.length, maxResults); + + const result = await store.doMetaQuery(bucket, { ...queryParam, nextToken, maxResults: 1 }); + assert.strictEqual(result.status, 200); + assert(result.files.length > 0); + assert(result.files[0].fileName.length > 0); + } + } catch (error) { + if (error.name !== 'MetaQueryNotExistError') assert.fail(error); + } + }); + + it('doMetaQuery() one Aggregations', async () => { + try { + const queryParam = { + maxResults: 2, + sort: 'Size', + order: 'asc', + query: { + operation: 'and', + subQueries: [ + { field: 'Filename', value: '_do', operation: 'match' }, + { field: 'Size', value: '1048576', operation: 'lt' } + ] + }, + aggregations: [{ field: 'Size', operation: 'sum' }] + }; + + const result = await store.doMetaQuery(bucket, queryParam); + assert.strictEqual(result.status, 200); + assert(result.aggregations.length > 0); + assert(result.aggregations[0].field, 'Size'); + } catch (error) { + if (error.name !== 'MetaQueryNotExistError') assert.fail(error); + } + }); + + it('doMetaQuery() two Aggregations', async () => { + try { + const queryParam = { + maxResults: 2, + sort: 'Size', + order: 'asc', + query: { + operation: 'and', + subQueries: [ + { field: 'Filename', value: 'test-', operation: 'match' }, + { field: 'Size', value: '1048576', operation: 'lt' } + ] + }, + aggregations: [ + { field: 'Size', operation: 'sum' }, + { field: 'OSSTaggingCount', operation: 'min' } + ] + }; + + const result = await store.doMetaQuery(bucket, queryParam); + assert.strictEqual(result.status, 200); + assert(result.aggregations.length > 0); + assert(result.aggregations[0].field, 'Size'); + assert(result.aggregations[1].field, 'OSSTaggingCount'); + } catch (error) { + if (error.name !== 'MetaQueryNotExistError') assert.fail(error); + } + }); + + it('closeMetaQuery()', async () => { + try { + const result = await store.closeMetaQuery(bucket); + assert.strictEqual(result.status, 200); + setTimeout(() => { + store.openMetaQuery(bucket).catch(); + }, 1000 * 60); + } catch (error) { + if (error.name !== 'MetaQueryNotExistError') assert.fail(error); + } + }); + }); }); diff --git a/test/node/bucket.test.js b/test/node/bucket.test.js index 7bbbae3b8..c48e08a2a 100644 --- a/test/node/bucket.test.js +++ b/test/node/bucket.test.js @@ -2,7 +2,7 @@ const assert = require('assert'); const utils = require('./utils'); const oss = require('../..'); const ms = require('humanize-ms'); -const { oss: config, metaSyncTime, timeout } = require('../config'); +const { sts, oss: config, metaSyncTime, timeout } = require('../config'); describe('test/bucket.test.js', () => { const { prefix, includesConf } = utils; @@ -1305,6 +1305,7 @@ describe('test/bucket.test.js', () => { } }); }); + describe('inventory()', () => { const inventory = { id: 'default', @@ -1480,4 +1481,119 @@ describe('test/bucket.test.js', () => { }); }); }); + + describe('openMetaQuery() openMetaQuery() doMetaQuery() closeMetaQuery()', () => { + it('open meta query of bucket', async () => { + try { + const result = await store.openMetaQuery(sts.bucket); + assert.strictEqual(result.status, 200); + } catch (error) { + if (!['MetaQueryNotReady', 'MetaQueryAlreadyExist'].includes(error.code)) assert.fail(error); + } + }); + + it.only('getMetaQueryStatus()', async () => { + try { + const result = await store.getMetaQueryStatus(sts.bucket); + assert.strictEqual(result.status, 200); + assert(result.phase.length > -1); + } catch (error) { + if (error.name !== 'MetaQueryNotExistError') assert.fail(error); + } + }); + + it('doMetaQuery()', async () => { + try { + const maxResults = 2; + const queryParam = { + maxResults, + sort: 'Size', + order: 'asc', + query: { + operation: 'and', + subQueries: [ + { field: 'Filename', value: 'test-doMetaQuery', operation: 'match' }, + { field: 'Size', value: '1048576', operation: 'lt' } + ] + } + }; + + const { status, files, nextToken } = await store.doMetaQuery(sts.bucket, queryParam); + assert.strictEqual(status, 200); + if (nextToken) { + assert.strictEqual(files.length, maxResults); + + const result = await store.doMetaQuery(sts.bucket, { ...queryParam, nextToken, maxResults: 1 }); + assert.strictEqual(result.status, 200); + assert(result.files.length > 0); + assert(result.files[0].fileName.length > 0); + } + } catch (error) { + if (error.name !== 'MetaQueryNotExistError') assert.fail(error); + } + }); + + it('doMetaQuery() one Aggregations', async () => { + try { + const queryParam = { + maxResults: 2, + sort: 'Size', + order: 'asc', + query: { + operation: 'and', + subQueries: [ + { field: 'Filename', value: '_do', operation: 'match' }, + { field: 'Size', value: '1048576', operation: 'lt' } + ] + }, + aggregations: [{ field: 'Size', operation: 'sum' }] + }; + + const result = await store.doMetaQuery(sts.bucket, queryParam); + assert.strictEqual(result.status, 200); + assert(result.aggregations.length > 0); + assert(result.aggregations[0].field, 'Size'); + } catch (error) { + if (error.name !== 'MetaQueryNotExistError') assert.fail(error); + } + }); + + it('doMetaQuery() two Aggregations', async () => { + try { + const queryParam = { + maxResults: 2, + sort: 'Size', + order: 'asc', + query: { + operation: 'and', + subQueries: [ + { field: 'Filename', value: 'test-', operation: 'match' }, + { field: 'Size', value: '1048576', operation: 'lt' } + ] + }, + aggregations: [ + { field: 'Size', operation: 'sum' }, + { field: 'OSSTaggingCount', operation: 'min' } + ] + }; + + const result = await store.doMetaQuery(sts.bucket, queryParam); + assert.strictEqual(result.status, 200); + assert(result.aggregations.length > 0); + assert(result.aggregations[0].field, 'Size'); + assert(result.aggregations[1].field, 'OSSTaggingCount'); + } catch (error) { + if (error.name !== 'MetaQueryNotExistError') assert.fail(error); + } + }); + + it('closeMetaQuery()', async () => { + try { + const result = await store.closeMetaQuery(sts.bucket); + assert.strictEqual(result.status, 200); + } catch (error) { + if (error.name !== 'MetaQueryNotExistError') assert.fail(error); + } + }); + }); });