Skip to content

Commit 75e3b98

Browse files
committed
docs(storage): document getFiles filtering and refactor validation logic
Extracted context validation into a shared helper for consistency and updated getFiles JSDoc to include Object Context filter syntax and examples.
1 parent ba94b80 commit 75e3b98

3 files changed

Lines changed: 72 additions & 31 deletions

File tree

handwritten/storage/src/bucket.ts

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ import * as path from 'path';
3434
import pLimit from 'p-limit';
3535
import {promisify} from 'util';
3636
import AsyncRetry from 'async-retry';
37-
import {convertObjKeysToSnakeCase, validateContexts} from './util.js';
37+
import {convertObjKeysToSnakeCase, handleContextValidation} from './util.js';
3838

3939
import {Acl, AclMetadata} from './acl.js';
4040
import {Channel} from './channel.js';
@@ -1662,14 +1662,11 @@ class Bucket extends ServiceObject<Bucket, BucketMetadata> {
16621662
}
16631663

16641664
if (options.contexts) {
1665-
try {
1666-
validateContexts(options.contexts);
1667-
} catch (err) {
1668-
if (callback) {
1669-
return (callback as CombineCallback)(err as Error, null, null);
1670-
}
1671-
return Promise.reject(err);
1672-
}
1665+
const validationError = handleContextValidation(
1666+
options.contexts,
1667+
callback
1668+
);
1669+
if (validationError) return validationError;
16731670
}
16741671

16751672
this.disableAutoRetryConditionallyIdempotent_(
@@ -2692,6 +2689,10 @@ class Bucket extends ServiceObject<Bucket, BucketMetadata> {
26922689
* in addition to the relevant part of the object name appearing in prefixes[].
26932690
* @property {string} [prefix] Filter results to objects whose names begin
26942691
* with this prefix.
2692+
* @property {string} [filter] Filter results using a server-side filter
2693+
* expression. This is primarily used for filtering by Object Contexts.
2694+
* Syntax: `contexts."<key>"="<value>"` or `contexts."<key>":*`.
2695+
* Prepend `-` for negation (e.g., `-contexts."key":*`).
26952696
* @property {string} [matchGlob] A glob pattern used to filter results,
26962697
* for example foo*bar
26972698
* @property {number} [maxApiCalls] Maximum number of API calls to make.
@@ -2739,6 +2740,9 @@ class Bucket extends ServiceObject<Bucket, BucketMetadata> {
27392740
* in addition to the relevant part of the object name appearing in prefixes[].
27402741
* @param {string} [query.prefix] Filter results to objects whose names begin
27412742
* with this prefix.
2743+
* @param {string} [query.filter] Filter results using a server-side filter
2744+
* expression. Supports Object Contexts with operators like `=`, `:`,
2745+
* and `-` for negation.
27422746
* @param {number} [query.maxApiCalls] Maximum number of API calls to make.
27432747
* @param {number} [query.maxResults] Maximum number of items plus prefixes to
27442748
* return per call.
@@ -2758,6 +2762,7 @@ class Bucket extends ServiceObject<Bucket, BucketMetadata> {
27582762
* billed for the request.
27592763
* @param {boolean} [query.versions] If true, returns File objects scoped to
27602764
* their versions.
2765+
*
27612766
* @param {GetFilesCallback} [callback] Callback function.
27622767
* @returns {Promise<GetFilesResponse>}
27632768
*
@@ -2851,6 +2856,31 @@ class Bucket extends ServiceObject<Bucket, BucketMetadata> {
28512856
* });
28522857
* ```
28532858
*
2859+
* @example
2860+
* //-
2861+
* // Filter files using Object Contexts.
2862+
* //-
2863+
* ```
2864+
* const query = {
2865+
* filter: 'contexts."status"="active"'
2866+
* };
2867+
* bucket.getFiles(query, function(err, files) {
2868+
* if (!err) {
2869+
* // files only contains objects with the 'status' context set to 'active'.
2870+
* }
2871+
* });
2872+
*
2873+
* //-
2874+
* // You can also filter by the absence of a context key.
2875+
* //-
2876+
*
2877+
* bucket.getFiles({
2878+
* filter: '-contexts."priority":*'
2879+
* }, function(err, files) {
2880+
* // files contains objects that DO NOT have the 'priority' context key.
2881+
* });
2882+
* ```
2883+
*
28542884
* @example <caption>include:samples/files.js</caption>
28552885
* region_tag:storage_list_files
28562886
* Another example:

handwritten/storage/src/file.ts

Lines changed: 13 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ import {
6161
unicodeJSONStringify,
6262
formatAsUTCISO,
6363
PassThroughShim,
64-
validateContexts,
64+
handleContextValidation,
6565
} from './util.js';
6666
import {CRC32C, CRC32CValidatorGenerator} from './crc32c.js';
6767
import {HashStreamValidator} from './hash-stream-validator.js';
@@ -1326,14 +1326,11 @@ class File extends ServiceObject<File, FileMetadata> {
13261326
}
13271327

13281328
if (options.contexts) {
1329-
try {
1330-
validateContexts(options.contexts);
1331-
} catch (err) {
1332-
if (callback) {
1333-
return (callback as CopyCallback)(err as Error, null, null);
1334-
}
1335-
return Promise.reject(err);
1336-
}
1329+
const validationError = handleContextValidation(
1330+
options.contexts,
1331+
callback
1332+
);
1333+
if (validationError) return validationError;
13371334
}
13381335

13391336
callback = callback || util.noop;
@@ -4165,18 +4162,16 @@ class File extends ServiceObject<File, FileMetadata> {
41654162
optionsOrCallback?: SaveOptions | SaveCallback,
41664163
callback?: SaveCallback,
41674164
): Promise<void> | void {
4168-
// tslint:enable:no-any
41694165
callback =
41704166
typeof optionsOrCallback === 'function' ? optionsOrCallback : callback;
41714167
const options =
41724168
typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
41734169

4174-
try {
4175-
validateContexts(options.metadata?.contexts);
4176-
} catch (err) {
4177-
if (callback) return callback(err as Error);
4178-
return Promise.reject(err);
4179-
}
4170+
const validationError = handleContextValidation(
4171+
options.metadata?.contexts,
4172+
callback
4173+
);
4174+
if (validationError) return validationError;
41804175

41814176
let maxRetries = this.storage.retryOptions.maxRetries;
41824177
if (
@@ -4281,12 +4276,8 @@ class File extends ServiceObject<File, FileMetadata> {
42814276
? (optionsOrCallback as MetadataCallback<FileMetadata>)
42824277
: cb;
42834278

4284-
try {
4285-
validateContexts(metadata.contexts);
4286-
} catch (err) {
4287-
if (cb) return cb(err as Error);
4288-
return Promise.reject(err);
4289-
}
4279+
const validationError = handleContextValidation(metadata.contexts, cb);
4280+
if (validationError) return validationError;
42904281

42914282
this.disableAutoRetryConditionallyIdempotent_(
42924283
this.methods.setMetadata,

handwritten/storage/src/util.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,3 +299,23 @@ export function validateContexts(contexts?: FileMetadata['contexts']): void {
299299
}
300300
}
301301
}
302+
303+
/**
304+
* Helper to validate contexts and route errors to either a callback or a Promise.
305+
* @param contexts The contexts to validate.
306+
* @param callback The optional user-provided callback.
307+
*/
308+
export function handleContextValidation<T>(
309+
contexts?: FileMetadata['contexts'],
310+
callback?: Function
311+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
312+
): Promise<any> | void {
313+
try {
314+
validateContexts(contexts);
315+
} catch (err) {
316+
if (callback) {
317+
return callback(err as Error);
318+
}
319+
return Promise.reject(err);
320+
}
321+
}

0 commit comments

Comments
 (0)