Skip to content

Commit

Permalink
feat: [GROOT-1552] implement taxonomy methods in CDA
Browse files Browse the repository at this point in the history
  • Loading branch information
LiamStokingerContentful committed Nov 27, 2024
1 parent 445344e commit 347f6af
Show file tree
Hide file tree
Showing 11 changed files with 432 additions and 0 deletions.
102 changes: 102 additions & 0 deletions lib/create-contentful-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ import type {
SyncOptions,
EntrySkeletonType,
LocaleCode,
ConceptCollection,
Concept,
ConceptScheme,
ConceptSchemeCollection,
} from './types/index.js'
import normalizeSearchParameters from './utils/normalize-search-parameters.js'
import normalizeSelect from './utils/normalize-select.js'
Expand Down Expand Up @@ -467,6 +471,98 @@ export default function createContentfulApi<OptionType extends ChainOptions>(
})
}

function getConceptScheme<Locales extends LocaleCode>(
id: string,
query: Record<string, any> = {},
): Promise<ConceptScheme<Locales>> {
return internalGetConceptScheme<Locales>(id, query)
}

async function internalGetConceptScheme<Locales extends LocaleCode>(
id: string,
query: Record<string, any> = {},
): Promise<ConceptScheme<Locales>> {
try {
return get({
context: 'environment',
path: `taxonomy/concept-schemes/${id}`,
config: createRequestConfig({
query: normalizeSearchParameters(normalizeSelect(query)),
}),
})
} catch (error) {
errorHandler(error)
}
}

function getConceptSchemes<Locales extends LocaleCode>(
query: Record<string, any> = {},
): Promise<ConceptSchemeCollection<Locales>> {
return internalGetConceptSchemes<Locales>(query)
}

async function internalGetConceptSchemes<Locales extends LocaleCode>(
query: Record<string, any> = {},
): Promise<ConceptSchemeCollection<Locales>> {
try {
return get({
context: 'environment',
path: 'taxonomy/concept-schemes',
config: createRequestConfig({
query: normalizeSearchParameters(normalizeSelect(query)),
}),
})
} catch (error) {
errorHandler(error)
}
}

function getConcept<Locales extends LocaleCode>(
id: string,
query: Record<string, any> = {},
): Promise<Concept<Locales>> {
return internalGetConcept<Locales>(id, query)
}

async function internalGetConcept<Locales extends LocaleCode>(
id: string,
query: Record<string, any> = {},
): Promise<Concept<Locales>> {
try {
return get({
context: 'environment',
path: `taxonomy/concepts/${id}`,
config: createRequestConfig({
query: normalizeSearchParameters(normalizeSelect(query)),
}),
})
} catch (error) {
errorHandler(error)
}
}

function getConcepts<Locales extends LocaleCode>(
query: Record<string, any> = {},
): Promise<ConceptCollection<Locales>> {
return internalGetConcepts<Locales>(query)
}

async function internalGetConcepts<Locales extends LocaleCode>(
query: Record<string, any> = {},
): Promise<ConceptCollection<Locales>> {
try {
return get({
context: 'environment',
path: 'taxonomy/concepts',
config: createRequestConfig({
query: normalizeSearchParameters(normalizeSelect(query)),
}),
})
} catch (error) {
errorHandler(error)
}
}

/*
* Switches BaseURL to use /environments path
* */
Expand Down Expand Up @@ -495,6 +591,12 @@ export default function createContentfulApi<OptionType extends ChainOptions>(
getEntry,
getEntries,

getConceptScheme,
getConceptSchemes,

getConcept,
getConcepts,

createAssetKey,
} as unknown as ContentfulClientApi<undefined>
}
80 changes: 80 additions & 0 deletions lib/types/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { LocaleCode, LocaleCollection } from './locale.js'
import {
AssetQueries,
AssetsQueries,
ConceptSchemesQueries,
ConceptsQueries,
EntriesQueries,
EntryQueries,
EntrySkeletonType,
Expand All @@ -14,6 +16,8 @@ import { Tag, TagCollection } from './tag.js'
import { AssetKey } from './asset-key.js'
import { Entry, EntryCollection } from './entry.js'
import { Asset, AssetCollection, AssetFields } from './asset.js'
import { Concept, ConceptCollection } from './concept.js'
import { ConceptScheme, ConceptSchemeCollection } from './concept-scheme.js'

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

/**
* Fetches a Concept
* @param id - The concept’s ID
* @returns Promise for a concept
* @example
* ```typescript
* const contentful = require('contentful')
*
* const client = contentful.createClient({
* space: '<space_id>',
* accessToken: '<content_delivery_api_key>'
* })
*
* const concept = await client.getConcept('<concept_id>')
* console.log(concept)
* ```
*/
getConcept(id: string): Promise<Concept<'en-US'>>

/**
* Fetches a collection of Concepts
* @param query - Object with search parameters
* @returns Promise for a collection of Concepts
* @example
* ```typescript
* const contentful = require('contentful')
*
* const client = contentful.createClient({
* space: '<space_id>',
* accessToken: '<content_delivery_api_key>'
* })
*
* const response = await client.getConcepts()
* console.log(response.items)
* ```
*/
getConcepts(query?: ConceptsQueries): Promise<ConceptCollection<'en-US'>>

/**
* Fetches a Concept Scheme
* @param id - The concept scheme's ID
* @returns Promise for a concept scheme
* @example
* ```typescript
* const contentful = require('contentful')
*
* const client = contentful.createClient({
* space: '<space_id>',
* accessToken: '<content_delivery_api_key>'
* })
*
* const conceptScheme = await client.getConceptScheme('<concept_id>')
* console.log(conceptScheme)
* ```
*/
getConceptScheme(id: string): Promise<ConceptScheme<'en-US'>>

/**
* Fetches a collection of Concept Schemes
* @param query - Object with search parameters
* @returns Promise for a collection of Concept Schemes
* @example
* ```typescript
* const contentful = require('contentful')
*
* const client = contentful.createClient({
* space: '<space_id>',
* accessToken: '<content_delivery_api_key>'
* })
*
* const response = await client.getConceptSchemes()
* console.log(response.items)
* ```
*/
getConceptSchemes(query?: ConceptSchemesQueries): Promise<ConceptSchemeCollection<'en-US'>>

/**
* Creates an asset key for signing asset URLs (Embargoed Assets)
* @returns Promise for an asset key
Expand Down
33 changes: 33 additions & 0 deletions lib/types/concept-scheme.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { Link } from './link'
import { LocaleCode } from './locale'

type ISODateString = string

export type ConceptSchemeSys = {
id: string
type: 'TaxonomyConceptScheme'
createdAt: ISODateString
updatedAt: ISODateString
version: number
}

export interface ConceptScheme<Locales extends LocaleCode> {
sys: ConceptSchemeSys
uri?: string
prefLabel: {
[locale in Locales]: string
}
definition?: {
[locale in Locales]: string
}
topConcepts: Link<'TaxonomyConcept'>[]
concepts: Link<'TaxonomyConcept'>[]
totalConcepts: number
}

export type ConceptSchemeCollection<Locale extends LocaleCode> = {
items: ConceptScheme<Locale>[]
limit: number
prevPage: string
nextPage: string
}
57 changes: 57 additions & 0 deletions lib/types/concept.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { Link } from './link'
import { LocaleCode } from './locale'

type ISODateString = string

export type ConceptSys = {
id: string
type: 'TaxonomyConcept'
createdAt: ISODateString
updatedAt: ISODateString
version: number
}

export interface Concept<Locales extends LocaleCode> {
sys: ConceptSys
uri?: string
prefLabel: {
[locale in Locales]: string
}
altLabels?: {
[locale in Locales]: string[]
}
hiddenLabels?: {
[locale in Locales]: string[]
}
note?: {
[locale in Locales]: string
}
changeNote?: {
[locale in Locales]: string
}
definition?: {
[locale in Locales]: string
}
editorialNote?: {
[locale in Locales]: string
}
example?: {
[locale in Locales]: string
}
historyNote?: {
[locale in Locales]: string
}
scopeNote?: {
[locale in Locales]: string
}
notations?: string[]
broader?: Link<'TaxonomyConcept'>[]
related?: Link<'TaxonomyConcept'>[]
}

export type ConceptCollection<Locale extends LocaleCode> = {
items: Concept<Locale>[]
limit: number
prevPage: string
nextPage: string
}
2 changes: 2 additions & 0 deletions lib/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ export * from './asset.js'
export * from './asset-key.js'
export { AddChainModifier, ChainModifiers, ContentfulClientApi } from './client.js'
export * from './collection.js'
export * from './concept-scheme.js'
export * from './concept.js'
export * from './content-type.js'
export * from './entry.js'
export * from './link.js'
Expand Down
4 changes: 4 additions & 0 deletions lib/types/query/order.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,7 @@ export type AssetOrderFilter = {
export type TagOrderFilter = {
order?: (OrderFilterPaths<TagSys, 'sys'> | 'name' | '-name')[]
}

export type TaxonomyOrderFilter = {
order?: ('sys.createdAt' | 'sys.updatedAt' | 'prefLabel')[]
}
12 changes: 12 additions & 0 deletions lib/types/query/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { EntryFieldsExistenceFilter, ExistenceFilter } from './existence.js'
import { LocationSearchFilters } from './location.js'
import {
AssetOrderFilter,
TaxonomyOrderFilter,
EntryOrderFilter,
EntryOrderFilterWithFields,
TagOrderFilter,
Expand Down Expand Up @@ -219,3 +220,14 @@ export type TagQueries = TagNameFilters &
SysQueries<Pick<TagSys, 'createdAt' | 'updatedAt' | 'visibility' | 'id' | 'type'>> &
TagOrderFilter &
FixedPagedOptions

type CursorPaginationOptions = {
limit?: number
prevPage?: string
nextPage?: string
}

export type ConceptsQueries = CursorPaginationOptions &
TaxonomyOrderFilter & { concept_scheme?: string }

export type ConceptSchemesQueries = CursorPaginationOptions & TaxonomyOrderFilter
17 changes: 17 additions & 0 deletions test/integration/getConcept.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import * as contentful from '../../lib/contentful'
import { params } from './utils'

if (process.env.API_INTEGRATION_TESTS) {
params.host = '127.0.0.1:5000'
params.insecure = true
}

const client = contentful.createClient(params)

describe('getConcept', () => {
it('returns a single concept', async () => {
const response = await client.getConcept('3eXhEIEzcZqwHyYWHbzSoS')

expect(response.sys.type).toBe('TaxonomyConcept')
})
})
17 changes: 17 additions & 0 deletions test/integration/getConceptScheme.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import * as contentful from '../../lib/contentful'
import { params } from './utils'

if (process.env.API_INTEGRATION_TESTS) {
params.host = '127.0.0.1:5000'
params.insecure = true
}

const client = contentful.createClient(params)

describe('getConceptScheme', () => {
it('returns a single concept scheme', async () => {
const response = await client.getConceptScheme('7lcOh0M5JAu5xvEwWzs00H')

expect(response.sys.type).toBe('TaxonomyConceptScheme')
})
})
Loading

0 comments on commit 347f6af

Please sign in to comment.