Skip to content

Commit 72e9c20

Browse files
author
Eder Lima
committed
initial commit
0 parents  commit 72e9c20

File tree

7 files changed

+606
-0
lines changed

7 files changed

+606
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
**/node_modules

database.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"people": [
3+
{ "_id": "3288e873-3bf4-406a-99b3-c6b1cbd61665", "name": "Eder", "age": 20 }
4+
]
5+
}

package.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"name": "fsdb",
3+
"version": "1.0.0",
4+
"main": "index.js",
5+
"license": "MIT",
6+
"scripts": {
7+
"dev": "ts-node-dev --transpile-only --ignore-watch node_modules src/index.ts"
8+
},
9+
"devDependencies": {
10+
"@types/node": "^18.0.0",
11+
"@types/uuid": "^8.3.4",
12+
"ts-node-dev": "^2.0.0",
13+
"typescript": "^4.7.4"
14+
},
15+
"dependencies": {
16+
"uuid": "^8.3.2"
17+
}
18+
}

src/index.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import FileSystemDatabase, { collection } from './lib/index'
2+
import type { DatabaseRecord } from './lib/index'
3+
4+
type Person = {
5+
name: string
6+
age: number
7+
}
8+
9+
type DatabaseType = {
10+
people: Array<DatabaseRecord<Person>>
11+
}
12+
13+
FileSystemDatabase.fromFile<DatabaseType>('database.json').then(async (db) => {
14+
const peopleRef = collection(db, 'people')
15+
16+
peopleRef.createDoc({
17+
name: 'Eder',
18+
age: 20,
19+
})
20+
21+
const people = peopleRef.getDocs()
22+
23+
console.log(people)
24+
})

src/lib/index.ts

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import { v4 } from 'uuid'
2+
import fsl from 'fs'
3+
import fsp from 'fs/promises'
4+
5+
export type GenericDatabaseType = {
6+
[k: string]: any[]
7+
}
8+
9+
export type DatabaseRecord<T> = { _id: string } & T
10+
11+
type ArrayElement<T> = T extends readonly (infer ElementType)[]
12+
? ElementType
13+
: never
14+
15+
export default class FileSystemDatabase<T extends GenericDatabaseType> {
16+
private data: T | null
17+
18+
private constructor(private filename: string) {
19+
this.data = null
20+
}
21+
22+
static fromRef<T extends GenericDatabaseType>(
23+
filename: string,
24+
ref: T
25+
): FileSystemDatabase<T> {
26+
const database = new FileSystemDatabase<T>(filename)
27+
database.data = ref
28+
return database
29+
}
30+
31+
static async fromFile<T extends GenericDatabaseType>(
32+
filename: string
33+
): Promise<FileSystemDatabase<T>> {
34+
const database = new FileSystemDatabase<T>(filename)
35+
await database.load()
36+
return database
37+
}
38+
39+
public getData(): T {
40+
return this.data!
41+
}
42+
43+
public async load(): Promise<void> {
44+
if (!fsl.existsSync(this.filename)) {
45+
this.data = {} as T
46+
47+
await fsp.writeFile(this.filename, JSON.stringify(this.data))
48+
}
49+
50+
this.data = JSON.parse(await fsp.readFile(this.filename, 'utf8'))
51+
}
52+
53+
public async save(): Promise<void> {
54+
await fsp.writeFile(this.filename, JSON.stringify(this.data))
55+
}
56+
57+
public async sync(): Promise<void> {
58+
await this.load()
59+
}
60+
}
61+
62+
export const collection = <T extends GenericDatabaseType, K extends keyof T>(
63+
database: FileSystemDatabase<T>,
64+
path: K
65+
) => {
66+
let data: T[K]
67+
const dbRef = database.getData()[path]
68+
69+
if (dbRef) {
70+
data = dbRef
71+
} else {
72+
;(database.getData()[path] as any) = []
73+
data = database.getData()[path]
74+
}
75+
76+
type DocDTO = Omit<ArrayElement<T[K]>, '_id'>
77+
78+
return {
79+
createDoc(doc: DocDTO): void {
80+
const docRecord = {
81+
_id: v4(),
82+
...doc,
83+
}
84+
85+
data.push(docRecord)
86+
},
87+
deleteDoc(id: string) {
88+
data.splice(
89+
data.findIndex((r) => r._id === id),
90+
1
91+
)
92+
},
93+
updateDoc(id: string, record: Partial<DocDTO>) {
94+
const index = data.findIndex((item) => item._id === id)
95+
96+
if (index === -1) {
97+
throw new Error('Record not found')
98+
}
99+
100+
Object.assign(data[index], record)
101+
},
102+
getDoc(id: string): ArrayElement<T[K]> | null {
103+
return data.find((record) => record.id === id) || null
104+
},
105+
getDocs(): T[K] {
106+
return data
107+
},
108+
}
109+
}

tsconfig.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"compilerOptions": {
3+
"target": "esnext",
4+
"module": "CommonJS",
5+
"esModuleInterop": true,
6+
"forceConsistentCasingInFileNames": true,
7+
"strict": true,
8+
"skipLibCheck": true,
9+
"baseUrl": ".",
10+
"outDir": "./dist"
11+
}
12+
}

0 commit comments

Comments
 (0)