Skip to content

Commit

Permalink
Organize file paths and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
ogzhanolguncu committed Jan 11, 2024
1 parent 64e9e26 commit 6326ae7
Show file tree
Hide file tree
Showing 21 changed files with 222 additions and 101 deletions.
45 changes: 45 additions & 0 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: Release

on:
release:
types:
- published

jobs:
release:
name: Release
runs-on: ubuntu-latest
steps:
- name: Checkout Repo
uses: actions/checkout@v3

- name: Set env
run: echo "VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV

- name: Setup Node
uses: actions/setup-node@v2
with:
node-version: 18

- name: Set package version
run: echo $(jq --arg v "${{ env.VERSION }}" '(.version) = $v' package.json) > package.json

- name: Install bun
run: npm install -g bun

- name: Install dependencies
run: bun install

- name: Build
run: bun run build

- name: Add npm token
run: echo "//registry.npmjs.org/:_authToken=${{secrets.NPM_TOKEN}}" > .npmrc

- name: Publish release candidate
if: "github.event.release.prerelease"
run: npm publish --access public --tag=canary --no-git-checks

- name: Publish
if: "!github.event.release.prerelease"
run: npm publish --access public --no-git-checks
18 changes: 13 additions & 5 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
RequesterConfig,
UpstashRequest,
UpstashResponse,
} from "./src/http";
} from "@http/index";
import * as core from "./src/vector";

export type { Requester, UpstashRequest, UpstashResponse };
Expand Down Expand Up @@ -75,14 +75,18 @@ export class Index extends core.Index {
configOrRequester.url.endsWith(" ") ||
/\r|\n/.test(configOrRequester.url)
) {
console.warn("The vector url contains whitespace or newline, which can cause errors!");
console.warn(
"The vector url contains whitespace or newline, which can cause errors!"
);
}
if (
configOrRequester.token.startsWith(" ") ||
configOrRequester.token.endsWith(" ") ||
/\r|\n/.test(configOrRequester.token)
) {
console.warn("The vector token contains whitespace or newline, which can cause errors!");
console.warn(
"The vector token contains whitespace or newline, which can cause errors!"
);
}

const client = new HttpClient({
Expand All @@ -108,11 +112,15 @@ export class Index extends core.Index {
static fromEnv(config?: Omit<VectorConfig, "url" | "token">): Index {
const url = process?.env.UPSTASH_VECTOR_REST_URL;
if (!url) {
throw new Error("Unable to find environment variable: `UPSTASH_VECTOR_REST_URL`");
throw new Error(
"Unable to find environment variable: `UPSTASH_VECTOR_REST_URL`"
);
}
const token = process?.env.UPSTASH_VECTOR_REST_TOKEN;
if (!token) {
throw new Error("Unable to find environment variable: `UPSTASH_VECTOR_REST_TOKEN`");
throw new Error(
"Unable to find environment variable: `UPSTASH_VECTOR_REST_TOKEN`"
);
}
return new Index({ ...config, url, token });
}
Expand Down
5 changes: 2 additions & 3 deletions src/commands/client/delete/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { afterAll, describe, expect, test } from "bun:test";
import { newHttpClient, randomID, resetIndexes } from "../../../utils/test-utils";
import { UpsertCommand } from "../upsert";
import { DeleteCommand } from "./";
import { DeleteCommand, UpsertCommand } from "@commands/index";
import { newHttpClient, randomID, resetIndexes } from "@utils/test-utils";

const client = newHttpClient();

Expand Down
4 changes: 1 addition & 3 deletions src/commands/client/delete/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Command } from "../../index";
import { Command } from "@commands/command";

/**
* Payload Type Definition for DeleteCommand
Expand Down Expand Up @@ -26,8 +26,6 @@ type Payload = {
* const deleteCommand = new DeleteCommand({ ids: deletionIds });
* // Use deleteCommand to execute the deletion operation
* ```
*
* The DeleteCommand takes a payload containing the IDs of the records to be deleted and performs the deletion operation when executed.
*/
export class DeleteCommand extends Command<string> {
constructor(payload: Payload) {
Expand Down
5 changes: 2 additions & 3 deletions src/commands/client/fetch/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { afterAll, describe, expect, test } from "bun:test";
import { FetchCommand } from ".";
import { newHttpClient, randomFloat, randomID, resetIndexes } from "../../../utils/test-utils";
import { UpsertCommand } from "../upsert";
import { FetchCommand, UpsertCommand } from "@commands/index";
import { newHttpClient, randomFloat, randomID, resetIndexes } from "@utils/test-utils";

const client = newHttpClient();

Expand Down
35 changes: 33 additions & 2 deletions src/commands/client/fetch/index.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,46 @@
import { Command } from "../../index";
import { Command } from "@commands/command";
import { Vector } from "../types";

/**
* Type definition for FetchCommand payload
*
* Properties:
* - ids: An array of numbers or strings, representing the unique identifiers of the records to be fetched.
* - includeMetadata (optional): A boolean flag indicating whether to include metadata in the response.
* - includeVectors (optional): A boolean flag indicating whether to include vector data in the response.
*
* The Payload type is used in the FetchCommand to specify the data required to fetch specific records.
* The optional flags allow for more detailed responses depending on the requirements.
*/
type Payload = {
ids: number[] | string[];
includeMetadata?: boolean;
includeVectors?: boolean;
};

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

export class FetchCommand<TMetadata> extends Command<FetchReturnResponse<TMetadata>[]> {
/**
* FetchCommand Class
*
* Extends the generic Command class to implement a fetch operation.
*
* Example:
* ```
* const fetchPayload = { ids: [1, 2, 3], includeMetadata: true };
* const fetchCommand = new FetchCommand(fetchPayload);
* // Use fetchCommand to execute the fetch operation
* ```
*/
export class FetchCommand<TMetadata> extends Command<
FetchReturnResponse<TMetadata>[]
> {
constructor(payload: Payload) {
super({ ...payload }, "fetch");
}
Expand Down
2 changes: 2 additions & 0 deletions src/commands/client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ export * from "./delete";
export * from "./query";
export * from "./upsert";
export * from "./fetch";
export * from "./range";
export * from "./reset";
5 changes: 2 additions & 3 deletions src/commands/client/query/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { afterAll, describe, expect, test } from "bun:test";
import { QueryCommand, UpsertCommand } from "@commands/index";
import { newHttpClient, resetIndexes } from "@utils/test-utils";
import { sleep } from "bun";
import { newHttpClient, resetIndexes } from "../../../utils/test-utils";
import { UpsertCommand } from "../upsert";
import { QueryCommand } from "./index";

const client = newHttpClient();

Expand Down
2 changes: 1 addition & 1 deletion src/commands/client/query/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Command } from "../../index";
import { Command } from "@commands/command";

/**
* Payload Type Definition
Expand Down
5 changes: 2 additions & 3 deletions src/commands/client/range/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { afterAll, describe, expect, test } from "bun:test";
import { RangeCommand } from ".";
import { newHttpClient, randomFloat, randomID, resetIndexes } from "../../../utils/test-utils";
import { UpsertCommand } from "../upsert";
import { RangeCommand, UpsertCommand } from "@commands/index";
import { newHttpClient, randomFloat, randomID, resetIndexes } from "@utils/test-utils";

const client = newHttpClient();

Expand Down
41 changes: 39 additions & 2 deletions src/commands/client/range/index.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,56 @@
import { Command } from "../../index";
import { Command } from "@commands/command";
import { Vector } from "../types";

/**
* Type definition for RangeCommand payload
*
* This type specifies the structure of the payload used in the RangeCommand.
*
* Properties:
* - cursor: A number indicating the starting point for the range query.
* - limit: A number specifying the maximum number of records to be returned.
* - includeVectors (optional): A boolean flag indicating whether to include vector data in the response.
* - includeMetadata (optional): A boolean flag indicating whether to include metadata in the response.
*
* This payload type is used for range queries, where a set of records is retrieved based on the specified cursor
* and limit. The optional inclusion of vectors and metadata allows for flexible and detailed data retrieval.
*/
type Payload = {
cursor: number;
limit: number;
includeVectors?: boolean;
includeMetadata?: boolean;
};

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

export class RangeCommand<TResult> extends Command<RangeReturnResponse<TResult>> {
/**
* RangeCommand Class
* Example:
* ```
* const rangePayload = { cursor: 0, limit: 10, includeVectors: true };
* const rangeCommand = new RangeCommand(rangePayload);
* // Use rangeCommand to execute the range query and retrieve data
* ```
*/
export class RangeCommand<TResult> extends Command<
RangeReturnResponse<TResult>
> {
constructor(payload: Payload) {
super(payload, "range");
}
Expand Down
6 changes: 2 additions & 4 deletions src/commands/client/reset/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { describe, expect, test } from "bun:test";
import { ResetCommand } from ".";
import { newHttpClient, randomFloat, randomID } from "../../../utils/test-utils";
import { FetchCommand } from "../fetch";
import { UpsertCommand } from "../upsert";
import { FetchCommand, ResetCommand, UpsertCommand } from "@commands/index";
import { newHttpClient, randomFloat, randomID } from "@utils/test-utils";

const client = newHttpClient();

Expand Down
9 changes: 8 additions & 1 deletion src/commands/client/reset/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import { Command } from "../../index";
import { Command } from "@commands/command";

/**
* Example:
* ```
* const resetCommand = new ResetCommand();
* // Use resetCommand to execute the reset operation
* ```
*/
export class ResetCommand extends Command<string> {
constructor() {
super([], "reset");
Expand Down
27 changes: 6 additions & 21 deletions src/commands/client/upsert/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
import { afterAll, describe, expect, test } from "bun:test";
import { UpsertCommand } from ".";
import { newHttpClient, resetIndexes } from "../../../utils/test-utils";
import { UpsertCommand } from "@commands/index";
import { newHttpClient, resetIndexes } from "@utils/test-utils";

const client = newHttpClient();

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

test("should add record successfully", async () => {
const res = await new UpsertCommand({ id: 1, vector: [0.1, 0.2] }).exec(client);
const res = await new UpsertCommand({ id: 1, vector: [0.1, 0.2] }).exec(
client
);
expect(res).toEqual("Success");
});

// biome-ignore lint/nursery/useAwait: required to test bad payloads
test("should return an error when vector is missing", async () => {
const throwable = async () => {
Expand All @@ -20,24 +23,6 @@ describe("UPSERT", () => {
expect(throwable).toThrow();
});

// biome-ignore lint/nursery/useAwait: required to test bad payloads
test("should return an error when id is missing", async () => {
const throwable = async () => {
//@ts-ignore
await new UpsertCommand({ vector: [0.1, 0.2] }).exec(client);
};
expect(throwable).toThrow();
});

// biome-ignore lint/nursery/useAwait: required to test bad payloads
test("should return an error when id is missing", async () => {
const throwable = async () => {
//@ts-ignore
await new UpsertCommand({ vector: [0.1, 0.2] }).exec(client);
};
expect(throwable).toThrow();
});

test("should add data successfully with a metadata", async () => {
//@ts-ignore
const res = await new UpsertCommand({
Expand Down
2 changes: 1 addition & 1 deletion src/commands/client/upsert/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Command } from "../../index";
import { Command } from "@commands/command";

/**
* Payload Type Definition for UpsertCommand
Expand Down
38 changes: 38 additions & 0 deletions src/commands/command.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { UpstashError } from "@error/index";
import { Requester } from "@http/index";

const ENDPOINTS = ["upsert", "query", "delete", "fetch", "reset", "range"] as const;

export type EndpointVariants = (typeof ENDPOINTS)[number];
/**
* TResult is the raw data returned from upstash, which may need to be transformed or parsed.
*/
export class Command<TResult> {
public readonly payload: Record<string, unknown> | unknown[];
public readonly endpoint: EndpointVariants;

constructor(command: Record<string, unknown> | unknown[], endpoint: EndpointVariants) {
this.payload = command;
this.endpoint = endpoint;
}

/**
* Execute the command using a client.
*/
public async exec(client: Requester): Promise<TResult> {
const { result, error } = await client.request<TResult>({
body: this.payload,
path: [this.endpoint],
});

if (error) {
throw new UpstashError(error);
}

if (typeof result === "undefined") {
throw new Error("Request did not return a result");
}

return result;
}
}
Loading

0 comments on commit 6326ae7

Please sign in to comment.