feat(model): ✨ add ref
class to link ressources
This commit is contained in:
parent
53d6727650
commit
3f37648dfd
|
@ -1,3 +1,4 @@
|
|||
import { Ref } from '@/src/models/utils/ref.ts'
|
||||
import { DateString, ToJson, UUID } from '@/types.ts'
|
||||
import { regex } from '@/utils.ts'
|
||||
|
||||
|
@ -90,6 +91,10 @@ export class Ressource {
|
|||
toString(): string {
|
||||
return `Ressource (${JSON.stringify(this)})`
|
||||
}
|
||||
|
||||
toRef(): Ref<Ressource> {
|
||||
return Ref.fromRessource(this)
|
||||
}
|
||||
}
|
||||
|
||||
export interface Ressource {
|
||||
|
|
102
src/models/utils/ref.ts
Normal file
102
src/models/utils/ref.ts
Normal file
|
@ -0,0 +1,102 @@
|
|||
import { Db } from '@/mod.ts'
|
||||
import type { UUID } from '@/types.ts'
|
||||
import {
|
||||
Credential,
|
||||
Group,
|
||||
Machine,
|
||||
type Ressource,
|
||||
Service,
|
||||
User,
|
||||
} from '@models'
|
||||
|
||||
export type RefString<T extends Ressource> =
|
||||
| `@ref/${T['type']}#${UUID}`
|
||||
| Ref<T>
|
||||
export type RefResolver<T extends Ressource> = (
|
||||
ref: RefString<T>,
|
||||
) => T | Promise<T>
|
||||
export class Ref<T extends Ressource> extends String {
|
||||
static #toString<T extends Ressource>(
|
||||
{ uuid, type }: { uuid: UUID; type: T['type'] },
|
||||
) {
|
||||
return `@ref/${type}#${uuid}` as const
|
||||
}
|
||||
|
||||
static parse<T extends Ressource>(string: RefString<T>) {
|
||||
const [_, value] = string.split('/')
|
||||
const [type, uuid] = value.split('#') as [T['type'], UUID]
|
||||
|
||||
return { type, uuid } as const
|
||||
}
|
||||
|
||||
static fromRessource<T extends Ressource>(ressource: T): Ref<T> {
|
||||
return new Ref<T>(ressource)
|
||||
}
|
||||
|
||||
static fromString<T extends Ressource>(string: RefString<T>) {
|
||||
return new Ref<T>(Ref.parse(string))
|
||||
}
|
||||
|
||||
private constructor({ uuid, type }: { uuid: UUID; type: T['type'] }) {
|
||||
super(Ref.#toString({ uuid, type }))
|
||||
this.#type = type
|
||||
this.#uuid = uuid
|
||||
}
|
||||
|
||||
#type: T['type']
|
||||
#uuid: UUID
|
||||
|
||||
get type() {
|
||||
return this.#type
|
||||
}
|
||||
|
||||
get uuid() {
|
||||
return this.#uuid
|
||||
}
|
||||
|
||||
ref(resolver: RefResolver<T>) {
|
||||
return resolver(this.toString())
|
||||
}
|
||||
|
||||
toString() {
|
||||
return Ref.#toString<T>({ uuid: this.uuid, type: this.type })
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
return this.toString()
|
||||
}
|
||||
}
|
||||
|
||||
export function RefDbResolver(db: Db) {
|
||||
return <T extends Ressource>(ref: RefString<T>) => {
|
||||
const { type, uuid } = Ref.parse(ref)
|
||||
return db.ressource[type].get({ uuid })
|
||||
}
|
||||
}
|
||||
|
||||
export function RefRestResolver(endpoint: string) {
|
||||
return async <T extends Ressource>(ref: RefString<T>) => {
|
||||
const { type, uuid } = Ref.parse(ref)
|
||||
const url = new URL(`${type}/${uuid}`, endpoint)
|
||||
const response = await fetch(url)
|
||||
const json = await response.json()
|
||||
|
||||
if (type === 'user') {
|
||||
return User.fromJSON(json)
|
||||
}
|
||||
if (type === 'machine') {
|
||||
return Machine.fromJSON(json)
|
||||
}
|
||||
if (type === 'service') {
|
||||
return Service.fromJSON(json)
|
||||
}
|
||||
if (type === 'group') {
|
||||
return Group.fromJSON(json)
|
||||
}
|
||||
if (type === 'credential') {
|
||||
return Credential.fromJSON(json)
|
||||
}
|
||||
|
||||
throw new TypeError(`unknown ref type "${type}"`)
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue