Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: [GROOT-1552] implement taxonomy methods in CDA #2389

Merged
merged 2 commits into from
Dec 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
40 changes: 40 additions & 0 deletions lib/types/concept-scheme.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
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
}
| null
topConcepts: Link<'TaxonomyConcept'>[]
concepts: Link<'TaxonomyConcept'>[]
totalConcepts: number
}

export type ConceptSchemeCollection<Locale extends LocaleCode> = {
sys: {
type: 'Array'
}
items: ConceptScheme<Locale>[]
limit: number
pages?: {
prev?: string
next?: string
}
}
76 changes: 76 additions & 0 deletions lib/types/concept.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
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
}
| null
changeNote?:
| {
[locale in Locales]: string
}
| null
definition?:
| {
[locale in Locales]: string
}
| null
editorialNote?:
| {
[locale in Locales]: string
}
| null
example?:
| {
[locale in Locales]: string
}
| null
historyNote?:
| {
[locale in Locales]: string
}
| null
scopeNote?:
| {
[locale in Locales]: string
}
| null
notations?: string[]
broader?: Link<'TaxonomyConcept'>[]
related?: Link<'TaxonomyConcept'>[]
}

export type ConceptCollection<Locale extends LocaleCode> = {
sys: {
type: 'Array'
}
items: Concept<Locale>[]
limit: number
pages?: {
prev?: string
next?: 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')
})
})
Loading