Skip to content

Commit 74cf6e7

Browse files
committed
rename function createTiny url to shortenUrl
1 parent dcff75e commit 74cf6e7

File tree

7 files changed

+145
-13
lines changed

7 files changed

+145
-13
lines changed

api/.env-dev

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1-
CACHE_PERSISTENCE= memory
21
MACHINE_ID=1
32
PORT = 3000
43
# Perhpas we should only use a domain name here instead of a full URL (with the port as it is error prone)
5-
SHORTENED_BASE_URL = http://localhost:3000
4+
SHORTENED_BASE_URL = http://localhost:3000
5+
# redis | memory
6+
CACHE_PERSISTENCE= memory
7+
REDIS_URL = redis://localhost:6379
8+
# 10 minutes
9+
REDIS_TTL = 600

api/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
"@nestjs/platform-express": "10.0.0",
2727
"class-transformer": "0.5.1",
2828
"class-validator": "0.14.1",
29+
"redis": "4.7.0",
2930
"reflect-metadata": "0.2.0",
3031
"rxjs": "7.8.1"
3132
},

api/src/infrastructure/repository/in-memory-url.repository.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { ShortenUrlRepository } from '../../shorten-url/shorten-url.repository';
2-
import { Injectable } from '@nestjs/common';
2+
import { Injectable, Logger } from '@nestjs/common';
33

44
@Injectable()
55
export class InMemoryUrlRepository implements ShortenUrlRepository {
Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,50 @@
11
import { ShortenUrlRepository } from '../../shorten-url/shorten-url.repository';
2-
import { Injectable } from '@nestjs/common';
2+
import {
3+
Injectable,
4+
Logger,
5+
OnModuleDestroy,
6+
OnModuleInit,
7+
} from '@nestjs/common';
8+
import { createClient, RedisClientType } from 'redis';
9+
import { ConfigService } from '@nestjs/config';
310

411
@Injectable()
5-
export class RedisUrlRepository implements ShortenUrlRepository {
6-
private urls: Map<string, string> = new Map();
12+
export class RedisUrlRepository
13+
implements ShortenUrlRepository, OnModuleInit, OnModuleDestroy
14+
{
15+
private readonly DEFAULT_TTL = 100;
716

8-
create(url: string, shortenedUrl: string): Promise<void> {
9-
this.urls.set(url, shortenedUrl);
10-
return Promise.resolve(undefined);
17+
private redisClient: RedisClientType;
18+
19+
private redisTTL: number;
20+
21+
constructor(private readonly configService: ConfigService) {
22+
const redisUrl = this.configService.get<string>('REDIS_URL');
23+
this.redisClient = createClient({ url: redisUrl });
24+
this.redisClient.on('error', (err) =>
25+
Logger.error('Redis Client Error', err),
26+
);
27+
this.redisTTL = this.configService.get<number>(
28+
'REDIS_TTL',
29+
this.DEFAULT_TTL,
30+
);
31+
}
32+
33+
async create(url: string, shortenedUrl: string): Promise<void> {
34+
await this.redisClient.set(url, shortenedUrl, { EX: this.redisTTL });
35+
}
36+
37+
async findURL(url: string): Promise<string | null> {
38+
return await this.redisClient.get(url);
39+
}
40+
41+
async onModuleInit() {
42+
await this.redisClient.connect();
43+
Logger.debug('✅ Connected to Redis');
1144
}
1245

13-
findURL(url: string): Promise<string | null> {
14-
const shortenedUrl = this.urls.get(url);
15-
return Promise.resolve(shortenedUrl);
46+
async onModuleDestroy() {
47+
await this.redisClient.quit();
48+
Logger.debug('🛑 Redis connection closed');
1649
}
1750
}

api/src/infrastructure/repository/repository.provider.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { ConfigService } from '@nestjs/config';
22
import { Provider } from '@nestjs/common';
33
import { InMemoryUrlRepository } from './in-memory-url.repository';
44
import { ShortenUrlRepository } from '../../shorten-url/shorten-url.repository';
5+
import { RedisUrlRepository } from './redis-url.repository';
56

67
/**
78
* Factory provider to select the appropriate repository implementation based on configuration.
@@ -17,7 +18,7 @@ export const RepositoryProvider: Provider = {
1718
);
1819

1920
if (persistenceType === 'redis') {
20-
throw new Error('Redis persistence is not yet implemented');
21+
return new RedisUrlRepository(configService);
2122
}
2223

2324
return new InMemoryUrlRepository();

api/yarn.lock

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -798,6 +798,40 @@
798798
resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.1.1.tgz#1ec17e2edbec25c8306d424ecfbf13c7de1aaa31"
799799
integrity sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==
800800

801+
802+
version "1.2.0"
803+
resolved "https://registry.yarnpkg.com/@redis/bloom/-/bloom-1.2.0.tgz#d3fd6d3c0af3ef92f26767b56414a370c7b63b71"
804+
integrity sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==
805+
806+
807+
version "1.6.0"
808+
resolved "https://registry.yarnpkg.com/@redis/client/-/client-1.6.0.tgz#dcf4ae1319763db6fdddd6de7f0af68a352c30ea"
809+
integrity sha512-aR0uffYI700OEEH4gYnitAnv3vzVGXCFvYfdpu/CJKvk4pHfLPEy/JSZyrpQ+15WhXe1yJRXLtfQ84s4mEXnPg==
810+
dependencies:
811+
cluster-key-slot "1.1.2"
812+
generic-pool "3.9.0"
813+
yallist "4.0.0"
814+
815+
816+
version "1.1.1"
817+
resolved "https://registry.yarnpkg.com/@redis/graph/-/graph-1.1.1.tgz#8c10df2df7f7d02741866751764031a957a170ea"
818+
integrity sha512-FEMTcTHZozZciLRl6GiiIB4zGm5z5F3F6a6FZCyrfxdKOhFlGkiAqlexWMBzCi4DcRoyiOsuLfW+cjlGWyExOw==
819+
820+
821+
version "1.0.7"
822+
resolved "https://registry.yarnpkg.com/@redis/json/-/json-1.0.7.tgz#016257fcd933c4cbcb9c49cde8a0961375c6893b"
823+
integrity sha512-6UyXfjVaTBTJtKNG4/9Z8PSpKE6XgSyEb8iwaqDcy+uKrd/DGYHTWkUdnQDyzm727V7p21WUMhsqz5oy65kPcQ==
824+
825+
826+
version "1.2.0"
827+
resolved "https://registry.yarnpkg.com/@redis/search/-/search-1.2.0.tgz#50976fd3f31168f585666f7922dde111c74567b8"
828+
integrity sha512-tYoDBbtqOVigEDMAcTGsRlMycIIjwMCgD8eR2t0NANeQmgK/lvxNAvYyb6bZDD4frHRhIHkJu2TBRvB0ERkOmw==
829+
830+
831+
version "1.1.0"
832+
resolved "https://registry.yarnpkg.com/@redis/time-series/-/time-series-1.1.0.tgz#cba454c05ec201bd5547aaf55286d44682ac8eb5"
833+
integrity sha512-c1Q99M5ljsIuc4YdaCwfUEXsofakb9c8+Zse2qxTadu8TalLXuAESzLvFAvNVbkmSlvlzIQOLpBCmWI9wTOt+g==
834+
801835
"@sinclair/typebox@^0.27.8":
802836
version "0.27.8"
803837
resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e"
@@ -1797,6 +1831,11 @@ clone@^1.0.2:
17971831
resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e"
17981832
integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==
17991833

1834+
1835+
version "1.1.2"
1836+
resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz#88ddaa46906e303b5de30d3153b7d9fe0a0c19ac"
1837+
integrity sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==
1838+
18001839
co@^4.6.0:
18011840
version "4.6.0"
18021841
resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
@@ -2607,6 +2646,11 @@ functional-red-black-tree@^1.0.1:
26072646
resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327"
26082647
integrity sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==
26092648

2649+
2650+
version "3.9.0"
2651+
resolved "https://registry.yarnpkg.com/generic-pool/-/generic-pool-3.9.0.tgz#36f4a678e963f4fdb8707eab050823abc4e8f5e4"
2652+
integrity sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==
2653+
26102654
gensync@^1.0.0-beta.2:
26112655
version "1.0.0-beta.2"
26122656
resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
@@ -4120,6 +4164,18 @@ readdirp@~3.6.0:
41204164
dependencies:
41214165
picomatch "^2.2.1"
41224166

4167+
4168+
version "4.7.0"
4169+
resolved "https://registry.yarnpkg.com/redis/-/redis-4.7.0.tgz#b401787514d25dd0cfc22406d767937ba3be55d6"
4170+
integrity sha512-zvmkHEAdGMn+hMRXuMBtu4Vo5P6rHQjLoHftu+lBqq8ZTA3RCVC/WzD790bkKKiNFp7d5/9PcSD19fJyyRvOdQ==
4171+
dependencies:
4172+
"@redis/bloom" "1.2.0"
4173+
"@redis/client" "1.6.0"
4174+
"@redis/graph" "1.1.1"
4175+
"@redis/json" "1.0.7"
4176+
"@redis/search" "1.2.0"
4177+
"@redis/time-series" "1.1.0"
4178+
41234179
41244180
version "0.2.0"
41254181
resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.2.0.tgz#e40299bf27422fe672b905468f34152a96efcaf7"
@@ -4985,6 +5041,11 @@ y18n@^5.0.5:
49855041
resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"
49865042
integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==
49875043

5044+
5045+
version "4.0.0"
5046+
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
5047+
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
5048+
49885049
yallist@^3.0.2:
49895050
version "3.1.1"
49905051
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd"

docker-compose.yml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
version: '3.8'
2+
3+
services:
4+
redis:
5+
image: redis:7.2.7
6+
container_name: redis
7+
restart: always
8+
ports:
9+
- "6379:6379"
10+
command: redis-server --save "" --appendonly no --maxmemory 100mb --maxmemory-policy allkeys-lru # ✅ Disable disk persistence
11+
volumes:
12+
- redis_data:/data # ✅ Ensures no persistence to disk
13+
environment:
14+
- ALLOW_EMPTY_PASSWORD=yes
15+
16+
redisinsight:
17+
image: redis/redisinsight:2.66
18+
container_name: redisinsight
19+
restart: always
20+
ports:
21+
- "5540:5540"
22+
depends_on:
23+
- redis
24+
environment:
25+
- REDIS_URI=redis://redis:6379 # ✅ Connect RedisInsight to Redis automatically
26+
27+
volumes:
28+
redis_data:
29+
driver: local
30+
driver_opts:
31+
type: tmpfs # ✅ Store Redis data in memory only
32+
device: tmpfs

0 commit comments

Comments
 (0)