Skip to content

Commit c901b04

Browse files
Merge pull request #53 from LabO8/feature/prefix-algorithm-setting
feat: allow custom prefix algorithm implementation
2 parents 98e91a3 + 5c4e8ba commit c901b04

16 files changed

+205
-25
lines changed

site/docs/prefixing.md

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
---
2+
id: prefixing
3+
title: Prefixing
4+
sidebar_label: Prefixing
5+
slug: /prefixing
6+
---
7+
8+
## Introduction
9+
10+
As our app grows, we might want to store our objects in a more organized way. This is where the prefix comes in.
11+
12+
The prefix is a string that is prepended to the object key. This allows us to organize our objects in a folder-like structure.
13+
14+
For example, if we have a bucket called `my-bucket` and we want to store our objects in a folder called `my-folder`, we can do that by prepending the prefix `my-folder/` to the object key.
15+
16+
## Usage
17+
18+
By default, the prefix is an empty string. This means that the object key is not modified, but if you set a prefix, when you initialize the module, the prefix will be prepended to the object key.
19+
20+
The default algorithm for prefixing will just prepend the prefix to the object key, but you can also specify a custom algorithm.
21+
22+
**All services like the `ObjectService` will use the prefix service by default.**
23+
24+
## Custom prefixing
25+
26+
In order to use a custom prefixing algorithm, you need to specify the `prefixingAlgorithm` when initializing the module.
27+
28+
```typescript
29+
class CustomPrefixService implements IPrefixAlgorithm {
30+
prefix(remote: string, prefix: string, bucket?: string): string {
31+
return `${bucket}/${prefix}${remote}`;
32+
}
33+
}
34+
35+
S3Module.forRoot({
36+
region: 'region',
37+
accessKeyId: '***',
38+
secretAccessKey: '***',
39+
prefix: 'test/',
40+
prefixAlgorithm: new CustomPrefixService(),
41+
})
42+
```
43+
44+
you can also use injectables
45+
46+
```typescript
47+
class CustomPrefixWithDIService implements IPrefixAlgorithm {
48+
public constructor(private readonly globalPrefix: string) {}
49+
50+
prefix(remote: string, prefix: string, bucket?: string): string {
51+
return `${bucket}/${this.globalPrefix}${prefix}${remote}`;
52+
}
53+
}
54+
55+
S3Module.forRootAsync({
56+
imports: [SomeModuleThatProvidesTheGlobalPrefix],
57+
prefixAlgorithmInject: ['GLOBAL_PREFIX'],
58+
prefixAlgorithmFactory: (globalPrefix: string) => new CustomPrefixWithDIService(globalPrefix),
59+
useFactory: () => ({
60+
region: 'region',
61+
accessKeyId: '***',
62+
secretAccessKey: '***',
63+
prefix: 'test/',
64+
}),
65+
})
66+
```

site/sidebars.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
const sidebars = {
1616
docsSidebar: {
1717
Introduction: ['getting-started'],
18-
Services: ['buckets', 'objects', 'signed-url', 'download-helper', 'deletion-helper'],
18+
Services: ['buckets', 'objects', 'signed-url', 'download-helper', 'prefix', 'deletion-helper'],
1919
API: [
2020
{
2121
type: 'autogenerated',

src/constants.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
export const S3_CONFIG = 's3.config';
22
export const S3_SERVICE = 's3.service';
3-
3+
export const PREFIX_ALGORITHM = 'prefix.algorithm';
44
export const DEFAULT_EXPIRES_IN = 3600;

src/interfaces/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './prefix-algorithm.interface';
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export interface IPrefixAlgorithm {
2+
prefix(remote: string, prefix?: string, bucket?: string): string;
3+
}

src/s3.module.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
import { HttpModule } from '@nestjs/axios';
22
import { DynamicModule, Global, Module, Provider } from '@nestjs/common';
3-
import { S3_CONFIG } from './constants';
3+
import { PREFIX_ALGORITHM, S3_CONFIG } from './constants';
44
import { createS3ServiceProvider } from './s3-service.factory';
5-
import { BucketsService, ObjectsService, PrefixService, SignedUrlService } from './services';
5+
import {
6+
BucketsService,
7+
DefaultPrefixAlgorithmService,
8+
ObjectsService,
9+
PrefixService,
10+
SignedUrlService,
11+
} from './services';
612
import { S3AsyncConfig, S3Config } from './types';
713
import { DeletionService, DownloadService } from './utils';
814

@@ -21,6 +27,10 @@ const createSharedProviders = (config: S3Config): Provider[] => [
2127
provide: S3_CONFIG,
2228
useValue: config,
2329
},
30+
{
31+
provide: PREFIX_ALGORITHM,
32+
useValue: config.prefixAlgorithm ? (config.prefixAlgorithm as any) : new DefaultPrefixAlgorithmService(),
33+
},
2434
...providers,
2535
];
2636

@@ -30,6 +40,13 @@ const createSharedProvidersAsync = (provider: S3AsyncConfig): Provider[] => [
3040
useFactory: provider.useFactory,
3141
inject: provider.inject || [],
3242
},
43+
{
44+
provide: PREFIX_ALGORITHM,
45+
useFactory: provider.prefixAlgorithmFactory
46+
? provider.prefixAlgorithmFactory
47+
: () => new DefaultPrefixAlgorithmService(),
48+
inject: provider.prefixAlgorithmInject || [],
49+
},
3350
...providers,
3451
];
3552

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { IPrefixAlgorithm } from '../interfaces';
2+
3+
export class DefaultPrefixAlgorithmService implements IPrefixAlgorithm {
4+
prefix(remote: string, prefix?: string, bucket?: string): string {
5+
if (!prefix) {
6+
return remote;
7+
}
8+
9+
return `${prefix}${remote}`;
10+
}
11+
}

src/services/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ export * from './buckers.service';
22
export * from './objects.service';
33
export * from './prefix.service';
44
export * from './signed-url.service';
5+
export * from './default-prefix-algorithm.service';

src/services/objects.service.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export class ObjectsService {
4646
new PutObjectCommand({
4747
Bucket: bucket,
4848
Body: body,
49-
Key: disableAutoPrefix ? remote : this.prefixService.prefix(remote),
49+
Key: disableAutoPrefix ? remote : this.prefixService.prefix(remote, bucket),
5050
...preparedOptions,
5151
}),
5252
);
@@ -73,7 +73,7 @@ export class ObjectsService {
7373
return this.client.send(
7474
new DeleteObjectCommand({
7575
Bucket: bucket,
76-
Key: disableAutoPrefix ? remote : this.prefixService.prefix(remote),
76+
Key: disableAutoPrefix ? remote : this.prefixService.prefix(remote, bucket),
7777
...preparedOptions,
7878
}),
7979
);
@@ -90,7 +90,7 @@ export class ObjectsService {
9090
new DeleteObjectsCommand({
9191
Bucket: bucket,
9292
Delete: {
93-
Objects: remotes.map((r) => ({ Key: disableAutoPrefix ? r : this.prefixService.prefix(r) })),
93+
Objects: remotes.map((r) => ({ Key: disableAutoPrefix ? r : this.prefixService.prefix(r, bucket) })),
9494
},
9595
...preparedOptions,
9696
}),
@@ -103,7 +103,7 @@ export class ObjectsService {
103103
return this.client.send(
104104
new GetObjectCommand({
105105
Bucket: bucket,
106-
Key: disableAutoPrefix ? remote : this.prefixService.prefix(remote),
106+
Key: disableAutoPrefix ? remote : this.prefixService.prefix(remote, bucket),
107107
...preparedOptions,
108108
}),
109109
);

src/services/prefix.service.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
import { Inject, Injectable } from '@nestjs/common';
2-
import { S3_CONFIG } from '../constants';
2+
import { PREFIX_ALGORITHM, S3_CONFIG } from '../constants';
33
import { S3Config } from '../types';
4+
import { IPrefixAlgorithm } from '../interfaces';
45

56
@Injectable()
67
export class PrefixService {
7-
public constructor(@Inject(S3_CONFIG) private readonly config: S3Config) {}
8+
public constructor(
9+
@Inject(S3_CONFIG) private readonly config: S3Config,
10+
@Inject(PREFIX_ALGORITHM) private readonly prefixAlgorithm: IPrefixAlgorithm,
11+
) {}
812

9-
public prefix(remote: string): string {
13+
public prefix(remote: string, bucket?: string): string {
1014
const { prefix } = this.config;
1115

12-
if (!prefix) {
13-
return remote;
14-
}
15-
16-
return `${prefix}${remote}`;
16+
return this.prefixAlgorithm.prefix(remote, prefix, bucket);
1717
}
1818
}

0 commit comments

Comments
 (0)