Skip to content

Commit a632a7f

Browse files
feat: [GROOT-1552] implement taxonomy methods in CDA (#2389)
1 parent 59ac267 commit a632a7f

11 files changed

+466
-0
lines changed

lib/create-contentful-api.ts

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ import type {
2424
SyncOptions,
2525
EntrySkeletonType,
2626
LocaleCode,
27+
ConceptCollection,
28+
Concept,
29+
ConceptScheme,
30+
ConceptSchemeCollection,
2731
} from './types/index.js'
2832
import normalizeSearchParameters from './utils/normalize-search-parameters.js'
2933
import normalizeSelect from './utils/normalize-select.js'
@@ -467,6 +471,98 @@ export default function createContentfulApi<OptionType extends ChainOptions>(
467471
})
468472
}
469473

474+
function getConceptScheme<Locales extends LocaleCode>(
475+
id: string,
476+
query: Record<string, any> = {},
477+
): Promise<ConceptScheme<Locales>> {
478+
return internalGetConceptScheme<Locales>(id, query)
479+
}
480+
481+
async function internalGetConceptScheme<Locales extends LocaleCode>(
482+
id: string,
483+
query: Record<string, any> = {},
484+
): Promise<ConceptScheme<Locales>> {
485+
try {
486+
return get({
487+
context: 'environment',
488+
path: `taxonomy/concept-schemes/${id}`,
489+
config: createRequestConfig({
490+
query: normalizeSearchParameters(normalizeSelect(query)),
491+
}),
492+
})
493+
} catch (error) {
494+
errorHandler(error)
495+
}
496+
}
497+
498+
function getConceptSchemes<Locales extends LocaleCode>(
499+
query: Record<string, any> = {},
500+
): Promise<ConceptSchemeCollection<Locales>> {
501+
return internalGetConceptSchemes<Locales>(query)
502+
}
503+
504+
async function internalGetConceptSchemes<Locales extends LocaleCode>(
505+
query: Record<string, any> = {},
506+
): Promise<ConceptSchemeCollection<Locales>> {
507+
try {
508+
return get({
509+
context: 'environment',
510+
path: 'taxonomy/concept-schemes',
511+
config: createRequestConfig({
512+
query: normalizeSearchParameters(normalizeSelect(query)),
513+
}),
514+
})
515+
} catch (error) {
516+
errorHandler(error)
517+
}
518+
}
519+
520+
function getConcept<Locales extends LocaleCode>(
521+
id: string,
522+
query: Record<string, any> = {},
523+
): Promise<Concept<Locales>> {
524+
return internalGetConcept<Locales>(id, query)
525+
}
526+
527+
async function internalGetConcept<Locales extends LocaleCode>(
528+
id: string,
529+
query: Record<string, any> = {},
530+
): Promise<Concept<Locales>> {
531+
try {
532+
return get({
533+
context: 'environment',
534+
path: `taxonomy/concepts/${id}`,
535+
config: createRequestConfig({
536+
query: normalizeSearchParameters(normalizeSelect(query)),
537+
}),
538+
})
539+
} catch (error) {
540+
errorHandler(error)
541+
}
542+
}
543+
544+
function getConcepts<Locales extends LocaleCode>(
545+
query: Record<string, any> = {},
546+
): Promise<ConceptCollection<Locales>> {
547+
return internalGetConcepts<Locales>(query)
548+
}
549+
550+
async function internalGetConcepts<Locales extends LocaleCode>(
551+
query: Record<string, any> = {},
552+
): Promise<ConceptCollection<Locales>> {
553+
try {
554+
return get({
555+
context: 'environment',
556+
path: 'taxonomy/concepts',
557+
config: createRequestConfig({
558+
query: normalizeSearchParameters(normalizeSelect(query)),
559+
}),
560+
})
561+
} catch (error) {
562+
errorHandler(error)
563+
}
564+
}
565+
470566
/*
471567
* Switches BaseURL to use /environments path
472568
* */
@@ -495,6 +591,12 @@ export default function createContentfulApi<OptionType extends ChainOptions>(
495591
getEntry,
496592
getEntries,
497593

594+
getConceptScheme,
595+
getConceptSchemes,
596+
597+
getConcept,
598+
getConcepts,
599+
498600
createAssetKey,
499601
} as unknown as ContentfulClientApi<undefined>
500602
}

lib/types/client.ts

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import { LocaleCode, LocaleCollection } from './locale.js'
44
import {
55
AssetQueries,
66
AssetsQueries,
7+
ConceptSchemesQueries,
8+
ConceptsQueries,
79
EntriesQueries,
810
EntryQueries,
911
EntrySkeletonType,
@@ -14,6 +16,8 @@ import { Tag, TagCollection } from './tag.js'
1416
import { AssetKey } from './asset-key.js'
1517
import { Entry, EntryCollection } from './entry.js'
1618
import { Asset, AssetCollection, AssetFields } from './asset.js'
19+
import { Concept, ConceptCollection } from './concept.js'
20+
import { ConceptScheme, ConceptSchemeCollection } from './concept-scheme.js'
1721

1822
/**
1923
* Client chain modifiers used in all types that depend on the client configuration.
@@ -202,6 +206,82 @@ export interface ContentfulClientApi<Modifiers extends ChainModifiers> {
202206
*/
203207
getTags(query?: TagQueries): Promise<TagCollection>
204208

209+
/**
210+
* Fetches a Concept
211+
* @param id - The concept’s ID
212+
* @returns Promise for a concept
213+
* @example
214+
* ```typescript
215+
* const contentful = require('contentful')
216+
*
217+
* const client = contentful.createClient({
218+
* space: '<space_id>',
219+
* accessToken: '<content_delivery_api_key>'
220+
* })
221+
*
222+
* const concept = await client.getConcept('<concept_id>')
223+
* console.log(concept)
224+
* ```
225+
*/
226+
getConcept(id: string): Promise<Concept<'en-US'>>
227+
228+
/**
229+
* Fetches a collection of Concepts
230+
* @param query - Object with search parameters
231+
* @returns Promise for a collection of Concepts
232+
* @example
233+
* ```typescript
234+
* const contentful = require('contentful')
235+
*
236+
* const client = contentful.createClient({
237+
* space: '<space_id>',
238+
* accessToken: '<content_delivery_api_key>'
239+
* })
240+
*
241+
* const response = await client.getConcepts()
242+
* console.log(response.items)
243+
* ```
244+
*/
245+
getConcepts(query?: ConceptsQueries): Promise<ConceptCollection<'en-US'>>
246+
247+
/**
248+
* Fetches a Concept Scheme
249+
* @param id - The concept scheme's ID
250+
* @returns Promise for a concept scheme
251+
* @example
252+
* ```typescript
253+
* const contentful = require('contentful')
254+
*
255+
* const client = contentful.createClient({
256+
* space: '<space_id>',
257+
* accessToken: '<content_delivery_api_key>'
258+
* })
259+
*
260+
* const conceptScheme = await client.getConceptScheme('<concept_id>')
261+
* console.log(conceptScheme)
262+
* ```
263+
*/
264+
getConceptScheme(id: string): Promise<ConceptScheme<'en-US'>>
265+
266+
/**
267+
* Fetches a collection of Concept Schemes
268+
* @param query - Object with search parameters
269+
* @returns Promise for a collection of Concept Schemes
270+
* @example
271+
* ```typescript
272+
* const contentful = require('contentful')
273+
*
274+
* const client = contentful.createClient({
275+
* space: '<space_id>',
276+
* accessToken: '<content_delivery_api_key>'
277+
* })
278+
*
279+
* const response = await client.getConceptSchemes()
280+
* console.log(response.items)
281+
* ```
282+
*/
283+
getConceptSchemes(query?: ConceptSchemesQueries): Promise<ConceptSchemeCollection<'en-US'>>
284+
205285
/**
206286
* Creates an asset key for signing asset URLs (Embargoed Assets)
207287
* @returns Promise for an asset key

lib/types/concept-scheme.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { Link } from './link'
2+
import { LocaleCode } from './locale'
3+
4+
type ISODateString = string
5+
6+
export type ConceptSchemeSys = {
7+
id: string
8+
type: 'TaxonomyConceptScheme'
9+
createdAt: ISODateString
10+
updatedAt: ISODateString
11+
version: number
12+
}
13+
14+
export interface ConceptScheme<Locales extends LocaleCode> {
15+
sys: ConceptSchemeSys
16+
uri?: string
17+
prefLabel: {
18+
[locale in Locales]: string
19+
}
20+
definition?:
21+
| {
22+
[locale in Locales]: string
23+
}
24+
| null
25+
topConcepts: Link<'TaxonomyConcept'>[]
26+
concepts: Link<'TaxonomyConcept'>[]
27+
totalConcepts: number
28+
}
29+
30+
export type ConceptSchemeCollection<Locale extends LocaleCode> = {
31+
sys: {
32+
type: 'Array'
33+
}
34+
items: ConceptScheme<Locale>[]
35+
limit: number
36+
pages?: {
37+
prev?: string
38+
next?: string
39+
}
40+
}

lib/types/concept.ts

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import { Link } from './link'
2+
import { LocaleCode } from './locale'
3+
4+
type ISODateString = string
5+
6+
export type ConceptSys = {
7+
id: string
8+
type: 'TaxonomyConcept'
9+
createdAt: ISODateString
10+
updatedAt: ISODateString
11+
version: number
12+
}
13+
14+
export interface Concept<Locales extends LocaleCode> {
15+
sys: ConceptSys
16+
uri?: string
17+
prefLabel: {
18+
[locale in Locales]: string
19+
}
20+
altLabels?: {
21+
[locale in Locales]: string[]
22+
}
23+
hiddenLabels?: {
24+
[locale in Locales]: string[]
25+
}
26+
note?:
27+
| {
28+
[locale in Locales]: string
29+
}
30+
| null
31+
changeNote?:
32+
| {
33+
[locale in Locales]: string
34+
}
35+
| null
36+
definition?:
37+
| {
38+
[locale in Locales]: string
39+
}
40+
| null
41+
editorialNote?:
42+
| {
43+
[locale in Locales]: string
44+
}
45+
| null
46+
example?:
47+
| {
48+
[locale in Locales]: string
49+
}
50+
| null
51+
historyNote?:
52+
| {
53+
[locale in Locales]: string
54+
}
55+
| null
56+
scopeNote?:
57+
| {
58+
[locale in Locales]: string
59+
}
60+
| null
61+
notations?: string[]
62+
broader?: Link<'TaxonomyConcept'>[]
63+
related?: Link<'TaxonomyConcept'>[]
64+
}
65+
66+
export type ConceptCollection<Locale extends LocaleCode> = {
67+
sys: {
68+
type: 'Array'
69+
}
70+
items: Concept<Locale>[]
71+
limit: number
72+
pages?: {
73+
prev?: string
74+
next?: string
75+
}
76+
}

lib/types/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ export * from './asset.js'
22
export * from './asset-key.js'
33
export { AddChainModifier, ChainModifiers, ContentfulClientApi } from './client.js'
44
export * from './collection.js'
5+
export * from './concept-scheme.js'
6+
export * from './concept.js'
57
export * from './content-type.js'
68
export * from './entry.js'
79
export * from './link.js'

lib/types/query/order.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,3 +90,7 @@ export type AssetOrderFilter = {
9090
export type TagOrderFilter = {
9191
order?: (OrderFilterPaths<TagSys, 'sys'> | 'name' | '-name')[]
9292
}
93+
94+
export type TaxonomyOrderFilter = {
95+
order?: ('sys.createdAt' | 'sys.updatedAt' | 'prefLabel')[]
96+
}

lib/types/query/query.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { EntryFieldsExistenceFilter, ExistenceFilter } from './existence.js'
1414
import { LocationSearchFilters } from './location.js'
1515
import {
1616
AssetOrderFilter,
17+
TaxonomyOrderFilter,
1718
EntryOrderFilter,
1819
EntryOrderFilterWithFields,
1920
TagOrderFilter,
@@ -219,3 +220,14 @@ export type TagQueries = TagNameFilters &
219220
SysQueries<Pick<TagSys, 'createdAt' | 'updatedAt' | 'visibility' | 'id' | 'type'>> &
220221
TagOrderFilter &
221222
FixedPagedOptions
223+
224+
type CursorPaginationOptions = {
225+
limit?: number
226+
prevPage?: string
227+
nextPage?: string
228+
}
229+
230+
export type ConceptsQueries = CursorPaginationOptions &
231+
TaxonomyOrderFilter & { concept_scheme?: string }
232+
233+
export type ConceptSchemesQueries = CursorPaginationOptions & TaxonomyOrderFilter

test/integration/getConcept.test.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import * as contentful from '../../lib/contentful'
2+
import { params } from './utils'
3+
4+
if (process.env.API_INTEGRATION_TESTS) {
5+
params.host = '127.0.0.1:5000'
6+
params.insecure = true
7+
}
8+
9+
const client = contentful.createClient(params)
10+
11+
describe('getConcept', () => {
12+
it('returns a single concept', async () => {
13+
const response = await client.getConcept('3eXhEIEzcZqwHyYWHbzSoS')
14+
15+
expect(response.sys.type).toBe('TaxonomyConcept')
16+
})
17+
})

0 commit comments

Comments
 (0)