Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 10 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,10 @@ await s3Handler.listObjects('my-prefix');
await s3Handler.deleteObject('my-key');

// Delete several objects
await s3Handler.deleteObjects([{ Key: 'my-key1' }, {Key: 'my-key2'}]);
await s3Handler.deleteObjects([{ Key: 'my-key1' }, { Key: 'my-key2' }]);

// Copy object
await s3Handler.copyObject('bucket/my-key', 'my-new-key');
```

### Readable Stream Usage
Expand Down Expand Up @@ -94,28 +97,28 @@ npm run format
npm test
```

_Note: that's the one you want to use most of the time_

### Running lint tests

```sh
npm test:lint
npm run test:lint
```

### Running coverage tests

```sh
npm test:cover
npm run test:cover
```

This will create a coverage folder with all the report in `coverage/index.html`

### Running all tests
### Running types tests

```sh
npm test:all
npm run test:types
```

_Note: that's the one you want to use most of the time_

## Reporting bugs and contributing

If you want to report a bug or request a feature, please open an issue.
Expand Down
16 changes: 16 additions & 0 deletions src/S3Handler.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import {
CopyObjectCommand,
CopyObjectCommandInput,
DeleteObjectCommand,
DeleteObjectCommandInput,
DeleteObjectsCommand,
Expand Down Expand Up @@ -146,6 +148,20 @@ export class S3Handler {
return this.client.send(deleteObjectsCommand);
}

async copyObject(
sourceKey: string,
destinationKey: string,
options: Omit<CopyObjectCommandInput, 'Bucket' | 'Key' | 'CopySource'> = {}
) {
const copyObjectCommand = new CopyObjectCommand({
Bucket: this.bucket,
Key: destinationKey,
CopySource: sourceKey,
...options
});
return this.client.send(copyObjectCommand);
}

async generateGetPresignedUrl(
key: string,
signedUrlOptions: RequestPresigningArguments = {},
Expand Down
51 changes: 51 additions & 0 deletions test/src/copyObject.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { expect } from 'chai';
import { CopyObjectCommand, S3Client } from '@aws-sdk/client-s3';
import { mockClient } from 'aws-sdk-client-mock';
import { S3Handler } from '../../src/S3Handler';

describe('S3Handler.copyObject', () => {
const s3ClientMock = mockClient(S3Client);

beforeEach(() => {
s3ClientMock.reset();
});

it('should copy an object', async () => {
s3ClientMock.on(CopyObjectCommand).resolvesOnce({});

const s3Handler = new S3Handler(new S3Client({}), 'my-dummy-bucket');

await s3Handler.copyObject('my-dummy-bucket/my-key', 'my-new-key');

expect(s3ClientMock.commandCalls(CopyObjectCommand).length).equal(1);
expect(s3ClientMock.commandCalls(CopyObjectCommand)[0].args[0].input).deep.equal({
Bucket: 'my-dummy-bucket',
Key: 'my-new-key',
CopySource: `my-dummy-bucket/my-key`
});
});

it('should copy an object with additional options', async () => {
s3ClientMock.on(CopyObjectCommand).resolvesOnce({});

const s3Handler = new S3Handler(new S3Client({}), 'my-dummy-bucket');

await s3Handler.copyObject('my-dummy-bucket/my-key', 'my-new-key', {
ContentType: 'text/plain',
ACL: 'public-read',
Metadata: { myCustomId: '1' },
MetadataDirective: 'COPY'
});

expect(s3ClientMock.commandCalls(CopyObjectCommand).length).equal(1);
expect(s3ClientMock.commandCalls(CopyObjectCommand)[0].args[0].input).deep.equal({
Bucket: 'my-dummy-bucket',
Key: 'my-new-key',
CopySource: `my-dummy-bucket/my-key`,
ContentType: 'text/plain',
ACL: 'public-read',
Metadata: { myCustomId: '1' },
MetadataDirective: 'COPY'
});
});
});