Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #1 by adding bulk API supports #4

Merged
merged 1 commit into from
Mar 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 49 additions & 1 deletion data_mapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,16 @@ import {
Operator,
SimpleExpression,
} from "./mod.ts";
import { CountResponse } from "./types.ts";
import {
AndConditions,
BulkDeleteResponse,
BulkGetResponse,
CountResponse,
DataMapperExpressionCountArgs,
DataMapperExpressionQueryArgs,
DataMapperFindFirstExpressionQueryArgs,
DataMapperIdQueryArgs,
DataMapperIdsQueryArgs,
DataMapperInitArgs,
DataMapperSaveArgs,
Definition,
Expand Down Expand Up @@ -92,6 +95,29 @@ export class DataMapper<Def extends Definition> {
});
}

async findAllByIds(
args: DataMapperIdsQueryArgs | string[],
): Promise<BulkGetResponse<Def>> {
let datastore = this.#defaultDatastore;
let ids: string[] | undefined = undefined;
if (Array.isArray(args)) {
ids = args;
} else {
ids = args.ids;
datastore = args.datastore ?? this.#defaultDatastore;
}
if (!datastore) {
throw new ConfigurationError(this.#datastoreMissingError);
}
const [client, logger] = [this.#client, this.#logger];
return await func.findAllByIds<Def>({
client,
datastore,
logger,
ids,
});
}

async findFirstBy(
args:
| DataMapperFindFirstExpressionQueryArgs<Def>
Expand Down Expand Up @@ -270,6 +296,28 @@ export class DataMapper<Def extends Definition> {
});
}

async deleteAllByIds(
args: DataMapperIdsQueryArgs | string[],
): Promise<BulkDeleteResponse> {
let datastore = this.#defaultDatastore;
let ids: string[] | undefined = undefined;
if (Array.isArray(args)) {
ids = args;
} else {
ids = args.ids;
datastore = args.datastore ?? this.#defaultDatastore;
}
if (!datastore) {
throw new ConfigurationError(this.#datastoreMissingError);
}
return await func.deleteAllByIds({
client: this.#client,
datastore,
ids,
logger: this.#logger,
});
}

#datastoreMissingError = "`datastore` needs to be passed";
}

Expand Down
57 changes: 57 additions & 0 deletions functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@ import {
} from "./dependencies/deno_slack_api_typed_method_types.ts";
import { DatastoreError } from "./errors.ts";
import {
BulkDeleteResponse,
BulkGetResponse,
CountResponse,
Definition,
DeleteResponse,
FindFirstRawExpressionQueryArgs,
GetResponse,
IdQueryArgs,
IdsQueryArgs,
PutResponse,
QueryResponse,
RawExpressionQueryArgs,
Expand Down Expand Up @@ -83,6 +86,33 @@ export async function findById<Def extends Definition>({
return result as GetResponse<Def>;
}

export async function findAllByIds<Def extends Definition>({
client,
datastore,
ids,
logger,
}: IdsQueryArgs): Promise<BulkGetResponse<Def>> {
const _logger = logger ?? defaultLogger;
if (_logger.level === log.LogLevels.DEBUG) {
_logger.debug(
`${logName} Finding records (datastore: ${datastore}, IDs: ${ids})`,
);
}
const result = await client.apps.datastore.bulkGet({ datastore, ids });
if (_logger.level === log.LogLevels.DEBUG) {
const response = JSON.stringify(result);
_logger.debug(
`${logName} Found: (datastore: ${datastore}, response: ${response})`,
);
}
if (result.error) {
const error =
`Failed to fetch rows (datastore: ${datastore}, error ${result.error})`;
throw new DatastoreError(error, result);
}
return result as BulkGetResponse<Def>;
}

export async function findFirstBy<Def extends Definition>({
client,
datastore,
Expand Down Expand Up @@ -281,3 +311,30 @@ export async function deleteById({
}
return result;
}

export async function deleteAllByIds({
client,
datastore,
ids,
logger,
}: IdsQueryArgs): Promise<BulkDeleteResponse> {
const _logger = logger ?? defaultLogger;
if (_logger.level === log.LogLevels.DEBUG) {
_logger.debug(
`${logName} Deleting records (datastore: ${datastore}, IDs: ${ids})`,
);
}
const result = await client.apps.datastore.bulkDelete({ datastore, ids });
if (_logger.level === log.LogLevels.DEBUG) {
const jsonData = JSON.stringify(result);
_logger.debug(
`${logName} Deletion result: (datastore: ${datastore}, response: ${jsonData})`,
);
}
if (result.error) {
const error =
`${logName} Failed to delete rows: (datastore: ${datastore}, error: ${result.error})`;
throw new DatastoreError(error, result);
}
return result;
}
60 changes: 59 additions & 1 deletion functions_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import { assertExists } from "./dependencies/testing_asserts.ts";
import { SlackAPI } from "./dependencies/deno_slack_api.ts";
import { save } from "./mod.ts";
import { DefineDatastore, Schema } from "./dependencies/deno_slack_sdk.ts";
import { findAllBy } from "./functions.ts";
import { countBy, findAllBy } from "./functions.ts";
import { findAllByIds } from "./functions.ts";

mf.install();

Expand Down Expand Up @@ -45,6 +46,39 @@ mf.mock("POST@/api/apps.datastore.query", () => {
},
);
});
mf.mock("POST@/api/apps.datastore.bulkGet", () => {
return new Response(
JSON.stringify({
"ok": true,
"datastore": "suveys",
"items": [
{
"id": "123",
"title": "Off-site event ideas",
"questions": [
"Can you share a fun idea for our off-site event in December?",
],
"closed": false,
},
],
}),
{
status: 200,
},
);
});
mf.mock("POST@/api/apps.datastore.count", () => {
return new Response(
JSON.stringify({
"ok": true,
"datastore": "suveys",
"count": 123,
}),
{
status: 200,
},
);
});

export const Surveys = DefineDatastore(
{
Expand Down Expand Up @@ -106,3 +140,27 @@ Deno.test("Run a query", async () => {
});
assertExists(result.items);
});

Deno.test("Run a bulk get request", async () => {
const client = SlackAPI("valid-token");
const result = await findAllByIds<typeof Surveys.definition>({
client,
datastore: "suveys",
ids: ["1", "2", "3"],
});
assertExists(result.items);
});

Deno.test("Run a count query", async () => {
const client = SlackAPI("valid-token");
const result = await countBy<typeof Surveys.definition>({
client,
datastore: "suveys",
expression: {
expression: "#id = :id",
attributes: { "#id": "id" },
values: { ":id": "123" },
},
});
assertExists(result.count);
});
10 changes: 10 additions & 0 deletions test-app/functions/survey_demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,11 @@ export default SlackFunction(def, async ({ client }) => {
});
console.log(countResult);

const findByIdsResult = await mapper.findAllByIds({
ids: ["1", "2", "3"],
});
console.log(findByIdsResult);

const deletion1 = await mapper.deleteById({ id: "1" });
console.log(`deletion 1: ${JSON.stringify(deletion1, null, 2)}`);
if (deletion1.error) {
Expand All @@ -208,6 +213,11 @@ export default SlackFunction(def, async ({ client }) => {
return { error: `Failed to delete a record - ${deletion2.error}` };
}

const deleteAllByIdsResult = await mapper.deleteAllByIds({
ids: ["1", "2", "3"],
});
console.log(deleteAllByIdsResult);

const alreadyInserted = (await mapper.findById({ id: "100" })).item;
if (!alreadyInserted) {
for (let i = 0; i < 100; i += 1) {
Expand Down
20 changes: 20 additions & 0 deletions types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import * as log from "./dependencies/logger.ts";
import {
DatastoreBulkDeleteResponse,
DatastoreBulkGetResponse,
DatastoreDeleteResponse,
DatastoreGetResponse,
DatastorePutResponse,
Expand Down Expand Up @@ -172,6 +174,13 @@ export interface IdQueryArgs {
logger?: log.Logger;
}

export interface IdsQueryArgs {
client: SlackAPIClient;
datastore: string;
ids: string[];
logger?: log.Logger;
}

export type RawExpressionCountArgs = {
client: SlackAPIClient;
datastore: string;
Expand Down Expand Up @@ -201,6 +210,10 @@ export type GetResponse<Def extends Definition> =
& Omit<DatastoreGetResponse<DatastoreSchema>, "item">
& { item: SavedAttributes<Def> };

export type BulkGetResponse<Def extends Definition> =
& Omit<DatastoreBulkGetResponse<DatastoreSchema>, "items">
& { items: SavedAttributes<Def> };

export type QueryResponse<Def extends Definition> =
& Omit<DatastoreQueryResponse<DatastoreSchema>, "items">
& { items: SavedAttributes<Def>[] };
Expand All @@ -209,6 +222,8 @@ export type CountResponse = DatastoreCountResponse<DatastoreSchema>;

export type DeleteResponse = DatastoreDeleteResponse<DatastoreSchema>;

export type BulkDeleteResponse = DatastoreBulkDeleteResponse<DatastoreSchema>;

// -----------------------
// DataMapper's types
// -----------------------
Expand All @@ -230,6 +245,11 @@ export interface DataMapperIdQueryArgs {
datastore?: string;
}

export interface DataMapperIdsQueryArgs {
ids: string[];
datastore?: string;
}

export type PaginationArgs = CursorPaginationArgs & {
autoPagination?: boolean; // default: true
};
Expand Down
Loading