Skip to content

Instantly share code, notes, and snippets.

@lightningspirit
Created June 25, 2024 10:33
Show Gist options
  • Save lightningspirit/af13b4b8a4d1ffaee698d9de09a62d3c to your computer and use it in GitHub Desktop.
Save lightningspirit/af13b4b8a4d1ffaee698d9de09a62d3c to your computer and use it in GitHub Desktop.
Pocketbase typings for collections
import PocketBaseClient from './pocketbase.ts'
type RecordMap = {
accounts: RecordAccount
categories: RecordCategory
pages: RecordPage
prices: RecordPrice
products: RecordProduct
users: RecordUser
}
type ModelMap = {
accounts: Account
categories: Category
pages: Page
prices: Price
products: Product
users: User
}
type Mappers = {
[K in keyof RecordMap]: (record: RecordMap[K]) => ModelMap[K]
}
function common(record: RecordModel) {
return {
id: record.id,
created: new Date(record.created),
updated: new Date(record.updated),
}
}
const mapper: Mappers = {
accounts(record) {
return {
...record,
...common(record),
expand: undefined,
}
},
categories(record) {
return {
...record,
...common(record),
expand: undefined,
}
},
pages(record) {
return {
...record,
...common(record),
expand: undefined,
}
},
prices(record) {
return {
name: record.name,
amount: {
usd: record.dollar,
eur: record.euro,
},
...common(record),
}
},
products(record) {
return {
...record,
...common(record),
images: previews.map((it) => pb.files.getUrl(record, it)),
expand: {
author: record.expand?.author
? mapper.users(record.expand.author)
: undefined,
category: record.expand?.category
? mapper.categories(record.expand.category)
: undefined,
prices: record.expand?.prices
? record.expand.prices.map(mapper.prices)
: undefined,
},
}
},
users: (record) => {
return {
...record,
...common(record),
avatar: record.avatar ? pb.files.getUrl(record, record.avatar) : undefined,
}
},
}
const pb = new PocketBaseClient<RecordMap, ModelMap>({
baseUrl: process.env.POCKETBASE_URL || 'http://127.0.0.1:8090',
mapper,
})
export default pb
import PocketBase, {
BaseAuthStore,
RecordModel,
RecordService,
} from 'pocketbase'
type RecordMapGeneric = {
[s: string]: RecordModel
}
type Mapper<
RMap extends RecordMapGeneric,
MMap extends { [K in keyof RMap]: any },
> = {
[K in keyof RMap]: (record: RMap[K]) => MMap[K]
}
class TypedRecordService<
RMap extends RecordMapGeneric,
MMap extends { [K in keyof RMap]: any },
K extends keyof RMap,
> extends RecordService<MMap[K]> {
private mapper: Mapper<RMap, MMap>
private idOrName: K
constructor(
client: PocketBase,
collectionIdOrName: K,
mapper: Mapper<RMap, MMap>,
) {
super(client, collectionIdOrName.toString())
this.idOrName = collectionIdOrName
this.mapper = mapper
}
decode(record: RMap[K]): MMap[K] {
return this.mapper[this.idOrName](record)
}
}
class PocketBaseClient<
RMap extends RecordMapGeneric,
MMap extends { [K in keyof RMap]: any },
> extends PocketBase {
private mapper: Mapper<RMap, MMap>
private services: Partial<{
[K in keyof RMap]: TypedRecordService<RMap, MMap, K>
}> = {}
constructor({
mapper,
baseUrl,
authStore,
lang,
}: {
baseUrl?: string
authStore?: BaseAuthStore | null
lang?: string
mapper: Mapper<RMap, MMap>
}) {
super(baseUrl, authStore, lang)
this.mapper = mapper
}
collection<K extends keyof RMap>(
idOrName: K,
): TypedRecordService<RMap, MMap, K> {
if (!this.services[idOrName]) {
this.services[idOrName] = new TypedRecordService<RMap, MMap, K>(
this,
idOrName,
this.mapper,
)
}
return this.services[idOrName]!
}
}
export default PocketBaseClient
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment