Properly initialize data source before making use in POST and PUT endpoints.master
@@ -18,7 +18,7 @@ export interface DataSource<T = object> { | |||||
getSingle(id: string): Promise<T | null>; | getSingle(id: string): Promise<T | null>; | ||||
create(data: Partial<T>): Promise<T>; | create(data: Partial<T>): Promise<T>; | ||||
delete(id: string): Promise<unknown>; | delete(id: string): Promise<unknown>; | ||||
emplace(id: string, data: Partial<T>): Promise<T>; | |||||
emplace(id: string, data: Partial<T>): Promise<[T, boolean]>; | |||||
patch(id: string, data: Partial<T>): Promise<T | null>; | patch(id: string, data: Partial<T>): Promise<T | null>; | ||||
} | } | ||||
@@ -75,10 +75,11 @@ export class DataSource<T extends Record<string, string>> implements DataSourceI | |||||
await writeFile(this.path, newData.map((d) => JSON.stringify(d)).join('\n')); | await writeFile(this.path, newData.map((d) => JSON.stringify(d)).join('\n')); | ||||
return data as T; | |||||
return [data, false] as [T, boolean]; | |||||
} | } | ||||
return this.create(dataToEmplace); | |||||
const newData = await this.create(dataToEmplace); | |||||
return [newData, true] as [T, boolean]; | |||||
} | } | ||||
async patch(id: string, data: Partial<T>) { | async patch(id: string, data: Partial<T>) { | ||||
@@ -501,10 +501,10 @@ export const handleCreateItem: Middleware = ({ | |||||
} | } | ||||
try { | try { | ||||
await theResource.dataSource.initialize(); | |||||
const newId = await theResource.newId(theResource.dataSource); | const newId = await theResource.newId(theResource.dataSource); | ||||
const params = bodyDeserialized as Record<string, unknown>; | const params = bodyDeserialized as Record<string, unknown>; | ||||
params[theResource.idAttr] = newId; | params[theResource.idAttr] = newId; | ||||
await theResource.dataSource.initialize(); | |||||
const newObject = await theResource.dataSource.create(params); | const newObject = await theResource.dataSource.create(params); | ||||
const theFormatted = theSerializerPair.serialize(newObject); | const theFormatted = theSerializerPair.serialize(newObject); | ||||
res.writeHead(constants.HTTP_STATUS_OK, { | res.writeHead(constants.HTTP_STATUS_OK, { | ||||
@@ -622,16 +622,20 @@ export const handleEmplaceItem: Middleware = ({ | |||||
} | } | ||||
try { | try { | ||||
const newId = await theResource.newId(theResource.dataSource); | |||||
const params = bodyDeserialized as Record<string, unknown>; | |||||
params[theResource.idAttr] = newId; | |||||
await theResource.dataSource.initialize(); | await theResource.dataSource.initialize(); | ||||
const newObject = await theResource.dataSource.emplace(mainResourceId, params); | |||||
const params = bodyDeserialized as Record<string, unknown>; | |||||
const [newObject, isCreated] = await theResource.dataSource.emplace(mainResourceId, params); | |||||
const theFormatted = theSerializerPair.serialize(newObject); | const theFormatted = theSerializerPair.serialize(newObject); | ||||
res.writeHead(constants.HTTP_STATUS_OK, { | |||||
'Content-Type': theMediaType, | |||||
'Location': `${serverParams.baseUrl}/${theResource.routeName}/${newId}` | |||||
}); | |||||
if (isCreated) { | |||||
res.writeHead(constants.HTTP_STATUS_CREATED, { | |||||
'Content-Type': theMediaType, | |||||
'Location': `${serverParams.baseUrl}/${theResource.routeName}/${mainResourceId}` | |||||
}); | |||||
} else { | |||||
res.writeHead(constants.HTTP_STATUS_OK, { | |||||
'Content-Type': theMediaType, | |||||
}); | |||||
} | |||||
res.end(theFormatted); | res.end(theFormatted); | ||||
} catch { | } catch { | ||||
res.statusCode = constants.HTTP_STATUS_INTERNAL_SERVER_ERROR; | res.statusCode = constants.HTTP_STATUS_INTERNAL_SERVER_ERROR; | ||||
@@ -1,4 +1,4 @@ | |||||
export * from './core'; | export * from './core'; | ||||
export * as valibot from 'valibot'; | |||||
export * as valibot from './validation'; | |||||
export * as dataSources from './data-sources'; | export * as dataSources from './data-sources'; | ||||
export * as serializers from './serializers'; | export * as serializers from './serializers'; |
@@ -15,7 +15,11 @@ const autoIncrement = async (dataSource: DataSource) => { | |||||
-Infinity | -Infinity | ||||
); | ); | ||||
return (highestId + 1).toString(); | |||||
if (Number.isFinite(highestId)) { | |||||
return (highestId + 1).toString(); | |||||
} | |||||
return "1"; | |||||
}; | }; | ||||
@@ -67,7 +71,7 @@ const User = resource(v.object( | |||||
middleName: v.string(), | middleName: v.string(), | ||||
lastName: v.string(), | lastName: v.string(), | ||||
bio: v.string(), | bio: v.string(), | ||||
createdAt: v.date() | |||||
birthday: v.datelike() | |||||
}, | }, | ||||
v.never() | v.never() | ||||
)) | )) | ||||
@@ -0,0 +1,13 @@ | |||||
import * as v from 'valibot'; | |||||
export * from 'valibot'; | |||||
export const datelike = () => v.transform( | |||||
v.union([ | |||||
v.string([v.isoDate()]), | |||||
v.string([v.isoDateTime()]), | |||||
v.number(), | |||||
v.date() | |||||
]), | |||||
(value) => new Date(value).toISOString(), | |||||
v.string([v.isoTimestamp()]) | |||||
); |