Skip to content

Commit e7bbab4

Browse files
committed
feat(chrono): checkout use-case
1 parent cbbc427 commit e7bbab4

File tree

5 files changed

+115
-31
lines changed

5 files changed

+115
-31
lines changed

packages/chrono/playground/PlayApp.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ async function run() {
4444
name: 'list',
4545
method: 'list',
4646
},
47+
{
48+
name: 'checkout',
49+
method: 'checkout',
50+
},
4751
]
4852

4953
const command = options.find((o) => o.name === commandName)

packages/chrono/src/ChronoApp.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import CommitUseCase from './use-cases/CommitUseCase'
1919
import StatusUseCase from './use-cases/StatusUseCase'
2020
import AddUseCase from './use-cases/AddUseCase'
2121
import ListFilesUseCase from './use-cases/ListFilesUseCase'
22+
import CheckoutUseCase from './use-cases/CheckoutUseCase'
2223

2324
export default class ChronoApp {
2425
private readonly drive: IDrive
@@ -106,4 +107,10 @@ export default class ChronoApp {
106107

107108
return useCase.execute()
108109
}
110+
111+
public async checkout(path: string, hash: string) {
112+
const useCase = new CheckoutUseCase(this.drive, this.objectRepository, this.blobRepository)
113+
114+
return useCase.execute({ hash, path })
115+
}
109116
}

packages/chrono/src/repositories/implementations/LocalHeadEntryRepository.ts

Lines changed: 18 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,19 @@
1-
import ChronoObjectTree from '../../entities/ChronoObjectTree'
21
import HeadEntry from '../../entities/HeadEntry'
32
import IDrive from '../../gateways/IDrive'
43
import HelperService from '../../services/HelperService'
4+
import TreeService from '../../services/TreeService'
55
import IHeadEntryRepository from '../IHeadEntryRepository'
66
import IObjectRepository from '../IObjectRepository'
77

88
export default class LocalHeadEntryRepository implements IHeadEntryRepository {
9-
constructor(
10-
private readonly drive: IDrive,
11-
private readonly objectRepository: IObjectRepository
12-
) {}
13-
14-
public async findEntriesFromTree(treeHash: string, basePath = '') {
15-
const entries = [] as HeadEntry[]
16-
17-
const object = await this.objectRepository.findOrFail(treeHash)
18-
19-
const tree = new ChronoObjectTree(object.content)
20-
21-
for await (const e of tree.entries) {
22-
const headEntry = HeadEntry.from({
23-
path: `${basePath}${e.path}`,
24-
hash: e.hash,
25-
type: e.type,
26-
})
27-
28-
entries.push(headEntry)
29-
30-
if (e.type === 'tree') {
31-
const childEntries = await this.findEntriesFromTree(e.hash, `${headEntry.path}/`)
32-
33-
entries.push(...childEntries)
34-
}
35-
}
36-
37-
return entries
9+
private readonly drive: IDrive
10+
private readonly objectRepository: IObjectRepository
11+
private readonly treeService: TreeService
12+
13+
constructor(drive: IDrive, objectRepository: IObjectRepository) {
14+
this.drive = drive
15+
this.objectRepository = objectRepository
16+
this.treeService = new TreeService(objectRepository)
3817
}
3918

4019
public findAll: IHeadEntryRepository['findAll'] = async () => {
@@ -49,7 +28,15 @@ export default class LocalHeadEntryRepository implements IHeadEntryRepository {
4928
const object = await this.objectRepository.findOrFail(hash)
5029

5130
if (object.type === 'commit') {
52-
return this.findEntriesFromTree(object.head.tree)
31+
const entries = await this.treeService.findTreeIndex(object.head.tree)
32+
33+
return entries.map((entry) =>
34+
HeadEntry.from({
35+
path: entry.fullPath,
36+
hash: entry.hash,
37+
type: entry.type as any,
38+
})
39+
)
5340
}
5441

5542
return []
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import ChronoObjectTree from '../entities/ChronoObjectTree'
2+
import IObjectRepository from '../repositories/IObjectRepository'
3+
4+
interface TreeEntry {
5+
path: string
6+
fullPath: string
7+
hash: string
8+
type: string
9+
}
10+
11+
export default class TreeService {
12+
constructor(private readonly objectRepository: IObjectRepository) {}
13+
14+
private async findEntriesFromTree(treeHash: string, basePath = '') {
15+
const entries = [] as TreeEntry[]
16+
17+
const object = await this.objectRepository.findOrFail(treeHash)
18+
19+
const tree = new ChronoObjectTree(object.content)
20+
21+
for await (const e of tree.entries) {
22+
const entry: TreeEntry = {
23+
path: e.path,
24+
fullPath: `${basePath}${e.path}`,
25+
hash: e.hash,
26+
type: e.type,
27+
}
28+
29+
entries.push(entry)
30+
31+
if (e.type === 'tree') {
32+
const childEntries = await this.findEntriesFromTree(e.hash, `${entry.path}/`)
33+
34+
entries.push(...childEntries)
35+
}
36+
}
37+
38+
return entries
39+
}
40+
41+
public async findTreeIndex(hash: string) {
42+
return this.findEntriesFromTree(hash)
43+
}
44+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import IDrive from '../gateways/IDrive'
2+
import IBlobRepository from '../repositories/IBlobRepository'
3+
import IObjectRepository from '../repositories/IObjectRepository'
4+
import TreeService from '../services/TreeService'
5+
6+
interface Params {
7+
path: string
8+
hash: string
9+
}
10+
11+
export default class CheckoutUseCase {
12+
constructor(
13+
private readonly drive: IDrive,
14+
private readonly objectRepository: IObjectRepository,
15+
private readonly blobRepository: IBlobRepository
16+
) {}
17+
18+
public async execute({ path, hash }: Params) {
19+
const service = new TreeService(this.objectRepository)
20+
const object = await this.objectRepository.findOrFail(hash)
21+
22+
if (object.type !== 'commit') {
23+
throw new Error('Object is not a commit')
24+
}
25+
26+
const treeIndexEntries = await service.findTreeIndex(object.head.tree)
27+
28+
const treeEntry = treeIndexEntries.find((entry) => entry.fullPath === path)
29+
30+
if (!treeEntry) return
31+
32+
const blobObject = await this.objectRepository.findOrFail(treeEntry.hash)
33+
34+
if (blobObject.type !== 'blob') {
35+
throw new Error('Error looking for blob object')
36+
}
37+
38+
const contents = await this.blobRepository.findOrFail(blobObject.head.blobHash)
39+
40+
await this.drive.write(path, contents)
41+
}
42+
}

0 commit comments

Comments
 (0)