Skip to content

Commit a92e575

Browse files
authored
Merge pull request #416 from jgilbert01/s3-head-object
S3 head object command
2 parents 8d7ac4c + f64e173 commit a92e575

6 files changed

Lines changed: 122 additions & 5 deletions

File tree

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "aws-lambda-stream",
3-
"version": "1.1.6",
3+
"version": "1.1.7",
44
"description": "Create stream processors with AWS Lambda functions.",
55
"keywords": [
66
"aws",

src/connectors/s3.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import { Readable } from 'stream';
44
import {
55
CopyObjectCommand,
6-
DeleteObjectCommand, GetObjectCommand, ListObjectsV2Command, PutObjectCommand, S3Client,
6+
DeleteObjectCommand, GetObjectCommand, HeadObjectCommand, ListObjectsV2Command, PutObjectCommand, S3Client,
77
} from '@aws-sdk/client-s3';
88
import { NodeHttpHandler } from '@smithy/node-http-handler';
99
import Promise from 'bluebird';
@@ -47,6 +47,15 @@ class Connector {
4747
return this.clients[pipelineId];
4848
}
4949

50+
headObject(inputParams, ctx) {
51+
const params = {
52+
Bucket: this.bucketName,
53+
...inputParams,
54+
};
55+
56+
return this._sendCommand(new HeadObjectCommand(params), ctx);
57+
}
58+
5059
putObject(inputParams, ctx) {
5160
const params = {
5261
Bucket: this.bucketName,

src/queries/s3.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,3 +193,32 @@ export const pageObjectsFromS3 = ({
193193
.map(listObjects)
194194
.parallel(parallel);
195195
};
196+
197+
export const headS3Object = ({
198+
id: pipelineId,
199+
debug = d('s3'),
200+
bucketName = process.env.BUCKET_NAME,
201+
headRequestField = 'headRequest',
202+
headResponseField = 'headResponse',
203+
parallel = Number(process.env.S3_PARALLEL) || Number(process.env.PARALLEL) || 8,
204+
step = 'get',
205+
...opt
206+
} = {}) => {
207+
const connector = new Connector({
208+
pipelineId, debug, bucketName, ...opt,
209+
});
210+
211+
const headObject = (uow) => {
212+
if (!uow[headRequestField]) return _(Promise.resolve(uow));
213+
214+
const p = () => connector.headObject(uow[headRequestField], uow)
215+
.then((headResponse) => ({ ...uow, [headResponseField]: headResponse }))
216+
.catch(rejectWithFault(uow));
217+
218+
return _(uow.metrics?.w(p, step) || p()); // wrap promise in a stream
219+
};
220+
221+
return (s) => s
222+
.map(headObject)
223+
.parallel(parallel);
224+
};

test/unit/connectors/s3.test.js

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { Readable } from 'stream';
66
import { mockClient } from 'aws-sdk-client-mock';
77
import {
88
CopyObjectCommand,
9-
DeleteObjectCommand, GetObjectCommand, ListObjectsV2Command, PutObjectCommand, S3Client,
9+
DeleteObjectCommand, GetObjectCommand, HeadObjectCommand, ListObjectsV2Command, PutObjectCommand, S3Client,
1010
} from '@aws-sdk/client-s3';
1111
import { sdkStreamMixin } from '@smithy/util-stream';
1212

@@ -199,4 +199,20 @@ describe('connectors/s3.js', () => {
199199
});
200200
expect(data).to.deep.equal({});
201201
});
202+
it('should head object', async () => {
203+
const spy = sinon.spy(() => ({}));
204+
mockS3.on(HeadObjectCommand).callsFake(spy);
205+
const inputParams = {
206+
Key: 'k1',
207+
};
208+
const data = await new Connector({
209+
debug: debug('s3'),
210+
bucketName: 'b1',
211+
}).headObject(inputParams);
212+
expect(spy).to.have.been.calledWith({
213+
Key: 'k1',
214+
Bucket: 'b1',
215+
});
216+
expect(data).to.deep.equal({});
217+
});
202218
});

test/unit/queries/s3.test.js

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
toGetObjectRequest,
1313
toGetObjectRequest2,
1414
getObjectFromS3AsStream,
15+
headS3Object,
1516
} from '../../../src/queries/s3';
1617

1718
import Connector from '../../../src/connectors/s3';
@@ -329,6 +330,68 @@ describe('queries/s3.js', () => {
329330
})
330331
.done(done);
331332
});
333+
it('should head object', (done) => {
334+
const stub = sinon.stub(Connector.prototype, 'headObject').resolves({
335+
Metadata: {
336+
testkey: '1',
337+
},
338+
});
339+
340+
const uows = [{
341+
headRequest: {
342+
Key: 'k1',
343+
},
344+
}];
345+
346+
_(uows)
347+
.through(headS3Object())
348+
.collect()
349+
.tap((collected) => {
350+
// console.log(JSON.stringify(collected, null, 2));
351+
352+
expect(stub).to.have.been.calledWith({
353+
Key: 'k1',
354+
});
355+
356+
expect(collected.length).to.equal(1);
357+
expect(collected[0]).to.deep.equal({
358+
headRequest: {
359+
Key: 'k1',
360+
},
361+
headResponse: {
362+
Metadata: {
363+
testkey: '1',
364+
},
365+
},
366+
});
367+
})
368+
.done(done);
369+
});
370+
it('should head object missing headRequestField', (done) => {
371+
sinon.stub(Connector.prototype, 'headObject').resolves({
372+
Metadata: {
373+
testkey: '1',
374+
},
375+
});
376+
377+
const uows = [{
378+
// headRequest: {
379+
// Key: 'k1',
380+
// },
381+
}];
382+
383+
_(uows)
384+
.through(headS3Object())
385+
.collect()
386+
.tap((collected) => {
387+
// console.log(JSON.stringify(collected, null, 2));
388+
389+
expect(collected[0]).to.deep.equal({});
390+
391+
expect(collected.length).to.equal(1);
392+
})
393+
.done(done);
394+
});
332395
});
333396

334397
const GET_RESPONSE = {

0 commit comments

Comments
 (0)