@@ -105,5 +105,5 @@ dist | |||||
.tern-port | .tern-port | ||||
.npmrc | .npmrc | ||||
*.jsonl | |||||
examples/**/*.jsonl | |||||
.idea/ | .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 {readFile, writeFile} from 'fs/promises'; | ||||
import {join} from 'path'; | |||||
import {DataSource as DataSourceInterface, Resource} from '../core'; | import {DataSource as DataSourceInterface, Resource} from '../core'; | ||||
export class DataSource<T extends Record<string, string>> implements DataSourceInterface<T> { | 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[] = []; | 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() { | 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); | |||||