Skip to content

Commit 8a7b82a

Browse files
authored
feat: Add file.exists
2 parents 056f4f7 + e991f74 commit 8a7b82a

File tree

7 files changed

+514
-1
lines changed

7 files changed

+514
-1
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@nitric/sdk",
33
"description": "Nitric NodeJS client sdk",
4-
"nitric": "v0.32.0",
4+
"nitric": "v0.33.0-rc.4",
55
"author": "Nitric <https://github.com/nitrictech>",
66
"repository": "https://github.com/nitrictech/node-sdk",
77
"main": "lib/index.js",

src/api/storage/v0/storage.test.ts

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import {
2121
StoragePreSignUrlRequest,
2222
StorageListFilesResponse,
2323
File,
24+
StorageExistsResponse,
2425
} from '@nitric/api/proto/storage/v1/storage_pb';
2526
import { UnimplementedError } from '../../errors';
2627
import {
@@ -162,6 +163,70 @@ describe('Storage Client Tests', () => {
162163
expect(readMock).toBeCalledTimes(1);
163164
});
164165
});
166+
167+
describe('Given nitric.api.storage.StorageClient.Exists throws an error', () => {
168+
const MOCK_ERROR = {
169+
code: 2,
170+
message: 'UNIMPLEMENTED',
171+
};
172+
let existsMock;
173+
174+
beforeAll(() => {
175+
existsMock = jest
176+
.spyOn(GrpcStorageClient.prototype, 'exists')
177+
.mockImplementation((_, callback: any) => {
178+
callback(MOCK_ERROR, null);
179+
180+
return null as any;
181+
});
182+
});
183+
184+
afterAll(() => {
185+
jest.resetAllMocks();
186+
});
187+
188+
test('Then StorageClient.exists should reject', async () => {
189+
const storage = new Storage();
190+
await expect(
191+
storage.bucket('test_bucket').file('test/item').exists()
192+
).rejects.toEqual(new UnimplementedError('UNIMPLEMENTED'));
193+
});
194+
195+
test('The Grpc client for Storage.write should have been called exactly once', () => {
196+
expect(existsMock).toBeCalledTimes(1);
197+
});
198+
});
199+
200+
describe('Given nitric.api.storage.StorageClient.Exists succeeds', () => {
201+
let writeMock;
202+
const MOCK_REPLY = new StorageExistsResponse();
203+
204+
beforeAll(() => {
205+
writeMock = jest
206+
.spyOn(GrpcStorageClient.prototype, 'exists')
207+
.mockImplementation((_, callback: any) => {
208+
callback(null, MOCK_REPLY);
209+
210+
return null as any;
211+
});
212+
});
213+
214+
afterAll(() => {
215+
jest.resetAllMocks();
216+
});
217+
218+
test('Then StorageClient.exists should resolve with success status', async () => {
219+
const storage = new Storage();
220+
await expect(
221+
storage.bucket('test_bucket').file('test/item').exists()
222+
).resolves.toBe(false);
223+
});
224+
225+
test('The Grpc client for Storage.write should have been called exactly once', () => {
226+
expect(writeMock).toBeCalledTimes(1);
227+
});
228+
});
229+
165230
describe('Given nitric.api.storage.StorageClient.Delete throws an error', () => {
166231
const MOCK_ERROR = {
167232
code: 2,

src/api/storage/v0/storage.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
StorageDeleteRequest,
2020
StoragePreSignUrlRequest,
2121
StorageListFilesRequest,
22+
StorageExistsRequest,
2223
} from '@nitric/api/proto/storage/v1/storage_pb';
2324
import * as grpc from '@grpc/grpc-js';
2425
import { fromGrpcError, InvalidArgumentError } from '../../errors';
@@ -314,6 +315,36 @@ export class File {
314315
});
315316
});
316317
}
318+
319+
/**
320+
* Determine if a file exists in a bucket.
321+
*
322+
* @returns A boolean promise.
323+
*
324+
* Example:
325+
* ```typescript
326+
* import { bucket } from "@nitric/sdk";
327+
*
328+
* const exampleBucket = bucket('exampleBucket').for('reading');
329+
*
330+
* const exists = await exampleBucket.file("my-item").exists();
331+
* ```
332+
*/
333+
public async exists(): Promise<boolean> {
334+
const request = new StorageExistsRequest();
335+
request.setBucket(this.bucket.name);
336+
request.setKey(this.name);
337+
338+
return new Promise((resolve, reject) => {
339+
this.storage.StorageServiceClient.exists(request, (error, response) => {
340+
if (error) {
341+
reject(fromGrpcError(error));
342+
} else {
343+
resolve(response.getExists());
344+
}
345+
});
346+
});
347+
}
317348
}
318349

319350
// Storage client singleton

src/gen/proto/storage/v1/storage_grpc_pb.d.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ interface IStorageServiceService extends grpc.ServiceDefinition<grpc.UntypedServ
1212
delete: grpc.MethodDefinition<proto_storage_v1_storage_pb.StorageDeleteRequest, proto_storage_v1_storage_pb.StorageDeleteResponse>;
1313
preSignUrl: grpc.MethodDefinition<proto_storage_v1_storage_pb.StoragePreSignUrlRequest, proto_storage_v1_storage_pb.StoragePreSignUrlResponse>;
1414
listFiles: grpc.MethodDefinition<proto_storage_v1_storage_pb.StorageListFilesRequest, proto_storage_v1_storage_pb.StorageListFilesResponse>;
15+
exists: grpc.MethodDefinition<proto_storage_v1_storage_pb.StorageExistsRequest, proto_storage_v1_storage_pb.StorageExistsResponse>;
1516
}
1617

1718
export const StorageServiceService: IStorageServiceService;
@@ -22,6 +23,7 @@ export interface IStorageServiceServer extends grpc.UntypedServiceImplementation
2223
delete: grpc.handleUnaryCall<proto_storage_v1_storage_pb.StorageDeleteRequest, proto_storage_v1_storage_pb.StorageDeleteResponse>;
2324
preSignUrl: grpc.handleUnaryCall<proto_storage_v1_storage_pb.StoragePreSignUrlRequest, proto_storage_v1_storage_pb.StoragePreSignUrlResponse>;
2425
listFiles: grpc.handleUnaryCall<proto_storage_v1_storage_pb.StorageListFilesRequest, proto_storage_v1_storage_pb.StorageListFilesResponse>;
26+
exists: grpc.handleUnaryCall<proto_storage_v1_storage_pb.StorageExistsRequest, proto_storage_v1_storage_pb.StorageExistsResponse>;
2527
}
2628

2729
export class StorageServiceClient extends grpc.Client {
@@ -41,4 +43,7 @@ export class StorageServiceClient extends grpc.Client {
4143
listFiles(argument: proto_storage_v1_storage_pb.StorageListFilesRequest, callback: grpc.requestCallback<proto_storage_v1_storage_pb.StorageListFilesResponse>): grpc.ClientUnaryCall;
4244
listFiles(argument: proto_storage_v1_storage_pb.StorageListFilesRequest, metadataOrOptions: grpc.Metadata | grpc.CallOptions | null, callback: grpc.requestCallback<proto_storage_v1_storage_pb.StorageListFilesResponse>): grpc.ClientUnaryCall;
4345
listFiles(argument: proto_storage_v1_storage_pb.StorageListFilesRequest, metadata: grpc.Metadata | null, options: grpc.CallOptions | null, callback: grpc.requestCallback<proto_storage_v1_storage_pb.StorageListFilesResponse>): grpc.ClientUnaryCall;
46+
exists(argument: proto_storage_v1_storage_pb.StorageExistsRequest, callback: grpc.requestCallback<proto_storage_v1_storage_pb.StorageExistsResponse>): grpc.ClientUnaryCall;
47+
exists(argument: proto_storage_v1_storage_pb.StorageExistsRequest, metadataOrOptions: grpc.Metadata | grpc.CallOptions | null, callback: grpc.requestCallback<proto_storage_v1_storage_pb.StorageExistsResponse>): grpc.ClientUnaryCall;
48+
exists(argument: proto_storage_v1_storage_pb.StorageExistsRequest, metadata: grpc.Metadata | null, options: grpc.CallOptions | null, callback: grpc.requestCallback<proto_storage_v1_storage_pb.StorageExistsResponse>): grpc.ClientUnaryCall;
4449
}

src/gen/proto/storage/v1/storage_grpc_pb.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,28 @@ function deserialize_nitric_storage_v1_StorageDeleteResponse(buffer_arg) {
2727
return proto_storage_v1_storage_pb.StorageDeleteResponse.deserializeBinary(new Uint8Array(buffer_arg));
2828
}
2929

30+
function serialize_nitric_storage_v1_StorageExistsRequest(arg) {
31+
if (!(arg instanceof proto_storage_v1_storage_pb.StorageExistsRequest)) {
32+
throw new Error('Expected argument of type nitric.storage.v1.StorageExistsRequest');
33+
}
34+
return Buffer.from(arg.serializeBinary());
35+
}
36+
37+
function deserialize_nitric_storage_v1_StorageExistsRequest(buffer_arg) {
38+
return proto_storage_v1_storage_pb.StorageExistsRequest.deserializeBinary(new Uint8Array(buffer_arg));
39+
}
40+
41+
function serialize_nitric_storage_v1_StorageExistsResponse(arg) {
42+
if (!(arg instanceof proto_storage_v1_storage_pb.StorageExistsResponse)) {
43+
throw new Error('Expected argument of type nitric.storage.v1.StorageExistsResponse');
44+
}
45+
return Buffer.from(arg.serializeBinary());
46+
}
47+
48+
function deserialize_nitric_storage_v1_StorageExistsResponse(buffer_arg) {
49+
return proto_storage_v1_storage_pb.StorageExistsResponse.deserializeBinary(new Uint8Array(buffer_arg));
50+
}
51+
3052
function serialize_nitric_storage_v1_StorageListFilesRequest(arg) {
3153
if (!(arg instanceof proto_storage_v1_storage_pb.StorageListFilesRequest)) {
3254
throw new Error('Expected argument of type nitric.storage.v1.StorageListFilesRequest');
@@ -178,6 +200,18 @@ listFiles: {
178200
responseSerialize: serialize_nitric_storage_v1_StorageListFilesResponse,
179201
responseDeserialize: deserialize_nitric_storage_v1_StorageListFilesResponse,
180202
},
203+
// Determine is an object exists in a bucket
204+
exists: {
205+
path: '/nitric.storage.v1.StorageService/Exists',
206+
requestStream: false,
207+
responseStream: false,
208+
requestType: proto_storage_v1_storage_pb.StorageExistsRequest,
209+
responseType: proto_storage_v1_storage_pb.StorageExistsResponse,
210+
requestSerialize: serialize_nitric_storage_v1_StorageExistsRequest,
211+
requestDeserialize: deserialize_nitric_storage_v1_StorageExistsRequest,
212+
responseSerialize: serialize_nitric_storage_v1_StorageExistsResponse,
213+
responseDeserialize: deserialize_nitric_storage_v1_StorageExistsResponse,
214+
},
181215
};
182216

183217
exports.StorageServiceClient = grpc.makeGenericClientConstructor(StorageServiceService);

src/gen/proto/storage/v1/storage_pb.d.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,3 +261,47 @@ export namespace StorageListFilesResponse {
261261
}
262262
}
263263

264+
export class StorageExistsRequest extends jspb.Message {
265+
getBucket(): string;
266+
setBucket(value: string): void;
267+
268+
getKey(): string;
269+
setKey(value: string): void;
270+
271+
serializeBinary(): Uint8Array;
272+
toObject(includeInstance?: boolean): StorageExistsRequest.AsObject;
273+
static toObject(includeInstance: boolean, msg: StorageExistsRequest): StorageExistsRequest.AsObject;
274+
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
275+
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
276+
static serializeBinaryToWriter(message: StorageExistsRequest, writer: jspb.BinaryWriter): void;
277+
static deserializeBinary(bytes: Uint8Array): StorageExistsRequest;
278+
static deserializeBinaryFromReader(message: StorageExistsRequest, reader: jspb.BinaryReader): StorageExistsRequest;
279+
}
280+
281+
export namespace StorageExistsRequest {
282+
export type AsObject = {
283+
bucket: string,
284+
key: string,
285+
}
286+
}
287+
288+
export class StorageExistsResponse extends jspb.Message {
289+
getExists(): boolean;
290+
setExists(value: boolean): void;
291+
292+
serializeBinary(): Uint8Array;
293+
toObject(includeInstance?: boolean): StorageExistsResponse.AsObject;
294+
static toObject(includeInstance: boolean, msg: StorageExistsResponse): StorageExistsResponse.AsObject;
295+
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
296+
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
297+
static serializeBinaryToWriter(message: StorageExistsResponse, writer: jspb.BinaryWriter): void;
298+
static deserializeBinary(bytes: Uint8Array): StorageExistsResponse;
299+
static deserializeBinaryFromReader(message: StorageExistsResponse, reader: jspb.BinaryReader): StorageExistsResponse;
300+
}
301+
302+
export namespace StorageExistsResponse {
303+
export type AsObject = {
304+
exists: boolean,
305+
}
306+
}
307+

0 commit comments

Comments
 (0)