Skip to content

Commit 6326ae7

Browse files
committed
Organize file paths and tests
1 parent 64e9e26 commit 6326ae7

File tree

21 files changed

+222
-101
lines changed

21 files changed

+222
-101
lines changed

.github/workflows/release.yaml

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
name: Release
2+
3+
on:
4+
release:
5+
types:
6+
- published
7+
8+
jobs:
9+
release:
10+
name: Release
11+
runs-on: ubuntu-latest
12+
steps:
13+
- name: Checkout Repo
14+
uses: actions/checkout@v3
15+
16+
- name: Set env
17+
run: echo "VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
18+
19+
- name: Setup Node
20+
uses: actions/setup-node@v2
21+
with:
22+
node-version: 18
23+
24+
- name: Set package version
25+
run: echo $(jq --arg v "${{ env.VERSION }}" '(.version) = $v' package.json) > package.json
26+
27+
- name: Install bun
28+
run: npm install -g bun
29+
30+
- name: Install dependencies
31+
run: bun install
32+
33+
- name: Build
34+
run: bun run build
35+
36+
- name: Add npm token
37+
run: echo "//registry.npmjs.org/:_authToken=${{secrets.NPM_TOKEN}}" > .npmrc
38+
39+
- name: Publish release candidate
40+
if: "github.event.release.prerelease"
41+
run: npm publish --access public --tag=canary --no-git-checks
42+
43+
- name: Publish
44+
if: "!github.event.release.prerelease"
45+
run: npm publish --access public --no-git-checks

index.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {
44
RequesterConfig,
55
UpstashRequest,
66
UpstashResponse,
7-
} from "./src/http";
7+
} from "@http/index";
88
import * as core from "./src/vector";
99

1010
export type { Requester, UpstashRequest, UpstashResponse };
@@ -75,14 +75,18 @@ export class Index extends core.Index {
7575
configOrRequester.url.endsWith(" ") ||
7676
/\r|\n/.test(configOrRequester.url)
7777
) {
78-
console.warn("The vector url contains whitespace or newline, which can cause errors!");
78+
console.warn(
79+
"The vector url contains whitespace or newline, which can cause errors!"
80+
);
7981
}
8082
if (
8183
configOrRequester.token.startsWith(" ") ||
8284
configOrRequester.token.endsWith(" ") ||
8385
/\r|\n/.test(configOrRequester.token)
8486
) {
85-
console.warn("The vector token contains whitespace or newline, which can cause errors!");
87+
console.warn(
88+
"The vector token contains whitespace or newline, which can cause errors!"
89+
);
8690
}
8791

8892
const client = new HttpClient({
@@ -108,11 +112,15 @@ export class Index extends core.Index {
108112
static fromEnv(config?: Omit<VectorConfig, "url" | "token">): Index {
109113
const url = process?.env.UPSTASH_VECTOR_REST_URL;
110114
if (!url) {
111-
throw new Error("Unable to find environment variable: `UPSTASH_VECTOR_REST_URL`");
115+
throw new Error(
116+
"Unable to find environment variable: `UPSTASH_VECTOR_REST_URL`"
117+
);
112118
}
113119
const token = process?.env.UPSTASH_VECTOR_REST_TOKEN;
114120
if (!token) {
115-
throw new Error("Unable to find environment variable: `UPSTASH_VECTOR_REST_TOKEN`");
121+
throw new Error(
122+
"Unable to find environment variable: `UPSTASH_VECTOR_REST_TOKEN`"
123+
);
116124
}
117125
return new Index({ ...config, url, token });
118126
}

src/commands/client/delete/index.test.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { afterAll, describe, expect, test } from "bun:test";
2-
import { newHttpClient, randomID, resetIndexes } from "../../../utils/test-utils";
3-
import { UpsertCommand } from "../upsert";
4-
import { DeleteCommand } from "./";
2+
import { DeleteCommand, UpsertCommand } from "@commands/index";
3+
import { newHttpClient, randomID, resetIndexes } from "@utils/test-utils";
54

65
const client = newHttpClient();
76

src/commands/client/delete/index.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Command } from "../../index";
1+
import { Command } from "@commands/command";
22

33
/**
44
* Payload Type Definition for DeleteCommand
@@ -26,8 +26,6 @@ type Payload = {
2626
* const deleteCommand = new DeleteCommand({ ids: deletionIds });
2727
* // Use deleteCommand to execute the deletion operation
2828
* ```
29-
*
30-
* The DeleteCommand takes a payload containing the IDs of the records to be deleted and performs the deletion operation when executed.
3129
*/
3230
export class DeleteCommand extends Command<string> {
3331
constructor(payload: Payload) {

src/commands/client/fetch/index.test.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { afterAll, describe, expect, test } from "bun:test";
2-
import { FetchCommand } from ".";
3-
import { newHttpClient, randomFloat, randomID, resetIndexes } from "../../../utils/test-utils";
4-
import { UpsertCommand } from "../upsert";
2+
import { FetchCommand, UpsertCommand } from "@commands/index";
3+
import { newHttpClient, randomFloat, randomID, resetIndexes } from "@utils/test-utils";
54

65
const client = newHttpClient();
76

src/commands/client/fetch/index.ts

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,46 @@
1-
import { Command } from "../../index";
1+
import { Command } from "@commands/command";
22
import { Vector } from "../types";
33

4+
/**
5+
* Type definition for FetchCommand payload
6+
*
7+
* Properties:
8+
* - ids: An array of numbers or strings, representing the unique identifiers of the records to be fetched.
9+
* - includeMetadata (optional): A boolean flag indicating whether to include metadata in the response.
10+
* - includeVectors (optional): A boolean flag indicating whether to include vector data in the response.
11+
*
12+
* The Payload type is used in the FetchCommand to specify the data required to fetch specific records.
13+
* The optional flags allow for more detailed responses depending on the requirements.
14+
*/
415
type Payload = {
516
ids: number[] | string[];
617
includeMetadata?: boolean;
718
includeVectors?: boolean;
819
};
920

21+
/**
22+
* Generic response type for FetchCommand
23+
*
24+
* This type represents the possible return type of a FetchCommand. It can be either a Vector
25+
* containing metadata or null, depending on whether the fetch operation was successful or not.
26+
*/
1027
type FetchReturnResponse<TMetadata> = Vector<TMetadata> | null;
1128

12-
export class FetchCommand<TMetadata> extends Command<FetchReturnResponse<TMetadata>[]> {
29+
/**
30+
* FetchCommand Class
31+
*
32+
* Extends the generic Command class to implement a fetch operation.
33+
*
34+
* Example:
35+
* ```
36+
* const fetchPayload = { ids: [1, 2, 3], includeMetadata: true };
37+
* const fetchCommand = new FetchCommand(fetchPayload);
38+
* // Use fetchCommand to execute the fetch operation
39+
* ```
40+
*/
41+
export class FetchCommand<TMetadata> extends Command<
42+
FetchReturnResponse<TMetadata>[]
43+
> {
1344
constructor(payload: Payload) {
1445
super({ ...payload }, "fetch");
1546
}

src/commands/client/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,5 @@ export * from "./delete";
22
export * from "./query";
33
export * from "./upsert";
44
export * from "./fetch";
5+
export * from "./range";
6+
export * from "./reset";

src/commands/client/query/index.test.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import { afterAll, describe, expect, test } from "bun:test";
2+
import { QueryCommand, UpsertCommand } from "@commands/index";
3+
import { newHttpClient, resetIndexes } from "@utils/test-utils";
24
import { sleep } from "bun";
3-
import { newHttpClient, resetIndexes } from "../../../utils/test-utils";
4-
import { UpsertCommand } from "../upsert";
5-
import { QueryCommand } from "./index";
65

76
const client = newHttpClient();
87

src/commands/client/query/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Command } from "../../index";
1+
import { Command } from "@commands/command";
22

33
/**
44
* Payload Type Definition

src/commands/client/range/index.test.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { afterAll, describe, expect, test } from "bun:test";
2-
import { RangeCommand } from ".";
3-
import { newHttpClient, randomFloat, randomID, resetIndexes } from "../../../utils/test-utils";
4-
import { UpsertCommand } from "../upsert";
2+
import { RangeCommand, UpsertCommand } from "@commands/index";
3+
import { newHttpClient, randomFloat, randomID, resetIndexes } from "@utils/test-utils";
54

65
const client = newHttpClient();
76

src/commands/client/range/index.ts

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,56 @@
1-
import { Command } from "../../index";
1+
import { Command } from "@commands/command";
22
import { Vector } from "../types";
33

4+
/**
5+
* Type definition for RangeCommand payload
6+
*
7+
* This type specifies the structure of the payload used in the RangeCommand.
8+
*
9+
* Properties:
10+
* - cursor: A number indicating the starting point for the range query.
11+
* - limit: A number specifying the maximum number of records to be returned.
12+
* - includeVectors (optional): A boolean flag indicating whether to include vector data in the response.
13+
* - includeMetadata (optional): A boolean flag indicating whether to include metadata in the response.
14+
*
15+
* This payload type is used for range queries, where a set of records is retrieved based on the specified cursor
16+
* and limit. The optional inclusion of vectors and metadata allows for flexible and detailed data retrieval.
17+
*/
418
type Payload = {
519
cursor: number;
620
limit: number;
721
includeVectors?: boolean;
822
includeMetadata?: boolean;
923
};
1024

25+
/**
26+
* Type definition for the response returned by RangeCommand
27+
*
28+
* This type outlines the structure of the response from a RangeCommand.
29+
*
30+
* Properties:
31+
* - nextCursor: A string that indicates the cursor to be used for the next range query, facilitating pagination.
32+
* - vectors: An array of Vector objects, each containing TMetadata, representing the data retrieved in the range query.
33+
*
34+
* The RangeReturnResponse type is crucial for operations that involve retrieving a range of records,
35+
* providing both the data (in the form of vectors) and the means to continue fetching subsequent ranges (via nextCursor).
36+
*/
1137
type RangeReturnResponse<TMetadata> = {
1238
nextCursor: string;
1339
vectors: Vector<TMetadata>[];
1440
};
1541

16-
export class RangeCommand<TResult> extends Command<RangeReturnResponse<TResult>> {
42+
/**
43+
* RangeCommand Class
44+
* Example:
45+
* ```
46+
* const rangePayload = { cursor: 0, limit: 10, includeVectors: true };
47+
* const rangeCommand = new RangeCommand(rangePayload);
48+
* // Use rangeCommand to execute the range query and retrieve data
49+
* ```
50+
*/
51+
export class RangeCommand<TResult> extends Command<
52+
RangeReturnResponse<TResult>
53+
> {
1754
constructor(payload: Payload) {
1855
super(payload, "range");
1956
}

src/commands/client/reset/index.test.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import { describe, expect, test } from "bun:test";
2-
import { ResetCommand } from ".";
3-
import { newHttpClient, randomFloat, randomID } from "../../../utils/test-utils";
4-
import { FetchCommand } from "../fetch";
5-
import { UpsertCommand } from "../upsert";
2+
import { FetchCommand, ResetCommand, UpsertCommand } from "@commands/index";
3+
import { newHttpClient, randomFloat, randomID } from "@utils/test-utils";
64

75
const client = newHttpClient();
86

src/commands/client/reset/index.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
1-
import { Command } from "../../index";
1+
import { Command } from "@commands/command";
22

3+
/**
4+
* Example:
5+
* ```
6+
* const resetCommand = new ResetCommand();
7+
* // Use resetCommand to execute the reset operation
8+
* ```
9+
*/
310
export class ResetCommand extends Command<string> {
411
constructor() {
512
super([], "reset");

src/commands/client/upsert/index.test.ts

Lines changed: 6 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
11
import { afterAll, describe, expect, test } from "bun:test";
2-
import { UpsertCommand } from ".";
3-
import { newHttpClient, resetIndexes } from "../../../utils/test-utils";
2+
import { UpsertCommand } from "@commands/index";
3+
import { newHttpClient, resetIndexes } from "@utils/test-utils";
44

55
const client = newHttpClient();
66

77
describe("UPSERT", () => {
88
afterAll(async () => await resetIndexes());
99

1010
test("should add record successfully", async () => {
11-
const res = await new UpsertCommand({ id: 1, vector: [0.1, 0.2] }).exec(client);
11+
const res = await new UpsertCommand({ id: 1, vector: [0.1, 0.2] }).exec(
12+
client
13+
);
1214
expect(res).toEqual("Success");
1315
});
16+
1417
// biome-ignore lint/nursery/useAwait: required to test bad payloads
1518
test("should return an error when vector is missing", async () => {
1619
const throwable = async () => {
@@ -20,24 +23,6 @@ describe("UPSERT", () => {
2023
expect(throwable).toThrow();
2124
});
2225

23-
// biome-ignore lint/nursery/useAwait: required to test bad payloads
24-
test("should return an error when id is missing", async () => {
25-
const throwable = async () => {
26-
//@ts-ignore
27-
await new UpsertCommand({ vector: [0.1, 0.2] }).exec(client);
28-
};
29-
expect(throwable).toThrow();
30-
});
31-
32-
// biome-ignore lint/nursery/useAwait: required to test bad payloads
33-
test("should return an error when id is missing", async () => {
34-
const throwable = async () => {
35-
//@ts-ignore
36-
await new UpsertCommand({ vector: [0.1, 0.2] }).exec(client);
37-
};
38-
expect(throwable).toThrow();
39-
});
40-
4126
test("should add data successfully with a metadata", async () => {
4227
//@ts-ignore
4328
const res = await new UpsertCommand({

src/commands/client/upsert/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Command } from "../../index";
1+
import { Command } from "@commands/command";
22

33
/**
44
* Payload Type Definition for UpsertCommand

src/commands/command.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { UpstashError } from "@error/index";
2+
import { Requester } from "@http/index";
3+
4+
const ENDPOINTS = ["upsert", "query", "delete", "fetch", "reset", "range"] as const;
5+
6+
export type EndpointVariants = (typeof ENDPOINTS)[number];
7+
/**
8+
* TResult is the raw data returned from upstash, which may need to be transformed or parsed.
9+
*/
10+
export class Command<TResult> {
11+
public readonly payload: Record<string, unknown> | unknown[];
12+
public readonly endpoint: EndpointVariants;
13+
14+
constructor(command: Record<string, unknown> | unknown[], endpoint: EndpointVariants) {
15+
this.payload = command;
16+
this.endpoint = endpoint;
17+
}
18+
19+
/**
20+
* Execute the command using a client.
21+
*/
22+
public async exec(client: Requester): Promise<TResult> {
23+
const { result, error } = await client.request<TResult>({
24+
body: this.payload,
25+
path: [this.endpoint],
26+
});
27+
28+
if (error) {
29+
throw new UpstashError(error);
30+
}
31+
32+
if (typeof result === "undefined") {
33+
throw new Error("Request did not return a result");
34+
}
35+
36+
return result;
37+
}
38+
}

0 commit comments

Comments
 (0)