@bejibun/cache 0.1.11 → 0.1.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,48 @@ All notable changes to this project will be documented in this file.
3
3
 
4
4
  ---
5
5
 
6
+ ## [v0.1.13](https://github.com/crenata/bejibun-cache/compare/v0.1.12...v0.1.13) - 2025-12-12
7
+
8
+ ### 🩹 Fixes
9
+
10
+ ### 📖 Changes
11
+ What's New :
12
+ - Adding `ttl` supports for file scheme.
13
+
14
+ #### How does it work?
15
+ When you use a cache and include a `ttl`, the system generates a `unix timestamp` and adds it with specified `ttl`.
16
+ Then system will write it to a file in the format `ttl|file`, separated by the `|` symbol.
17
+
18
+ When you call data from the cache, the system creates metadata consisting of the `ttl` and `data` by splitting them with `|`.
19
+ The system then checks if the `ttl` is empty and returns the data.
20
+
21
+ Or if the `ttl` is present, the system checks whether the `current timestamp` <= `ttl`?
22
+ If so, the data is returned. Otherwise, the cache file will be deleted and returned null.
23
+
24
+ ### ❤️Contributors
25
+ - Havea Crenata ([@crenata](https://github.com/crenata))
26
+
27
+ **Full Changelog**: https://github.com/crenata/bejibun-cache/blob/master/CHANGELOG.md
28
+
29
+ ---
30
+
31
+ ## [v0.1.12](https://github.com/crenata/bejibun-cache/compare/v0.1.11...v0.1.12) - 2025-12-04
32
+
33
+ ### 🩹 Fixes
34
+
35
+ ### 📖 Changes
36
+ What's New :
37
+ - Adding `local` connection for file schema
38
+
39
+ Now, [@bejibun/cache](https://github.com/crenata/bejibun-cache) has local and redis for cache system.
40
+
41
+ ### ❤️Contributors
42
+ - Havea Crenata ([@crenata](https://github.com/crenata))
43
+
44
+ **Full Changelog**: https://github.com/crenata/bejibun-cache/blob/master/CHANGELOG.md
45
+
46
+ ---
47
+
6
48
  ## [v0.1.11](https://github.com/crenata/bejibun-cache/compare/v0.1.0...v0.1.11) - 2025-11-23
7
49
 
8
50
  ### 🩹 Fixes
package/README.md CHANGED
@@ -38,10 +38,16 @@ config/cache.ts
38
38
  ```
39
39
 
40
40
  ```ts
41
+ import App from "@bejibun/app";
42
+
41
43
  const config: Record<string, any> = {
42
- connection: "redis",
44
+ connection: "local",
43
45
 
44
46
  connections: {
47
+ local: {
48
+ path: App.Path.storagePath("cache") // absolute path
49
+ },
50
+
45
51
  redis: {
46
52
  host: "127.0.0.100",
47
53
  port: 6379,
@@ -4,6 +4,11 @@ export default class CacheBuilder {
4
4
  constructor();
5
5
  private get config();
6
6
  private key;
7
+ private connection;
8
+ private filePath;
9
+ private file;
10
+ private setFile;
11
+ private getFile;
7
12
  remember(key: string, callback: Function, ttl?: number): Promise<any>;
8
13
  has(key: string): Promise<boolean>;
9
14
  get(key: string): Promise<any>;
@@ -1,8 +1,10 @@
1
1
  import App from "@bejibun/app";
2
2
  import Logger from "@bejibun/logger";
3
3
  import Redis from "@bejibun/redis";
4
- import { isEmpty, isNotEmpty } from "@bejibun/utils";
4
+ import Luxon from "@bejibun/utils/facades/Luxon";
5
+ import { defineValue, isEmpty, isNotEmpty } from "@bejibun/utils";
5
6
  import fs from "fs";
7
+ import path from "path";
6
8
  import CacheConfig from "../config/cache";
7
9
  import CacheException from "../exceptions/CacheException";
8
10
  export default class CacheBuilder {
@@ -24,11 +26,65 @@ export default class CacheBuilder {
24
26
  return this.conf;
25
27
  }
26
28
  key(key) {
27
- return `${this.prefix}/${key}`;
29
+ const defaultKey = `${this.prefix}-${key.replaceAll("/", "-").replaceAll(" ", "-")}`;
30
+ return defaultKey;
31
+ /*if (forceDefault) return defaultKey;
32
+
33
+ switch (this.config.connection) {
34
+ case "local":
35
+ return `${Luxon.DateTime.now().toUnixInteger()}-${defaultKey}`;
36
+ default:
37
+ return defaultKey;
38
+ }*/
39
+ }
40
+ connection() {
41
+ return this.config.connections[this.config.connection];
42
+ }
43
+ filePath(key) {
44
+ return path.resolve(this.connection().path, `${this.key(key)}.cache`);
45
+ }
46
+ file(key) {
47
+ return Bun.file(this.filePath(key));
48
+ }
49
+ async setFile(key, data, ttl) {
50
+ ttl = defineValue(ttl, "");
51
+ if (isNotEmpty(ttl))
52
+ ttl = Luxon.DateTime.now().toUnixInteger() + ttl;
53
+ await fs.promises.mkdir(this.connection().path, { recursive: true });
54
+ return await Bun.write(this.filePath(key), `${ttl}|${data}`);
55
+ }
56
+ async getFile(key) {
57
+ let metadata = {
58
+ ttl: null,
59
+ data: null
60
+ };
61
+ const file = this.file(key);
62
+ if (await file.exists()) {
63
+ const raw = await file.text();
64
+ const [unix, ...rest] = raw.split("|");
65
+ const ttl = Number(unix);
66
+ const data = rest.join("|");
67
+ if (isEmpty(ttl) || Luxon.DateTime.now().toUnixInteger() <= ttl)
68
+ metadata = {
69
+ ttl: defineValue(Number(ttl)),
70
+ data
71
+ };
72
+ else
73
+ await this.file(key).delete();
74
+ }
75
+ return metadata;
28
76
  }
29
77
  async remember(key, callback, ttl) {
30
78
  let data;
31
79
  switch (this.config.connection) {
80
+ case "local":
81
+ const raw = await this.getFile(key);
82
+ data = raw.data;
83
+ if (isEmpty(data)) {
84
+ data = callback();
85
+ await this.setFile(key, data, ttl);
86
+ }
87
+ break;
32
88
  case "redis":
33
89
  data = await Redis.get(this.key(key));
34
90
  if (isEmpty(data)) {
@@ -45,6 +101,10 @@ export default class CacheBuilder {
45
101
  async has(key) {
46
102
  let data;
47
103
  switch (this.config.connection) {
104
+ case "local":
105
+ const raw = await this.getFile(key);
106
+ data = raw.data;
107
+ break;
48
108
  case "redis":
49
109
  data = await Redis.get(this.key(key));
50
110
  break;
@@ -57,6 +117,10 @@ export default class CacheBuilder {
57
117
  async get(key) {
58
118
  let data;
59
119
  switch (this.config.connection) {
120
+ case "local":
121
+ const raw = await this.getFile(key);
122
+ data = raw.data;
123
+ break;
60
124
  case "redis":
61
125
  data = await Redis.get(this.key(key));
62
126
  break;
@@ -71,6 +135,10 @@ export default class CacheBuilder {
71
135
  let data;
72
136
  try {
73
137
  switch (this.config.connection) {
138
+ case "local":
139
+ const raw = await this.getFile(key);
140
+ data = raw.data;
141
+ break;
74
142
  case "redis":
75
143
  data = await Redis.get(this.key(key));
76
144
  break;
@@ -80,6 +148,9 @@ export default class CacheBuilder {
80
148
  }
81
149
  if (isEmpty(data)) {
82
150
  switch (this.config.connection) {
151
+ case "local":
152
+ await this.setFile(key, value, ttl);
153
+ break;
83
154
  case "redis":
84
155
  await Redis.set(this.key(key), value, ttl);
85
156
  break;
@@ -102,6 +173,9 @@ export default class CacheBuilder {
102
173
  let status = true;
103
174
  try {
104
175
  switch (this.config.connection) {
176
+ case "local":
177
+ await this.setFile(key, value, ttl);
178
+ break;
105
179
  case "redis":
106
180
  await Redis.set(this.key(key), value, ttl);
107
181
  break;
@@ -117,6 +191,14 @@ export default class CacheBuilder {
117
191
  }
118
192
  async forget(key) {
119
193
  switch (this.config.connection) {
194
+ case "local":
195
+ try {
196
+ await this.file(key).delete();
197
+ }
198
+ catch (error) {
199
+ break;
200
+ }
201
+ break;
120
202
  case "redis":
121
203
  await Redis.del(this.key(key));
122
204
  break;
@@ -127,6 +209,18 @@ export default class CacheBuilder {
127
209
  async increment(key, ttl) {
128
210
  let data;
129
211
  switch (this.config.connection) {
212
+ case "local":
213
+ const raw = await this.getFile(key);
214
+ data = Number(raw.data);
215
+ if (isEmpty(data)) {
216
+ data = 1;
217
+ await this.setFile(key, String(data), ttl);
218
+ }
219
+ else {
220
+ data++;
221
+ await this.setFile(key, String(data), ttl);
222
+ }
223
+ break;
130
224
  case "redis":
131
225
  data = Number(await Redis.get(this.key(key)));
132
226
  if (isEmpty(data)) {
@@ -147,6 +241,18 @@ export default class CacheBuilder {
147
241
  async decrement(key, ttl) {
148
242
  let data;
149
243
  switch (this.config.connection) {
244
+ case "local":
245
+ const raw = await this.getFile(key);
246
+ data = Number(raw.data);
247
+ if (isEmpty(data)) {
248
+ data = -1;
249
+ await this.setFile(key, String(data), ttl);
250
+ }
251
+ else {
252
+ data--;
253
+ await this.setFile(key, String(data), ttl);
254
+ }
255
+ break;
150
256
  case "redis":
151
257
  data = Number(await Redis.get(this.key(key)));
152
258
  if (isEmpty(data)) {
package/config/cache.js CHANGED
@@ -1,6 +1,10 @@
1
+ import App from "@bejibun/app";
1
2
  const config = {
2
- connection: "redis",
3
+ connection: "local",
3
4
  connections: {
5
+ local: {
6
+ path: App.Path.storagePath("cache") // absolute path
7
+ },
4
8
  redis: {
5
9
  host: "127.0.0.100",
6
10
  port: 6379,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bejibun/cache",
3
- "version": "0.1.11",
3
+ "version": "0.1.13",
4
4
  "author": "Havea Crenata <havea.crenata@gmail.com>",
5
5
  "repository": {
6
6
  "type": "git",
@@ -37,7 +37,7 @@
37
37
  "dependencies": {
38
38
  "@bejibun/app": "^0.1.22",
39
39
  "@bejibun/logger": "^0.1.22",
40
- "@bejibun/redis": "^0.1.34",
41
- "@bejibun/utils": "^0.1.21"
40
+ "@bejibun/redis": "^0.1.36",
41
+ "@bejibun/utils": "^0.1.27"
42
42
  }
43
43
  }