improved contracts
This commit is contained in:
@@ -89,6 +89,13 @@ const documentSearchOptionsSchema = z.object({
|
|||||||
|
|
||||||
type DocumentSearchOptions = z.infer<typeof documentSearchOptionsSchema>;
|
type DocumentSearchOptions = z.infer<typeof documentSearchOptionsSchema>;
|
||||||
|
|
||||||
|
const documentSearchResultSchema = z.object({
|
||||||
|
documents: z.array(documentSchema),
|
||||||
|
more: z.boolean(),
|
||||||
|
});
|
||||||
|
|
||||||
|
type DocumentSearchResult = z.infer<typeof documentSearchResultSchema>;
|
||||||
|
|
||||||
const documentUpsertEventSchema = z.object({
|
const documentUpsertEventSchema = z.object({
|
||||||
action: z.union([z.literal('insert'), z.literal('update'), z.literal('delete')]),
|
action: z.union([z.literal('insert'), z.literal('update'), z.literal('delete')]),
|
||||||
document: documentSchema,
|
document: documentSchema,
|
||||||
@@ -96,12 +103,21 @@ const documentUpsertEventSchema = z.object({
|
|||||||
|
|
||||||
type DocumentUpsertEvent = z.infer<typeof documentUpsertEventSchema>;
|
type DocumentUpsertEvent = z.infer<typeof documentUpsertEventSchema>;
|
||||||
|
|
||||||
export type { Document, DocumentUpsert, MetaFilter, MetaCondition, DocumentSearchOptions, DocumentUpsertEvent };
|
export type {
|
||||||
|
Document,
|
||||||
|
DocumentUpsert,
|
||||||
|
MetaFilter,
|
||||||
|
MetaCondition,
|
||||||
|
DocumentSearchOptions,
|
||||||
|
DocumentSearchResult,
|
||||||
|
DocumentUpsertEvent,
|
||||||
|
};
|
||||||
export {
|
export {
|
||||||
documentSchema,
|
documentSchema,
|
||||||
documentUpsertSchema,
|
documentUpsertSchema,
|
||||||
metaFilterSchema,
|
metaFilterSchema,
|
||||||
metaConditionSchema,
|
metaConditionSchema,
|
||||||
documentSearchOptionsSchema,
|
documentSearchOptionsSchema,
|
||||||
|
documentSearchResultSchema,
|
||||||
documentUpsertEventSchema,
|
documentUpsertEventSchema,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import {
|
|||||||
documentUpsertEventSchema,
|
documentUpsertEventSchema,
|
||||||
type Document,
|
type Document,
|
||||||
type DocumentSearchOptions,
|
type DocumentSearchOptions,
|
||||||
|
type DocumentSearchResult,
|
||||||
type DocumentUpsert,
|
type DocumentUpsert,
|
||||||
type DocumentUpsertEvent,
|
type DocumentUpsertEvent,
|
||||||
} from './documents.schemas.ts';
|
} from './documents.schemas.ts';
|
||||||
@@ -26,7 +27,7 @@ class DocumentsService extends EventEmitter<DocumentEvents> {
|
|||||||
this.#services = services;
|
this.#services = services;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get = async (uri: string, type: string) => {
|
public get = async (uri: string, type: string): Promise<Document | undefined> => {
|
||||||
const db = await this.#services.get(DatabaseService).getDb();
|
const db = await this.#services.get(DatabaseService).getDb();
|
||||||
const [document] = await db<TableRow['document']>(tableNames.documents)
|
const [document] = await db<TableRow['document']>(tableNames.documents)
|
||||||
.where({
|
.where({
|
||||||
@@ -37,7 +38,7 @@ class DocumentsService extends EventEmitter<DocumentEvents> {
|
|||||||
return document;
|
return document;
|
||||||
};
|
};
|
||||||
|
|
||||||
public delete = async (uri: string, type: string) => {
|
public delete = async (uri: string, type: string): Promise<DocumentUpsertEvent | undefined> => {
|
||||||
const db = await this.#services.get(DatabaseService).getDb();
|
const db = await this.#services.get(DatabaseService).getDb();
|
||||||
const [document] = await db<TableRow['document']>(tableNames.documents)
|
const [document] = await db<TableRow['document']>(tableNames.documents)
|
||||||
.where({
|
.where({
|
||||||
@@ -53,10 +54,12 @@ class DocumentsService extends EventEmitter<DocumentEvents> {
|
|||||||
deletedAt: new Date().toISOString(),
|
deletedAt: new Date().toISOString(),
|
||||||
};
|
};
|
||||||
await db(tableNames.documents).where({ uri, type }).update(toDelete);
|
await db(tableNames.documents).where({ uri, type }).update(toDelete);
|
||||||
this.emit('upsert', { action: 'delete', document: toDelete });
|
const event: DocumentUpsertEvent = { action: 'delete', document: toDelete };
|
||||||
|
this.emit('upsert', event);
|
||||||
|
return event;
|
||||||
};
|
};
|
||||||
|
|
||||||
public upsert = async (document: DocumentUpsert) => {
|
public upsert = async (document: DocumentUpsert): Promise<DocumentUpsertEvent | undefined> => {
|
||||||
const db = await this.#services.get(DatabaseService).getDb();
|
const db = await this.#services.get(DatabaseService).getDb();
|
||||||
const [current] = await db<TableRow['document']>(tableNames.documents)
|
const [current] = await db<TableRow['document']>(tableNames.documents)
|
||||||
.where({
|
.where({
|
||||||
@@ -80,7 +83,9 @@ class DocumentsService extends EventEmitter<DocumentEvents> {
|
|||||||
uri: document.uri,
|
uri: document.uri,
|
||||||
type: document.type,
|
type: document.type,
|
||||||
});
|
});
|
||||||
this.emit('upsert', { action: 'update', document: toInsert });
|
const event: DocumentUpsertEvent = { action: 'update', document: toInsert };
|
||||||
|
this.emit('upsert', event);
|
||||||
|
return event;
|
||||||
} else {
|
} else {
|
||||||
const toInsert: Document = {
|
const toInsert: Document = {
|
||||||
...document,
|
...document,
|
||||||
@@ -88,12 +93,14 @@ class DocumentsService extends EventEmitter<DocumentEvents> {
|
|||||||
updatedAt: new Date().toISOString(),
|
updatedAt: new Date().toISOString(),
|
||||||
};
|
};
|
||||||
await db(tableNames.documents).insert(toInsert);
|
await db(tableNames.documents).insert(toInsert);
|
||||||
this.emit('upsert', { action: 'insert', document: toInsert });
|
const event: DocumentUpsertEvent = { action: 'insert', document: toInsert };
|
||||||
|
this.emit('upsert', event);
|
||||||
|
return event;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public search = async (options: DocumentSearchOptions) => {
|
public search = async (options: DocumentSearchOptions): Promise<DocumentSearchResult> => {
|
||||||
const { uris, types, meta, limit, offset } = options;
|
const { uris, types, meta, limit = 10, offset = 0 } = options;
|
||||||
const db = await this.#services.get(DatabaseService).getDb();
|
const db = await this.#services.get(DatabaseService).getDb();
|
||||||
let query = db<TableRow['document']>(tableNames.documents);
|
let query = db<TableRow['document']>(tableNames.documents);
|
||||||
if (uris) {
|
if (uris) {
|
||||||
@@ -102,18 +109,15 @@ class DocumentsService extends EventEmitter<DocumentEvents> {
|
|||||||
if (types) {
|
if (types) {
|
||||||
query = query.whereIn('type', types);
|
query = query.whereIn('type', types);
|
||||||
}
|
}
|
||||||
if (limit) {
|
|
||||||
query = query.limit(limit);
|
|
||||||
}
|
|
||||||
if (meta) {
|
if (meta) {
|
||||||
query = query.where((builder) => {
|
query = query.where((builder) => {
|
||||||
buildMetaCondition(builder, meta);
|
buildMetaCondition(builder, meta);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (offset) {
|
query = query.limit(limit + 1).offset(offset);
|
||||||
query = query.offset(offset);
|
const documents = await query;
|
||||||
}
|
const more = documents.length > limit;
|
||||||
return query;
|
return { documents: documents.slice(0, limit), more };
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import type { Services } from '@morten-olsen/fluxcurrent-core/utils/services.ts'
|
|||||||
import { parseDSL } from '@morten-olsen/fluxcurrent-core/services/documents/documents.dsl.ts';
|
import { parseDSL } from '@morten-olsen/fluxcurrent-core/services/documents/documents.dsl.ts';
|
||||||
import { DocumentsService } from '@morten-olsen/fluxcurrent-core/services/documents/documents.ts';
|
import { DocumentsService } from '@morten-olsen/fluxcurrent-core/services/documents/documents.ts';
|
||||||
import {
|
import {
|
||||||
documentSchema,
|
documentSearchResultSchema,
|
||||||
type DocumentUpsertEvent,
|
type DocumentUpsertEvent,
|
||||||
} from '@morten-olsen/fluxcurrent-core/services/documents/documents.schemas.ts';
|
} from '@morten-olsen/fluxcurrent-core/services/documents/documents.schemas.ts';
|
||||||
import { filterDocument } from '@morten-olsen/fluxcurrent-core/services/documents/documents.filter.ts';
|
import { filterDocument } from '@morten-olsen/fluxcurrent-core/services/documents/documents.filter.ts';
|
||||||
@@ -18,7 +18,7 @@ const searchEndpoint: FastifyPluginAsyncZod<{ services: Services }> = async (fas
|
|||||||
query: z.string().optional(),
|
query: z.string().optional(),
|
||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: z.array(documentSchema),
|
200: documentSearchResultSchema,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
handler: async (req, res) => {
|
handler: async (req, res) => {
|
||||||
@@ -42,7 +42,7 @@ const searchEndpoint: FastifyPluginAsyncZod<{ services: Services }> = async (fas
|
|||||||
const documentsService = services.get(DocumentsService);
|
const documentsService = services.get(DocumentsService);
|
||||||
res.sse({ event: 'init' });
|
res.sse({ event: 'init' });
|
||||||
const documents = await documentsService.search(query);
|
const documents = await documentsService.search(query);
|
||||||
for (const document of documents) {
|
for (const document of documents.documents) {
|
||||||
res.sse({ event: 'upsert', data: JSON.stringify(document) });
|
res.sse({ event: 'upsert', data: JSON.stringify(document) });
|
||||||
}
|
}
|
||||||
const listener = (event: DocumentUpsertEvent) => {
|
const listener = (event: DocumentUpsertEvent) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user