Skip to content

Commit

Permalink
Return null if there is no data in DynamoDB
Browse files Browse the repository at this point in the history
  • Loading branch information
krzysztofzuraw committed Jan 17, 2025
1 parent e67ddcf commit af4d5f6
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 16 deletions.
14 changes: 10 additions & 4 deletions apps/segment/src/lib/__tests__/in-memory-apl-repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ export class InMemoryAPLRepository implements APLRepository {

async getEntry(args: {
saleorApiUrl: string;
}): Promise<Result<AuthData, InstanceType<typeof BaseError>>> {
}): Promise<Result<AuthData | null, InstanceType<typeof BaseError>>> {
if (this.entries[args.saleorApiUrl]) {
return ok(this.entries[args.saleorApiUrl]);
}

return err(new BaseError("Error geting entry"));
return ok(null);
}

async setEntry(args: {
Expand All @@ -35,7 +35,13 @@ export class InMemoryAPLRepository implements APLRepository {
return err(new BaseError("Error deleting entry"));
}

async getAllEntries(): Promise<Result<AuthData[], InstanceType<typeof BaseError>>> {
return ok(Object.values(this.entries));
async getAllEntries(): Promise<Result<AuthData[] | null, InstanceType<typeof BaseError>>> {
const values = Object.values(this.entries);

if (values.length === 0) {
return ok(null);
}

return ok(values);
}
}
17 changes: 13 additions & 4 deletions apps/segment/src/lib/dyanmodb-apl.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,17 @@ describe("DynamoAPL", () => {
expect(result).toBeUndefined();
});

it("should throw an error if getting auth data fails", async () => {
const repository = new InMemoryAPLRepository();
const apl = new DynamoAPL({ repository });

vi.spyOn(repository, "getEntry").mockReturnValue(
Promise.resolve(err(new BaseError("Error getting data"))),
);

await expect(apl.get("saleorApiUrl")).rejects.toThrowError(DynamoAPL.GetAuthDataError);
});

it("should set auth data", async () => {
const repository = new InMemoryAPLRepository();
const apl = new DynamoAPL({ repository });
Expand Down Expand Up @@ -136,17 +147,15 @@ describe("DynamoAPL", () => {
expect(result).toStrictEqual([mockedAuthData, secondEntry]);
});

it("should return empty array if getting all auth data fails", async () => {
it("should throw an error if getting all auth data fails", async () => {
const repository = new InMemoryAPLRepository();
const apl = new DynamoAPL({ repository });

vi.spyOn(repository, "getAllEntries").mockResolvedValue(
err(new BaseError("Error getting data")),
);

const result = await apl.getAll();

expect(result).toStrictEqual([]);
await expect(apl.getAll()).rejects.toThrowError(DynamoAPL.GetAllAuthDataError);
});

it("should return ready:true when APL related env variables are set", async () => {
Expand Down
16 changes: 16 additions & 0 deletions apps/segment/src/lib/dynamodb-apl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ import { BaseError } from "@/errors";
import { APLRepository } from "@/modules/db/types";

export class DynamoAPL implements APL {
static GetAuthDataError = BaseError.subclass("GetAuthDataError");
static SetAuthDataError = BaseError.subclass("SetAuthDataError");
static DeleteAuthDataError = BaseError.subclass("DeleteAuthDataError");
static GetAllAuthDataError = BaseError.subclass("GetAllAuthDataError");
static MissingEnvVariablesError = BaseError.subclass("MissingEnvVariablesError");

private tracer = getOtelTracer();
Expand All @@ -21,6 +23,13 @@ export class DynamoAPL implements APL {
});

if (getEntryResult.isErr()) {
span.end();
throw new DynamoAPL.GetAuthDataError("Failed to get APL entry", {
cause: getEntryResult.error,
});
}

if (!getEntryResult.value) {
span.end();
return undefined;
}
Expand Down Expand Up @@ -71,6 +80,13 @@ export class DynamoAPL implements APL {
const getAllEntriesResult = await this.deps.repository.getAllEntries();

if (getAllEntriesResult.isErr()) {
span.end();
throw new DynamoAPL.GetAllAuthDataError("Failed to get all APL entries", {
cause: getAllEntriesResult.error,
});
}

if (!getAllEntriesResult.value) {
span.end();
return [];
}
Expand Down
30 changes: 28 additions & 2 deletions apps/segment/src/modules/db/segment-apl-repository.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ describe("SegmentAPLRepository", () => {
});
});

it("should fail to get AuthData entry from DynamoDB if it does not exist", async () => {
mockDocumentClient.on(GetCommand, {}).resolvesOnce({});
it("should handle errors when getting AuthData from DynamoDB", async () => {
mockDocumentClient.on(GetCommand, {}).rejectsOnce("Exception");

const repository = new SegmentAPLRepository({ segmentAPLEntity });

Expand All @@ -77,6 +77,18 @@ describe("SegmentAPLRepository", () => {
expect(result._unsafeUnwrapErr()).toBeInstanceOf(SegmentAPLRepository.ReadEntityError);
});

it("should return null if AuthData entry does not exist in DynamoDB", async () => {
mockDocumentClient.on(GetCommand, {}).resolvesOnce({});

const repository = new SegmentAPLRepository({ segmentAPLEntity });

const result = await repository.getEntry({ saleorApiUrl: "saleorApiUrl" });

expect(result.isOk()).toBe(true);

expect(result._unsafeUnwrap()).toBe(null);
});

it("should successfully set AuthData entry in DynamoDB", async () => {
mockDocumentClient.on(PutCommand, {}).resolvesOnce({});

Expand Down Expand Up @@ -181,6 +193,20 @@ describe("SegmentAPLRepository", () => {
]);
});

it("should return null if there are no AuthData entries in DynamoDB", async () => {
mockDocumentClient.on(ScanCommand, {}).resolvesOnce({
Items: [],
});

const repository = new SegmentAPLRepository({ segmentAPLEntity });

const result = await repository.getAllEntries();

expect(result.isOk()).toBe(true);

expect(result._unsafeUnwrap()).toBe(null);
});

it("should handle error when getting all AuthData entries from DynamoDB", async () => {
mockDocumentClient.on(ScanCommand, {}).rejectsOnce("Exception");

Expand Down
12 changes: 8 additions & 4 deletions apps/segment/src/modules/db/segment-apl-repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export class SegmentAPLRepository implements APLRepository {
if (!getEntryResult.value.Item) {
this.logger.warn("APL entry not found", { args });

return err(new SegmentAPLRepository.ReadEntityError("APL entry not found"));
return ok(null);
}

return ok(this.segmentAPLMapper.dynamoDBEntityToAuthData(getEntryResult.value.Item));
Expand Down Expand Up @@ -128,8 +128,12 @@ export class SegmentAPLRepository implements APLRepository {
return err(scanEntriesResult.error);
}

return ok(
scanEntriesResult.value.Items?.map(this.segmentAPLMapper.dynamoDBEntityToAuthData) ?? [],
);
const possibleItems = scanEntriesResult.value.Items ?? [];

if (possibleItems.length > 0) {
return ok(possibleItems.map(this.segmentAPLMapper.dynamoDBEntityToAuthData));
}

return ok(null);
}
}
4 changes: 2 additions & 2 deletions apps/segment/src/modules/db/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ import { BaseError } from "@/errors";
export interface APLRepository {
getEntry(args: {
saleorApiUrl: string;
}): Promise<Result<AuthData, InstanceType<typeof BaseError>>>;
}): Promise<Result<AuthData | null, InstanceType<typeof BaseError>>>;
setEntry(args: { authData: AuthData }): Promise<Result<void, InstanceType<typeof BaseError>>>;
deleteEntry(args: {
saleorApiUrl: string;
}): Promise<Result<void, InstanceType<typeof BaseError>>>;
getAllEntries(): Promise<Result<AuthData[], InstanceType<typeof BaseError>>>;
getAllEntries(): Promise<Result<AuthData[] | null, InstanceType<typeof BaseError>>>;
}

0 comments on commit af4d5f6

Please sign in to comment.