Skip to content

Commit

Permalink
feat: add wordClass and maxCount query parameters
Browse files Browse the repository at this point in the history
  • Loading branch information
adalinesimonian committed Jan 12, 2024
1 parent 0618f74 commit 947297c
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 27 deletions.
4 changes: 4 additions & 0 deletions src/dictionary/providers/ordboekene-api.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,24 +26,28 @@ export class OrdboekeneApiService {
dictionaries?: Dictionary[],
maxCount?: number,
searchType?: OrdboekeneApiSearchType,
wordClass?: string,
): Promise<any> {
return this.request<any>('api/suggest', {
q: word,
include: this.getSearchTypeParam(searchType),
...(dictionaries ? { dict: this.getDictParam(dictionaries) } : {}),
...(maxCount ? { n: maxCount } : {}),
...(wordClass ? { wc: wordClass } : {}),
});
}

articles(
word: string,
dictionaries: Dictionary[],
searchType: OrdboekeneApiSearchType = OrdboekeneApiSearchType.Exact,
wordClass?: string,
): Promise<any> {
return this.request<any>('api/articles', {
w: word,
scope: this.getSearchTypeParam(searchType),
...(dictionaries ? { dict: this.getDictParam(dictionaries) } : {}),
...(wordClass ? { wc: wordClass } : {}),
});
}

Expand Down
52 changes: 32 additions & 20 deletions src/dictionary/providers/word.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,22 @@ import {
OrdboekeneApiService,
OrdboekeneApiSearchType as ApiSearchType,
} from './ordboekene-api.service';
import { TwoWayMap } from '../types';

const wordClassMap = new TwoWayMap([
['NOUN', WordClass.Substantiv],
['ADJ', WordClass.Adjektiv],
['ADV', WordClass.Adverb],
['VERB', WordClass.Verb],
['PRON', WordClass.Pronomen],
['ADP', WordClass.Preposisjon],
['CCONJ', WordClass.Konjunksjon],
['INTJ', WordClass.Interjeksjon],
['DET', WordClass.Determinativ],
['SCONJ', WordClass.Subjunksjon],
['SYM', WordClass.Symbol],
['ABBR', WordClass.Forkorting],
]);

@Injectable()
export class WordService {
Expand All @@ -30,14 +46,17 @@ export class WordService {
word: string,
dictionaries: Dictionary[],
searchType?: ApiSearchType,
maxCount?: number,
wordClass?: WordClass,
): Promise<Suggestions> {
this.logger.debug(`Getting suggestions for word: ${word}`);

const data = await this.ordboekeneApiService.suggest(
word,
dictionaries,
undefined,
maxCount,
searchType,
wordClass ? wordClassMap.getReverse(wordClass) : undefined,
);
this.logger.debug(`Received suggestions: ${JSON.stringify(data)}`);

Expand All @@ -47,12 +66,18 @@ export class WordService {
async getWord(
word: string,
dictionaries: Dictionary[],
wordClass?: WordClass,
): Promise<Word | undefined> {
await this.loadConcepts();

this.logger.debug(`Getting articles for word: ${word}`);

const data = await this.ordboekeneApiService.articles(word, dictionaries);
const data = await this.ordboekeneApiService.articles(
word,
dictionaries,
ApiSearchType.Exact,
wordClass ? wordClassMap.getReverse(wordClass) : undefined,
);

// Example API response:

Expand Down Expand Up @@ -184,33 +209,20 @@ export class WordService {
}

private transformWordClass(article: any): WordClass | undefined {
const tagMapping: { [key: string]: WordClass } = {
NOUN: WordClass.Substantiv,
ADJ: WordClass.Adjektiv,
ADV: WordClass.Adverb,
VERB: WordClass.Verb,
PRON: WordClass.Pronomen,
ADP: WordClass.Preposisjon,
CCONJ: WordClass.Konjunksjon,
INTJ: WordClass.Interjeksjon,
DET: WordClass.Determinativ,
SCONJ: WordClass.Subjunksjon,
SYM: WordClass.Symbol,
ABBR: WordClass.Forkorting,
};

if (article.lemmas && article.lemmas.length > 0) {
const lemma = article.lemmas[0];
if (lemma.paradigm_info && lemma.paradigm_info.length > 0) {
const tags = lemma.paradigm_info[0].tags;
if (tags && tags.length > 0) {
const wordClassTag = tags.find((tag: string) => tagMapping[tag]);
if (!tagMapping[wordClassTag]) {
const wordClassTag = tags.find((tag: string) =>
wordClassMap.has(tag),
);
if (!wordClassTag) {
this.logger.warn(
`Fann ikkje ordklasse for ${lemma.lemma} (prøvde å transformera ${tags} til ordklasse)`,
);
}
return wordClassTag && tagMapping[wordClassTag];
return wordClassTag && wordClassMap.get(wordClassTag);
}
}
}
Expand Down
23 changes: 21 additions & 2 deletions src/dictionary/resolvers/suggestions.resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
WordService,
OrdboekeneApiSearchType as ApiSearchType,
} from '../providers';
import { Dictionary, Suggestions, Word } from '../models';
import { Dictionary, Suggestions, Word, WordClass } from '../models';

@Resolver(() => Word)
export class SuggestionsResolver {
Expand All @@ -27,6 +27,19 @@ export class SuggestionsResolver {
'Liste over ordbøker som skal brukast for å generera forslag. Standardverdiane er Bokmålsordboka og Nynorskordboka.',
})
dictionaries: Dictionary[],
@Args('maxCount', {
type: () => Number,
nullable: true,
description: 'Begrensar talet på forslag som skal returnerast.',
})
maxCount: number | undefined,
@Args('wordClass', {
type: () => WordClass,
nullable: true,
description:
'Begrensar forslaga til å berre gjelda ord med denne ordklassen.',
})
wordClass: WordClass | undefined,
@Info() info: GraphQLResolveInfo,
) {
const selections = info.fieldNodes[0].selectionSet?.selections;
Expand Down Expand Up @@ -58,6 +71,12 @@ export class SuggestionsResolver {
}
}

return this.wordService.getSuggestions(word, dictionaries, searchTypes);
return this.wordService.getSuggestions(
word,
dictionaries,
searchTypes,
maxCount,
wordClass,
);
}
}
27 changes: 22 additions & 5 deletions src/dictionary/resolvers/word.resolver.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Resolver, Query, Args, Parent, ResolveField } from '@nestjs/graphql';
import { WordService } from '../providers';
import { Dictionary, Article, Word } from '../models';
import { Dictionary, Article, Word, WordClass } from '../models';

@Resolver(() => Word)
export class WordResolver {
Expand All @@ -24,13 +24,30 @@ export class WordResolver {
'Liste over ordbøker der søket skal utførast. Standardverdiane er Bokmålsordboka og Nynorskordboka.',
})
dictionaries: Dictionary[],
@Args('wordClass', {
type: () => WordClass,
nullable: true,
description:
'Begrensar søket til å berre gjelda ord med denne ordklassen.',
})
wordClass: WordClass | undefined,
) {
return this.wordService.getWord(word, dictionaries);
return this.wordService.getWord(word, dictionaries, wordClass);
}

@ResolveField(() => [Article], { nullable: true })
async articles(@Parent() word: Word) {
return (await this.wordService.getWord(word.word, word.dictionaries))
?.articles;
async articles(
@Parent() word: Word,
@Args('wordClass', {
type: () => WordClass,
nullable: true,
description:
'Begrensar artiklane til å berre gjelda ord med denne ordklassen.',
})
wordClass: WordClass | undefined,
) {
return (
await this.wordService.getWord(word.word, word.dictionaries, wordClass)
)?.articles;
}
}
1 change: 1 addition & 0 deletions src/dictionary/types/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './two-way-map';
55 changes: 55 additions & 0 deletions src/dictionary/types/two-way-map.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
export class TwoWayMap<L extends string | number, R extends string | number> {
private map: Record<L, R> = {} as Record<L, R>;
private reverseMap: Record<R, L> = {} as Record<R, L>;

constructor(entries: [L, R][]) {
entries.forEach(([left, right]) => {
this.map[left] = right;
this.reverseMap[right] = left;
});
}

get(left: L): R {
return this.map[left];
}

getReverse(right: R): L {
return this.reverseMap[right];
}

has(left: string | number): left is L {
return left in this.map;
}

hasReverse(right: string | number): right is R {
return right in this.reverseMap;
}

getEntries(): [L, R][] {
return Object.entries(this.map) as [L, R][];
}

getReverseEntries(): [R, L][] {
return Object.entries(this.reverseMap) as [R, L][];
}

getKeys(): L[] {
return Object.keys(this.map) as L[];
}

getReverseKeys(): R[] {
return Object.keys(this.reverseMap) as R[];
}

getValues(): R[] {
return Object.values(this.map) as R[];
}

getReverseValues(): L[] {
return Object.values(this.reverseMap) as L[];
}

get size(): number {
return Object.keys(this.map).length;
}
}

0 comments on commit 947297c

Please sign in to comment.