Skip to content

Commit

Permalink
AfO Register (#398)
Browse files Browse the repository at this point in the history
* Implement repository & tests (WiP)

* Add AfO service, tests & bibliography routes and tabs

* Add tests & format

* Impelment AfO Register search forms

* Implement search & async options (WiP)

* Update & fix tests

* Implement suggestions (WiP)

* Adjust search, sorting & form (WiP)

* Correct Markdown string output

* Update queries & interface, refactor

* Refactor search form

* Add AfO Register & bibliography intro, style

* Implement AfO Reg. display in Fragmentarium

* Implement fragment injection, link, style, refactor & update tests

* Fix CSS style

* Refactor

* Refactor more

* Add missing space

* Update repository & service tests

* Add factory & display tests

* Add search results display test

* Add text select tests

* Add fragment records test & fix display

* Add & update tests

* Extend repository tests

* Update bibliography tests

* Add repository test

* Extend search form tests
  • Loading branch information
khoidt authored Nov 28, 2023
1 parent 7799178 commit e53966b
Show file tree
Hide file tree
Showing 46 changed files with 1,868 additions and 73 deletions.
63 changes: 63 additions & 0 deletions src/afo-register/application/AfoRegisterService.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { testDelegation, TestData } from 'test-support/utils'
import AfoRegisterRepository from 'afo-register/infrastructure/AfoRegisterRepository'
import AfoRegisterRecord, {
AfoRegisterRecordSuggestion,
} from 'afo-register/domain/Record'
import AfoRegisterService from 'afo-register/application/AfoRegisterService'
import { stringify } from 'query-string'

jest.mock('afo-register/infrastructure/AfoRegisterRepository')
const afoRegisterRepository = new (AfoRegisterRepository as jest.Mock)()

const afoRegisterService = new AfoRegisterService(afoRegisterRepository)

const resultStub = {
afoNumber: 'AfO 1',
page: '2',
text: 'some text',
textNumber: '5',
discussedBy: '',
discussedByNotes: '',
linesDiscussed: '',
fragmentNumbers: undefined,
}

const suggestionResultStub = {
text: 'some text',
textNumbers: undefined,
}

const query = { afoNumber: resultStub.afoNumber, page: resultStub.page }
const entry = new AfoRegisterRecord(resultStub)
const suggestionEntry = new AfoRegisterRecordSuggestion(suggestionResultStub)

const testData: TestData<AfoRegisterService>[] = [
new TestData(
'search',
[stringify(query)],
afoRegisterRepository.search,
[entry],
[stringify(query), undefined],
Promise.resolve([entry])
),
new TestData(
'searchTextsAndNumbers',
[['text1', 'number1']],
afoRegisterRepository.searchTextsAndNumbers,
[entry],
[['text1', 'number1']],
Promise.resolve([entry])
),
new TestData(
'searchSuggestions',
['suggestion query'],
afoRegisterRepository.searchSuggestions,
[suggestionEntry],
['suggestion query'],
Promise.resolve([suggestionEntry])
),
]

describe('AfoRegisterService', () => {
testDelegation(afoRegisterService, testData)
})
40 changes: 40 additions & 0 deletions src/afo-register/application/AfoRegisterService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import Promise from 'bluebird'
import AfoRegisterRecord, {
AfoRegisterRecordSuggestion,
} from 'afo-register/domain/Record'
import AfoRegisterRepository from 'afo-register/infrastructure/AfoRegisterRepository'
import FragmentService from 'fragmentarium/application/FragmentService'

export interface afoRegisterSearch {
search(query: string): Promise<readonly AfoRegisterRecord[]>
searchSuggestions(
query: string
): Promise<readonly AfoRegisterRecordSuggestion[]>
}

export default class AfoRegisterService implements afoRegisterSearch {
private readonly afoRegisterRepository: AfoRegisterRepository

constructor(afoRegisterRepository: AfoRegisterRepository) {
this.afoRegisterRepository = afoRegisterRepository
}

search(
query: string,
fragmentService?: FragmentService
): Promise<readonly AfoRegisterRecord[]> {
return this.afoRegisterRepository.search(query, fragmentService)
}

searchTextsAndNumbers(
query: readonly string[]
): Promise<readonly AfoRegisterRecord[]> {
return this.afoRegisterRepository.searchTextsAndNumbers(query)
}

searchSuggestions(
query: string
): Promise<readonly AfoRegisterRecordSuggestion[]> {
return this.afoRegisterRepository.searchSuggestions(query)
}
}
48 changes: 48 additions & 0 deletions src/afo-register/domain/Record.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import AfoRegisterRecord from 'afo-register/domain/Record'

describe('AfoRegisterRecord', () => {
const mockRecord = {
afoNumber: '123',
page: '456',
text: 'Sample text',
textNumber: '789',
linesDiscussed: 'Some lines',
discussedBy: 'John Doe',
discussedByNotes: 'Notes by John',
fragmentNumbers: ['BM777'],
}

describe('constructor', () => {
describe('constructor', () => {
it('should initialize properties correctly', () => {
const record = new AfoRegisterRecord(mockRecord)
expect(record.afoNumber).toEqual('123')
expect(record.page).toEqual('456')
expect(record.text).toEqual('Sample text')
expect(record.textNumber).toEqual('789')
expect(record.linesDiscussed).toEqual('Some lines')
expect(record.discussedBy).toEqual('John Doe')
expect(record.discussedByNotes).toEqual('Notes by John')
})
})
})

describe('Converts to Markdown string', () => {
it('Returns the correct markdown string with fragments', () => {
const record = new AfoRegisterRecord(mockRecord)
const result = record.toMarkdownString()
expect(result).toEqual(
'Sample text 789 ([BM777](/fragmentarium/BM777)), Some lines: John Doe Notes by John<small class="text-black-50 ml-3">[123, 456]</small>'
)
})

it('Handles sup tags correctly', () => {
const recordWithSup = new AfoRegisterRecord({
...mockRecord,
text: 'Sample^text^',
})
const result = recordWithSup.toMarkdownString()
expect(result).toContain('<sup>text</sup>')
})
})
})
113 changes: 113 additions & 0 deletions src/afo-register/domain/Record.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import produce, { Draft, immerable } from 'immer'

interface RecordData {
readonly afoNumber: string
readonly page: string
readonly text: string
readonly textNumber: string
readonly linesDiscussed?: string
readonly discussedBy?: string
readonly discussedByNotes?: string
readonly fragmentNumbers?: string[]
}

export class AfoRegisterRecordSuggestion {
[immerable] = true

readonly text: string
readonly textNumbers?: string[]

constructor({
text,
textNumbers,
}: {
readonly text: string
readonly textNumbers?: string[]
}) {
this.text = text
this.textNumbers = textNumbers
}
}

export default class AfoRegisterRecord {
[immerable] = true

readonly afoNumber: string
readonly page: string
readonly text: string
readonly textNumber: string
readonly linesDiscussed?: string
readonly discussedBy?: string
readonly discussedByNotes?: string
readonly fragmentNumbers?: string[]

constructor({
afoNumber,
page,
text,
textNumber,
linesDiscussed,
discussedBy,
discussedByNotes,
fragmentNumbers,
}: RecordData) {
this.afoNumber = afoNumber
this.page = page
this.text = text
this.textNumber = textNumber
this.linesDiscussed = linesDiscussed
this.discussedBy = discussedBy
this.discussedByNotes = discussedByNotes
this.fragmentNumbers = fragmentNumbers
}

toMarkdownString(): string {
const textNumber = this.textNumberToMarkdownString()
const fragments = this.fragmentsToMarkdownString()
const linesDiscussed = this.linesDiscussedToMarkdownString()
const discussedBy = this.discussedByToMarkdownString()
const discussedByNotes = this.discussedByNotesToMarkdownString()
const footnote = this.footnotesToMarkdownString()
const result = `${this.text}${textNumber}${fragments}${linesDiscussed}${discussedBy}${discussedByNotes}${footnote}`
return result.replace(/\^([^^]+)\^/g, '<sup>$1</sup>')
}

setFragmentNumbers(fragmentNumbers: string[]): AfoRegisterRecord {
return produce(this, (draft: Draft<AfoRegisterRecord>) => {
draft.fragmentNumbers = fragmentNumbers
})
}

private textNumberToMarkdownString(): string {
return `${this.textNumber ? ` ${this.textNumber}` : ''}`
}

private fragmentsToMarkdownString(): string {
if (!this.fragmentNumbers || this.fragmentNumbers?.length < 1) {
return ''
}
const fragmentsString = this.fragmentNumbers
.map(
(fragmentNumber) =>
`[${fragmentNumber}](/fragmentarium/${fragmentNumber})`
)
.join(', ')
return ` (${fragmentsString})`
}

private linesDiscussedToMarkdownString(): string {
return this.linesDiscussed ? `, ${this.linesDiscussed}` : ''
}

private discussedByToMarkdownString(): string {
return this.discussedBy ? `: ${this.discussedBy}` : ''
}

private discussedByNotesToMarkdownString(): string {
return this.discussedByNotes ? ` ${this.discussedByNotes}` : ''
}

private footnotesToMarkdownString(): string {
return `<small class="text-black-50 ml-3">[${this.afoNumber}, ${this.page}]</small>`
}
}
Loading

0 comments on commit e53966b

Please sign in to comment.