@@ -105,5 +105,5 @@ dist | |||
.tern-port | |||
.npmrc | |||
*.jsonl | |||
examples/**/*.jsonl | |||
.idea/ |
@@ -0,0 +1,18 @@ | |||
import {DataSource, dataSources, Resource} from '../../src'; | |||
export const autoIncrement = async (dataSource: DataSource) => { | |||
const data = await dataSource.getMultiple() as Record<string, string>[]; | |||
const highestId = data.reduce<number>( | |||
(highestId, d) => (Number(d.id) > highestId ? Number(d.id) : highestId), | |||
-Infinity | |||
); | |||
if (Number.isFinite(highestId)) { | |||
return (highestId + 1).toString(); | |||
} | |||
return "1"; | |||
}; | |||
export const dataSource = (resource: Resource) => new dataSources.jsonlFile.DataSource(resource, 'examples/basic'); |
@@ -0,0 +1,28 @@ | |||
export const TEXT_SERIALIZER_PAIR = { | |||
serialize(obj: unknown, level = 0): string { | |||
if (Array.isArray(obj)) { | |||
return obj.map((o) => this.serialize(o)).join('\n\n'); | |||
} | |||
if (typeof obj === 'object') { | |||
if (obj !== null) { | |||
return Object.entries(obj) | |||
.map(([key, value]) => `${Array(level * 2).fill(' ').join('')}${key}: ${this.serialize(value, level + 1)}`) | |||
.join('\n'); | |||
} | |||
return ''; | |||
} | |||
if (typeof obj === 'number' && Number.isFinite(obj)) { | |||
return obj.toString(); | |||
} | |||
if (typeof obj === 'string') { | |||
return obj; | |||
} | |||
return ''; | |||
}, | |||
deserialize: <T>(str: string) => str as T | |||
}; |
@@ -0,0 +1,53 @@ | |||
import { | |||
application, | |||
resource, | |||
valibot as v, | |||
serializers | |||
} from '../../src'; | |||
import {TEXT_SERIALIZER_PAIR} from './serializers'; | |||
import {autoIncrement, dataSource} from './data-source'; | |||
const Piano = resource(v.object( | |||
{ | |||
brand: v.string() | |||
}, | |||
v.never() | |||
)) | |||
.name('Piano') | |||
.id('id', { | |||
generationStrategy: autoIncrement, | |||
}); | |||
// TODO implement authentication and RBAC on each resource | |||
const User = resource(v.object( | |||
{ | |||
firstName: v.string(), | |||
middleName: v.string(), | |||
lastName: v.string(), | |||
bio: v.string(), | |||
birthday: v.datelike() | |||
}, | |||
v.never() | |||
)) | |||
.name('User') | |||
.fullText('bio') | |||
.id('id', { | |||
generationStrategy: autoIncrement, | |||
}); | |||
const app = application({ | |||
name: 'piano-service', | |||
dataSource, | |||
}) | |||
.contentType('application/json', serializers.applicationJson) | |||
.contentType('text/json', serializers.textJson) | |||
.contentType('text/plain', TEXT_SERIALIZER_PAIR) | |||
.resource(Piano) | |||
.resource(User); | |||
const server = app.createServer({ | |||
baseUrl: '/api' | |||
}); | |||
server.listen(3000); |
@@ -1,4 +1,5 @@ | |||
import {readFile, writeFile} from 'fs/promises'; | |||
import {join} from 'path'; | |||
import {DataSource as DataSourceInterface, Resource} from '../core'; | |||
export class DataSource<T extends Record<string, string>> implements DataSourceInterface<T> { | |||
@@ -6,8 +7,8 @@ export class DataSource<T extends Record<string, string>> implements DataSourceI | |||
data: T[] = []; | |||
constructor(private readonly resource: Resource) { | |||
this.path = `${this.resource.collectionName}.jsonl`; | |||
constructor(private readonly resource: Resource, private readonly baseDir = '') { | |||
this.path = join(baseDir, `${this.resource.collectionName}.jsonl`); | |||
} | |||
async initialize() { | |||
@@ -1,99 +0,0 @@ | |||
import { | |||
application, | |||
DataSource, | |||
resource, | |||
valibot as v, | |||
dataSources, | |||
serializers | |||
} from '.'; | |||
const autoIncrement = async (dataSource: DataSource) => { | |||
const data = await dataSource.getMultiple() as Record<string, string>[]; | |||
const highestId = data.reduce<number>( | |||
(highestId, d) => (Number(d.id) > highestId ? Number(d.id) : highestId), | |||
-Infinity | |||
); | |||
if (Number.isFinite(highestId)) { | |||
return (highestId + 1).toString(); | |||
} | |||
return "1"; | |||
}; | |||
const TEXT_SERIALIZER_PAIR = { | |||
serialize(obj: unknown, level = 0): string { | |||
if (Array.isArray(obj)) { | |||
return obj.map((o) => this.serialize(o)).join('\n\n'); | |||
} | |||
if (typeof obj === 'object') { | |||
if (obj !== null) { | |||
return Object.entries(obj) | |||
.map(([key, value]) => `${Array(level * 2).fill(' ').join('')}${key}: ${this.serialize(value, level + 1)}`) | |||
.join('\n'); | |||
} | |||
return ''; | |||
} | |||
if (typeof obj === 'number' && Number.isFinite(obj)) { | |||
return obj.toString(); | |||
} | |||
if (typeof obj === 'string') { | |||
return obj; | |||
} | |||
return ''; | |||
}, | |||
deserialize: <T>(str: string) => str as T | |||
}; | |||
const Piano = resource(v.object( | |||
{ | |||
brand: v.string() | |||
}, | |||
v.never() | |||
)) | |||
.name('Piano') | |||
.id('id', { | |||
generationStrategy: autoIncrement, | |||
}); | |||
// TODO implement authentication and RBAC on each resource | |||
const User = resource(v.object( | |||
{ | |||
firstName: v.string(), | |||
middleName: v.string(), | |||
lastName: v.string(), | |||
bio: v.string(), | |||
birthday: v.datelike() | |||
}, | |||
v.never() | |||
)) | |||
.name('User') | |||
.fullText('bio') | |||
.id('id', { | |||
generationStrategy: autoIncrement, | |||
}); | |||
const app = application({ | |||
name: 'piano-service', | |||
dataSource: (resource) => new dataSources.jsonlFile.DataSource(resource), | |||
}) | |||
.contentType('application/json', serializers.applicationJson) | |||
.contentType('text/json', serializers.textJson) | |||
.contentType('text/plain', TEXT_SERIALIZER_PAIR) | |||
.resource(Piano) | |||
.resource(User); | |||
const server = app.createServer({ | |||
baseUrl: '/api' | |||
}); | |||
server.listen(3000); | |||