[CM] Improve CRUD & RPC interfaces (#154150)

This commit is contained in:
Sébastien Loix 2023-04-04 16:20:11 +01:00 committed by GitHub
parent 5b250268e7
commit 56c28af1f5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
43 changed files with 672 additions and 372 deletions

View file

@ -6,13 +6,17 @@
* Side Public License, v 1.
*/
import { schema } from '@kbn/config-schema';
import {
CreateIn,
CreateResult,
DeleteIn,
DeleteResult,
GetIn,
GetResult,
SearchIn,
SearchResult,
UpdateIn,
UpdateResult,
} from '@kbn/content-management-plugin/common';
export const TODO_CONTENT_ID = 'todos';
@ -21,43 +25,18 @@ export interface Todo {
title: string;
completed: boolean;
}
const todoSchema = schema.object({
id: schema.string(),
title: schema.string(),
completed: schema.boolean(),
});
export type TodoCreateIn = CreateIn<'todos', { title: string }>;
export type TodoCreateOut = Todo; // TODO: Is this correct?
export const createInSchema = schema.object({ title: schema.string() });
export const createOutSchema = todoSchema;
export type TodoCreateOut = CreateResult<Todo>;
export type TodoUpdateIn = UpdateIn<'todos', Partial<Omit<Todo, 'id'>>>;
export type TodoUpdateOut = Todo;
export const updateInSchema = schema.object({
title: schema.maybe(schema.string()),
completed: schema.maybe(schema.boolean()),
});
export const updateOutSchema = todoSchema;
export type TodoUpdateOut = UpdateResult<Todo>;
export type TodoDeleteIn = DeleteIn<'todos', { id: string }>;
export type TodoDeleteOut = void;
export type TodoDeleteOut = DeleteResult;
export type TodoGetIn = GetIn<'todos'>;
export type TodoGetOut = Todo;
export const getOutSchema = todoSchema;
export type TodoGetOut = GetResult<Todo>;
export type TodoSearchIn = SearchIn<'todos', { filter?: 'todo' | 'completed' }>;
export interface TodoSearchOut {
hits: Todo[];
}
export const searchInSchema = schema.object({
filter: schema.maybe(
schema.oneOf([schema.literal('todo'), schema.literal('completed')], {
defaultValue: undefined,
})
),
});
export const searchOutSchema = schema.object({
hits: schema.arrayOf(todoSchema),
});
export type TodoSearchOut = SearchResult<Todo>;

View file

@ -39,22 +39,40 @@ export class TodosClient implements CrudClient {
completed: false,
};
this.todos.push(todo);
return todo;
return {
item: todo,
};
}
async delete(input: TodoDeleteIn): Promise<TodoDeleteOut> {
this.todos = this.todos.filter((todo) => todo.id !== input.id);
return { success: true };
}
async get(input: TodoGetIn): Promise<TodoGetOut> {
return this.todos.find((todo) => todo.id === input.id)!;
return {
item: this.todos.find((todo) => todo.id === input.id)!,
};
}
async search(input: TodoSearchIn): Promise<TodoSearchOut> {
const filter = input.query.filter;
if (filter === 'todo') return { hits: this.todos.filter((t) => !t.completed) };
if (filter === 'completed') return { hits: this.todos.filter((t) => t.completed) };
return { hits: [...this.todos] };
const filter = input.options?.filter;
let hits = [...this.todos];
if (filter === 'todo') {
hits = this.todos.filter((t) => !t.completed);
}
if (filter === 'completed') {
hits = this.todos.filter((t) => t.completed);
}
return {
hits,
pagination: {
total: hits.length,
},
};
}
async update(input: TodoUpdateIn): Promise<TodoUpdateOut> {
@ -63,6 +81,10 @@ export class TodosClient implements CrudClient {
if (todoToUpdate) {
Object.assign(todoToUpdate, input.data);
}
return { ...todoToUpdate };
return {
item: {
...todoToUpdate,
},
};
}
}

View file

@ -37,10 +37,11 @@ import {
const useCreateTodoMutation = () => useCreateContentMutation<TodoCreateIn, TodoCreateOut>();
const useDeleteTodoMutation = () => useDeleteContentMutation<TodoDeleteIn, TodoDeleteOut>();
const useUpdateTodoMutation = () => useUpdateContentMutation<TodoUpdateIn, TodoUpdateOut>();
const useSearchTodosQuery = ({ filter }: { filter: TodoSearchIn['query']['filter'] }) =>
const useSearchTodosQuery = ({ options: { filter } = {} }: { options: TodoSearchIn['options'] }) =>
useSearchContentQuery<TodoSearchIn, TodoSearchOut>({
contentTypeId: TODO_CONTENT_ID,
query: { filter },
query: {},
options: { filter },
});
type TodoFilter = 'all' | 'completed' | 'todo';
@ -63,7 +64,7 @@ export const Todos = () => {
const [filterIdSelected, setFilterIdSelected] = React.useState<TodoFilter>('all');
const { data, isError, error, isFetching, isLoading } = useSearchTodosQuery({
filter: filterIdSelected === 'all' ? undefined : filterIdSelected,
options: { filter: filterIdSelected === 'all' ? undefined : filterIdSelected },
});
const createTodoMutation = useCreateTodoMutation();

View file

@ -6,6 +6,7 @@
* Side Public License, v 1.
*/
import type { BulkGetResult } from '@kbn/content-management-plugin/common';
import {
ContentStorage,
StorageContext,
@ -39,7 +40,7 @@ export const registerTodoContentType = ({
});
};
class TodosStorage implements ContentStorage {
class TodosStorage implements ContentStorage<Todo> {
private db: Map<string, Todo> = new Map();
constructor() {
@ -58,11 +59,15 @@ class TodosStorage implements ContentStorage {
}
async get(ctx: StorageContext, id: string): Promise<TodoGetOut> {
return this.db.get(id)!;
return {
item: this.db.get(id)!,
};
}
async bulkGet(ctx: StorageContext, ids: string[]): Promise<TodoGetOut[]> {
return ids.map((id) => this.db.get(id)!);
async bulkGet(ctx: StorageContext, ids: string[]): Promise<BulkGetResult<Todo>> {
return {
hits: ids.map((id) => ({ item: this.db.get(id)! })),
};
}
async create(ctx: StorageContext, data: TodoCreateIn['data']): Promise<TodoCreateOut> {
@ -74,7 +79,9 @@ class TodosStorage implements ContentStorage {
this.db.set(todo.id, todo);
return todo;
return {
item: todo,
};
}
async update(
@ -94,17 +101,36 @@ class TodosStorage implements ContentStorage {
this.db.set(id, updatedContent);
return updatedContent;
return {
item: updatedContent,
};
}
async delete(ctx: StorageContext, id: string): Promise<TodoDeleteOut> {
this.db.delete(id);
return { success: true };
}
async search(ctx: StorageContext, query: TodoSearchIn['query']): Promise<TodoSearchOut> {
const hits = Array.from(this.db.values());
if (query.filter === 'todo') return { hits: hits.filter((t) => !t.completed) };
if (query.filter === 'completed') return { hits: hits.filter((t) => t.completed) };
return { hits };
async search(
ctx: StorageContext,
_: TodoSearchIn['query'],
options: TodoSearchIn['options']
): Promise<TodoSearchOut> {
let hits = Array.from(this.db.values());
if (options?.filter === 'todo') {
hits = hits.filter((t) => !t.completed);
}
if (options?.filter === 'completed') {
hits = hits.filter((t) => t.completed);
}
return {
hits,
pagination: {
total: hits.length,
},
};
}
}

View file

@ -17,7 +17,6 @@
"kbn_references": [
"@kbn/core",
"@kbn/developer-examples-plugin",
"@kbn/config-schema",
"@kbn/content-management-plugin",
"@kbn/core-application-browser",
]