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: extensible environment #133

Merged
merged 2 commits into from
Apr 22, 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
5 changes: 5 additions & 0 deletions .changeset/fluffy-seals-scream.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@kopflos-cms/core": patch
---

Changed the generic interface to allow extending the runtime environment
28 changes: 14 additions & 14 deletions Api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,49 +3,49 @@ import EcmaScriptLoader from 'rdf-loader-code/ecmaScript.js'
import LoaderRegistryImpl, { LoaderRegistry } from 'rdf-loaders-registry'
import EcmaScriptModuleLoader from 'rdf-loader-code/ecmaScriptModule.js'
import EcmaScriptLiteralLoader from 'rdf-loader-code/ecmaScriptLiteral.js'
import type { NamedNode, Quad_Graph, DatasetCore } from '@rdfjs/types'
import type { NamedNode, Quad_Graph } from '@rdfjs/types'
import addAll from 'rdf-dataset-ext/addAll.js'
import fromStream from 'rdf-dataset-ext/fromStream.js'
import { replaceDatasetIRI } from './lib/replaceIRI.js'
import Factory from './lib/factory.js'
import Factory, { ExtractDataset } from './lib/factory.js'

interface ApiInit<D extends DatasetCore = DatasetCore> {
export interface ApiInit<E extends Factory = Factory> {
term?: NamedNode
dataset?: D
dataset?: ExtractDataset<E>
graph?: NamedNode
path?: string
codePath?: string
factory: Factory<D>
factory: E
}

export interface Api<D extends DatasetCore = DatasetCore> {
env: Factory<D>
export interface Api<E extends Factory = Factory> {
env: E
initialized: boolean
path: string
codePath: string
graph?: Quad_Graph | undefined
dataset: D
dataset: ExtractDataset<E>
term: NamedNode | undefined
loaderRegistry: LoaderRegistry
init(): Promise<void>
}

export default class Impl<D extends DatasetCore = DatasetCore> implements Api<D> {
export default class Impl<E extends Factory = Factory> implements Api<E> {
initialized: boolean
path: string
codePath: string
graph?: Quad_Graph | undefined
dataset: D
dataset: ExtractDataset<E>
private _term: NamedNode | undefined
loaderRegistry: LoaderRegistry
private _initialization?: Promise<void>
readonly tasks: Array<() => Promise<void>>
readonly env: Factory<D>
readonly env: E

constructor({ term, dataset, graph, path = '/api', codePath = process.cwd(), factory }: ApiInit<D>) {
constructor({ term, dataset, graph, path = '/api', codePath = process.cwd(), factory }: ApiInit<E>) {
this._term = term
this.env = factory
this.dataset = dataset || factory.dataset()
this.dataset = (dataset || factory.dataset()) as unknown as ExtractDataset<E>
this.graph = graph
this.path = path
this.codePath = codePath
Expand Down Expand Up @@ -98,7 +98,7 @@ export default class Impl<D extends DatasetCore = DatasetCore> implements Api<D>

async _beginInit() {
if (!this.dataset) {
this.dataset = this.env.dataset()
this.dataset = this.env.dataset() as unknown as ExtractDataset<E>
}

for (const task of this.tasks) {
Expand Down
8 changes: 4 additions & 4 deletions index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type { Readable } from 'stream'
import type * as RDF from '@rdfjs/types'
import type { GraphPointer } from 'clownface'
import type { Request } from 'express'
import type { Api } from './Api.js'
import Factory, { ExtractDataset } from './lib/factory.js'

export { default as middleware } from './middleware.js'
export { default as Api } from './Api.js'
Expand All @@ -11,7 +11,7 @@ export interface Resource<D extends RDF.DatasetCore = RDF.DatasetCore> {
term: RDF.NamedNode
prefetchDataset: RDF.DatasetCore
dataset(): Promise<D>
quadStream(): RDF.Stream & Readable
quadStream(): RDF.Stream
types: Set<RDF.NamedNode>
}

Expand All @@ -25,8 +25,8 @@ export interface PotentialOperation<D extends RDF.DatasetCore = RDF.DatasetCore>
operation: GraphPointer
}

export interface HydraBox<D extends RDF.DatasetCore = RDF.DatasetCore> {
api: Api<D>
export interface HydraBox<E extends Factory = Factory, D extends RDF.DatasetCore = ExtractDataset<E>> {
api: Api<E>
term: RDF.NamedNode
store: RDF.Store
resource: Resource<D> & { clownface(): Promise<GraphPointer<RDF.NamedNode, D>> }
Expand Down
1 change: 1 addition & 0 deletions lib/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ import type FsUtilsFactory from '@zazuko/rdf-utils-fs/Factory.js'
import type { NamespaceFactory } from '@rdfjs/namespace/Factory.js'

type Factory<D extends DatasetCore = DatasetCore> = Environment<DatasetCoreFactory<Quad, Quad, D> | DataFactory | TermSetFactory | ClownfaceFactory | NsBuildersFactory | FsUtilsFactory | NamespaceFactory>
export type ExtractDataset<This> = This extends DatasetCoreFactory ? ReturnType<This['dataset']> : never;

export default Factory
8 changes: 4 additions & 4 deletions lib/replaceIRI.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { Term, Quad, DatasetCore, NamedNode, DataFactory } from '@rdfjs/types'
import type { Term, Quad, NamedNode, DataFactory } from '@rdfjs/types'
import type { Environment } from '@rdfjs/environment/Environment.js'
import Factory from './factory.js'
import Factory, { ExtractDataset } from './factory.js'

export function replaceTermIRI<T extends Term>(oldIRI: string | NamedNode, newIRI: string | NamedNode, term: T, factory: Environment<DataFactory>): T {
const oldIRIString = typeof oldIRI === 'string' ? oldIRI : oldIRI.value
Expand All @@ -26,6 +26,6 @@ export function replaceQuadIRI(oldIRI: string | NamedNode, newIRI: string | Name
)
}

export function replaceDatasetIRI<D extends DatasetCore>(oldIRI: string | NamedNode, newIRI: string | NamedNode, dataset: D, factory: Factory<D>): D {
return factory.dataset([...dataset].map(quad => replaceQuadIRI(oldIRI, newIRI, quad, factory)))
export function replaceDatasetIRI<E extends Factory>(oldIRI: string | NamedNode, newIRI: string | NamedNode, dataset: ExtractDataset<E>, factory: E): ExtractDataset<E> {
return factory.dataset([...dataset].map(quad => replaceQuadIRI(oldIRI, newIRI, quad, factory))) as unknown as ExtractDataset<E>
}
15 changes: 12 additions & 3 deletions middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { defer } from 'promise-the-world'
import rdfHandler from '@rdfjs/express-handler'
import setLink from 'set-link'
import type { DatasetCore, Store } from '@rdfjs/types'
import type { CombinedEnvironment } from '@zazuko/env-core/lib/extend.js'
import apiHeader from './lib/middleware/apiHeader.js'
import iriTemplate from './lib/middleware/iriTemplate.js'
import operation from './lib/middleware/operation.js'
Expand All @@ -14,11 +15,19 @@ import waitFor from './lib/middleware/waitFor.js'
import StoreResourceLoader from './StoreResourceLoader.js'
import log from './lib/log.js'
import { Api } from './Api.js'
import Factory, { ExtractDataset } from './lib/factory.js'
import { HydraBox, ResourceLoader } from './index.js'

// eslint-disable-next-line @typescript-eslint/no-explicit-any
type ValuesArray<R extends Record<string, any>> = R[keyof R][];

export interface AdditionalFactories {
core: Factory
}

declare module 'express-serve-static-core' {
interface Request {
hydra: HydraBox
hydra: HydraBox<CombinedEnvironment<ValuesArray<AdditionalFactories>>>
}
}

Expand All @@ -36,7 +45,7 @@ interface Options<D extends DatasetCore> {
middleware?: HydraBoxMiddleware
}

function middleware<D extends DatasetCore>(api: Api<D>, { baseIriFromRequest, loader, store, middleware = {} }: Options<D>) {
function middleware<E extends Factory = Factory, D extends DatasetCore = ExtractDataset<E>>(api: Api<E>, { baseIriFromRequest, loader, store, middleware = {} }: Options<D>) {
const init = defer()
const router = Router()

Expand All @@ -51,7 +60,7 @@ function middleware<D extends DatasetCore>(api: Api<D>, { baseIriFromRequest, lo

debug(`${req.method} to ${term.value}`)

req.hydra = <HydraBox<D>>{
req.hydra = <HydraBox<E>>{
api,
store,
term,
Expand Down
5 changes: 3 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
"@types/uri-template-route": "^1.0.0",
"@typescript-eslint/eslint-plugin": "^7.0.1",
"@typescript-eslint/parser": "^7.0.1",
"@zazuko/env-core": "^1.1.2",
"@zazuko/env-node": "^2.1.2",
"alcaeus": "^3.0.0",
"c8": "^9.1.0",
Expand Down