diff --git a/src/data/openalex-fields.json.ts b/src/data/openalex-fields.json.ts index d569443..c6330dd 100644 --- a/src/data/openalex-fields.json.ts +++ b/src/data/openalex-fields.json.ts @@ -2,7 +2,7 @@ import { HttpClient, Terminal } from '@effect/platform' import { NodeTerminal } from '@effect/platform-node' import { Schema } from '@effect/schema' import { Effect, Record } from 'effect' -import { FieldIdFromUrlSchema, FieldIdSchema } from '../lib/OpenAlex.js' +import { DomainIdFromUrlSchema, DomainIdSchema, FieldIdFromUrlSchema, FieldIdSchema } from '../lib/OpenAlex.js' import { UrlFromStringSchema } from '../lib/Url.js' const Fields = Schema.Struct({ @@ -10,11 +10,14 @@ const Fields = Schema.Struct({ Schema.Struct({ id: Schema.compose(UrlFromStringSchema, FieldIdFromUrlSchema), display_name: Schema.String, + domain: Schema.Struct({ + id: Schema.compose(UrlFromStringSchema, DomainIdFromUrlSchema), + }), }), ), }) -const FieldNames = Schema.Record(FieldIdSchema, Schema.String) +const FieldNames = Schema.Record(FieldIdSchema, Schema.Struct({ name: Schema.String, domain: DomainIdSchema })) const program = Effect.gen(function* () { const terminal = yield* Terminal.Terminal @@ -25,7 +28,10 @@ const program = Effect.gen(function* () { .fetchOk(request) .pipe(Effect.andThen(HttpClient.response.schemaBodyJson(Fields)), Effect.scoped) - const transformedData = Record.fromIterableWith(data.results, field => [field.id, field.display_name]) + const transformedData = Record.fromIterableWith(data.results, field => [ + field.id, + { name: field.display_name, domain: field.domain.id }, + ]) const encoded = yield* Schema.encode(Schema.parseJson(FieldNames))(transformedData) diff --git a/src/data/requests.json.ts b/src/data/requests.json.ts index 198356a..4424ab5 100644 --- a/src/data/requests.json.ts +++ b/src/data/requests.json.ts @@ -3,7 +3,7 @@ import { NodeTerminal } from '@effect/platform-node' import { Schema } from '@effect/schema' import { Effect } from 'effect' import * as LanguageCode from '../lib/LanguageCode.js' -import { FieldIdSchema } from '../lib/OpenAlex.js' +import { DomainIdSchema, FieldIdSchema } from '../lib/OpenAlex.js' import * as Temporal from '../lib/Temporal.js' const Requests = Schema.Array( @@ -11,6 +11,7 @@ const Requests = Schema.Array( timestamp: Temporal.InstantFromStringSchema, language: Schema.optional(LanguageCode.LanguageCodeSchema, { nullable: true }), fields: Schema.Array(FieldIdSchema), + domains: Schema.Array(DomainIdSchema), }), ) diff --git a/src/lib/OpenAlex.ts b/src/lib/OpenAlex.ts index 0c12c5d..c8d0312 100644 --- a/src/lib/OpenAlex.ts +++ b/src/lib/OpenAlex.ts @@ -15,3 +15,17 @@ export const FieldIdFromUrlSchema = Schema.transformOrFail(UrlFromSelfSchema, Fi : Either.left(new ParseResult.Type(ast, url)), encode: topicId => ParseResult.succeed(new URL(`https://openalex.org/fields/${encodeURIComponent(topicId)}`)), }) + +type DomainId = string & Brand.Brand<'OpenAlexDomainId'> + +const DomainId = Brand.nominal() + +export const DomainIdSchema = Schema.String.pipe(Schema.fromBrand(DomainId)) + +export const DomainIdFromUrlSchema = Schema.transformOrFail(UrlFromSelfSchema, DomainIdSchema, { + decode: (url, _, ast) => + url.origin === 'https://openalex.org' && url.pathname.startsWith('/domains/') + ? Either.right(decodeURIComponent(url.pathname.substring(9))) + : Either.left(new ParseResult.Type(ast, url)), + encode: topicId => ParseResult.succeed(new URL(`https://openalex.org/domains/${encodeURIComponent(topicId)}`)), +}) diff --git a/src/requests.md b/src/requests.md index c8f88f9..7ae8d58 100644 --- a/src/requests.md +++ b/src/requests.md @@ -42,7 +42,7 @@ const languageColor = Plot.scale({ }) const requestsByField = requests.flatMap(({ fields, ...request }) => - fields.map(field => ({ ...request, field: openAlexFields[field] })), + fields.map(field => ({ ...request, field: openAlexFields[field].name })), ) ```