Skip to content

Commit

Permalink
Merge pull request #296 from tigrisdata/main
Browse files Browse the repository at this point in the history
Beta Release
  • Loading branch information
ovaistariq authored Apr 10, 2023
2 parents 52ded45 + 3eb3b88 commit 5f6f1b3
Show file tree
Hide file tree
Showing 22 changed files with 249 additions and 31 deletions.
2 changes: 1 addition & 1 deletion api/proto
Submodule proto updated from 48734e to 1c4a37
8 changes: 5 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@
"ts-jest": "^28.0.8",
"ts-mockito": "^2.6.1",
"tsutils": "^3.21.0",
"typescript": "^4.7.2",
"uuid": "^8.3.2"
},
"dependencies": {
Expand All @@ -113,7 +114,6 @@
"google-protobuf": "^3.21.0",
"json-bigint": "github:sidorares/json-bigint",
"reflect-metadata": "^0.1.13",
"typescript": "^4.7.2",
"app-root-path": "^3.1.0"
}
}
7 changes: 5 additions & 2 deletions src/__tests__/fixtures/json-schema/movies.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"type": "string"
},
"title": {
"type": "string"
"type": "string",
"searchIndex": true
},
"year": {
"type": "integer",
Expand All @@ -33,7 +34,9 @@
"type": "array",
"items": {
"type": "string"
}
},
"searchIndex": true,
"facet": true
},
"productionHouse": {
"type": "object",
Expand Down
7 changes: 7 additions & 0 deletions src/__tests__/fixtures/json-schema/search/matrices.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@
}
},
"searchIndex": true
},
"relevance": {
"type": "array",
"dimensions": 4,
"format": "vector",
"searchIndex": true,
"sort": false
}
}
}
6 changes: 6 additions & 0 deletions src/__tests__/fixtures/json-schema/vacationRentals.json
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,12 @@
"type": "string",
"format": "uuid",
"default": "uuid()"
},
"relevance": {
"type": "array",
"dimensions": 3,
"format": "vector",
"default": [1.0, 1.0, 1.0]
}
},
"primary_key": ["id"]
Expand Down
6 changes: 6 additions & 0 deletions src/__tests__/fixtures/schema/movies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { TigrisCollection } from "../../../decorators/tigris-collection";
import { PrimaryKey } from "../../../decorators/tigris-primary-key";
import { TigrisCollectionType, TigrisDataTypes, TigrisSchema } from "../../../types";
import { Field } from "../../../decorators/tigris-field";
import { SearchField } from "../../../decorators/tigris-search-field";

/******************************************************************************
* `Movie` class demonstrates a Tigris collection schema generated using
Expand Down Expand Up @@ -34,6 +35,7 @@ export class Movie {
@PrimaryKey(TigrisDataTypes.STRING, { order: 1 })
movieId: string;

@SearchField(TigrisDataTypes.STRING)
@Field(TigrisDataTypes.STRING)
title: string;

Expand All @@ -43,6 +45,7 @@ export class Movie {
@Field(TigrisDataTypes.ARRAY, { elements: Actor })
actors: Array<Actor>;

@SearchField(TigrisDataTypes.ARRAY, { elements: TigrisDataTypes.STRING, facet: true })
@Field(TigrisDataTypes.ARRAY, { elements: TigrisDataTypes.STRING })
genres: Array<string>;

Expand All @@ -68,6 +71,7 @@ export const MovieSchema: TigrisSchema<Movie> = {
},
title: {
type: TigrisDataTypes.STRING,
searchIndex: true,
},
year: {
type: TigrisDataTypes.INT32,
Expand All @@ -92,6 +96,8 @@ export const MovieSchema: TigrisSchema<Movie> = {
items: {
type: TigrisDataTypes.STRING,
},
searchIndex: true,
facet: true,
},
productionHouse: {
type: {
Expand Down
12 changes: 12 additions & 0 deletions src/__tests__/fixtures/schema/search/matrices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ export class Matrix {

@SearchField({ elements: Cell, depth: 3 })
cells: Cell[][][];

@SearchField({ dimensions: 4, sort: false })
relevance: Array<number>;
}
/********************************** END **************************************/

Expand Down Expand Up @@ -69,4 +72,13 @@ export const MatrixSchema: TigrisIndexSchema<Matrix> = {
},
},
},
relevance: {
type: TigrisDataTypes.ARRAY,
searchIndex: true,
sort: false,
dimensions: 4,
items: {
type: TigrisDataTypes.NUMBER,
},
},
};
11 changes: 11 additions & 0 deletions src/__tests__/fixtures/schema/vacationRentals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ export class VacationRentals {

@Field(TigrisDataTypes.UUID, { default: GeneratedField.UUID })
referralId: string;

@Field({ dimensions: 3, default: [1.0, 1.0, 1.0] })
relevance: number[];
}
/********************************** END **************************************/

Expand Down Expand Up @@ -200,4 +203,12 @@ export const VacationsRentalSchema: TigrisSchema<VacationRentals> = {
type: TigrisDataTypes.UUID,
default: GeneratedField.UUID,
},
relevance: {
type: TigrisDataTypes.ARRAY,
dimensions: 3,
default: [1.0, 1.0, 1.0],
items: {
type: TigrisDataTypes.NUMBER,
},
},
};
19 changes: 19 additions & 0 deletions src/__tests__/search/schema.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ import { Utility } from "../../utility";
import { readJSONFileAsObj } from "../utils";
import { DecoratedSchemaProcessor, IndexSchema } from "../../schema/decorated-schema-processor";
import { MATRICES_INDEX_NAME, Matrix, MatrixSchema } from "../fixtures/schema/search/matrices";
import { TigrisCollection } from "../../decorators/tigris-collection";
import { Field } from "../../decorators/tigris-field";
import { TigrisDataTypes } from "../../types";
import { IncorrectVectorDefError } from "../../error";

type SchemaTestCase<T extends TigrisIndexType> = {
schemaClass: T;
Expand Down Expand Up @@ -41,3 +45,18 @@ describe.each(schemas)("Schema conversion for: '$name'", (tc) => {
);
});
});

test("throws error when Vector fields have incorrect type", () => {
let caught;

try {
@TigrisCollection("test_studio")
class Studio {
@Field({ dimensions: 3, elements: TigrisDataTypes.STRING })
actors: Array<string>;
}
} catch (e) {
caught = e;
}
expect(caught).toBeInstanceOf(IncorrectVectorDefError);
});
4 changes: 4 additions & 0 deletions src/__tests__/search/search.types.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,15 +173,19 @@ describe("SearchResponse parsing", () => {
const parsed: TextMatchInfo = TextMatchInfo.from(input);
expect(parsed.fields).toStrictEqual([]);
expect(parsed.score).toBe("");
expect(parsed.vectorDistance).toBeUndefined();
});
it("generates match field from input", () => {
const input: ProtoMatch = new ProtoMatch();
input.setScore("456");
input.addFields(new ProtoMatchField().setName("person"));
input.addFields(new ProtoMatchField().setName("user"));
input.setVectorDistance(0.24);

const parsed: TextMatchInfo = TextMatchInfo.from(input);
expect(parsed.fields).toEqual(expect.arrayContaining(["person", "user"]));
expect(parsed.score).toBe("456");
expect(parsed.vectorDistance).toBe(0.24);
});
});
});
19 changes: 17 additions & 2 deletions src/__tests__/tigris.schema.spec.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { CollectionSchema, DecoratedSchemaProcessor } from "../schema/decorated-schema-processor";
import { TigrisCollectionType, TigrisSchema } from "../types";
import { TigrisCollectionType, TigrisDataTypes, TigrisSchema } from "../types";
import { User, USERS_COLLECTION_NAME, UserSchema } from "./fixtures/schema/users";
import {
RENTALS_COLLECTION_NAME,
VacationRentals,
VacationsRentalSchema,
} from "./fixtures/schema/vacationRentals";
import { Field } from "../decorators/tigris-field";
import { IncompleteArrayTypeDefError } from "../error";
import { IncompleteArrayTypeDefError, IncorrectVectorDefError } from "../error";
import { TigrisCollection } from "../decorators/tigris-collection";
import { Utility } from "../utility";
import { Order, ORDERS_COLLECTION_NAME, OrderSchema } from "./fixtures/schema/orders";
Expand Down Expand Up @@ -91,3 +91,18 @@ test("throws error when Arrays are not properly decorated", () => {
}
expect(caught).toBeInstanceOf(IncompleteArrayTypeDefError);
});

test("throws error when Vector fields have incorrect type", () => {
let caught;

try {
@TigrisCollection("test_studio")
class Studio {
@Field({ dimensions: 3, elements: TigrisDataTypes.STRING })
actors: Array<string>;
}
} catch (e) {
caught = e;
}
expect(caught).toBeInstanceOf(IncorrectVectorDefError);
});
13 changes: 13 additions & 0 deletions src/__tests__/tigris.utility.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ describe("utility tests", () => {
expect(request.getSearchFieldsList()).toEqual([]);
expect(request.getFilter()).toBe("");
expect(request.getFacet()).toBe("");
expect(request.getVector()).toBe("");
expect(request.getSort()).toBe("");
expect(request.getIncludeFieldsList()).toEqual([]);
expect(request.getExcludeFieldsList()).toEqual([]);
Expand Down Expand Up @@ -133,6 +134,18 @@ describe("utility tests", () => {
);
});

it("sets vector query", () => {
const query: SearchQuery<Student> = {
vectorQuery: {
"address.street": [0.4, -0.15, 0.9],
},
};
Utility.protoSearchRequestFromQuery(query, request);
expect(request.getVector()).toEqual(
Utility.stringToUint8Array('{"address.street":[0.4,-0.15,0.9]}')
);
});

it("sets sort order", () => {
const query: SearchQuery<Student> = {
sort: { field: "balance", order: "$desc" },
Expand Down
16 changes: 12 additions & 4 deletions src/decorators/tigris-field.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import "reflect-metadata";
import { TigrisDataTypes, CollectionFieldOptions } from "../types";
import { CollectionFieldOptions, TigrisDataTypes } from "../types";
import { EmbeddedFieldOptions } from "./options/embedded-field-options";
import {
CannotInferFieldTypeError,
IncompleteArrayTypeDefError,
IncorrectVectorDefError,
ReflectionNotEnabled,
} from "../error";
import { getDecoratorMetaStorage } from "../globals";
Expand Down Expand Up @@ -94,9 +95,16 @@ export function Field(
throw new ReflectionNotEnabled(target, propertyName);
}

// if propertyType is Array, subtype is required
if (propertyType === TigrisDataTypes.ARRAY && embedOptions?.elements === undefined) {
throw new IncompleteArrayTypeDefError(target, propertyName);
// if propertyType is Array, type of contents is required unless its a vector
if (propertyType === TigrisDataTypes.ARRAY) {
if (fieldOptions?.dimensions !== undefined) {
if (embedOptions?.elements && embedOptions?.elements !== TigrisDataTypes.NUMBER) {
throw new IncorrectVectorDefError(target, propertyName);
}
embedOptions = { elements: TigrisDataTypes.NUMBER };
} else if (embedOptions?.elements === undefined) {
throw new IncompleteArrayTypeDefError(target, propertyName);
}
}

// if propertyType is still undefined, it probably is a typed object
Expand Down
14 changes: 11 additions & 3 deletions src/decorators/tigris-search-field.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Log } from "../utils/logger";
import {
CannotInferFieldTypeError,
IncompleteArrayTypeDefError,
IncorrectVectorDefError,
ReflectionNotEnabled,
} from "../error";
import { getDecoratorMetaStorage } from "../globals";
Expand Down Expand Up @@ -60,9 +61,16 @@ export function SearchField(
throw new ReflectionNotEnabled(target, propertyName);
}

// if propertyType is Array, subtype is required
if (propertyType === TigrisDataTypes.ARRAY && embedOptions?.elements === undefined) {
throw new IncompleteArrayTypeDefError(target, propertyName);
// if propertyType is Array, type of contents is required unless its a vector
if (propertyType === TigrisDataTypes.ARRAY) {
if (fieldOptions?.dimensions !== undefined) {
if (embedOptions?.elements && embedOptions?.elements !== TigrisDataTypes.NUMBER) {
throw new IncorrectVectorDefError(target, propertyName);
}
embedOptions = { elements: TigrisDataTypes.NUMBER };
} else if (embedOptions?.elements === undefined) {
throw new IncompleteArrayTypeDefError(target, propertyName);
}
}

// if propertyType is still undefined, it probably is a typed object
Expand Down
10 changes: 10 additions & 0 deletions src/error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,16 @@ export class IncompleteArrayTypeDefError extends TigrisError {
}
}

export class IncorrectVectorDefError extends TigrisError {
constructor(object: Object, propertyName: string) {
super(`'${propertyName}' in '${object.constructor.name}' defines "dimensions" field option identifying it as a Vector data type.
The primitive data type for Vector can only be a 'number[]'`);
}
override get name(): string {
return "IncorrectVectorDefError";
}
}

export class IncompletePrimaryKeyDefError extends TigrisError {
constructor(object: Object, propertyName: string) {
super(`Missing "PrimaryKeyOptions" for '${object.constructor.name}#${propertyName}'`);
Expand Down
Loading

0 comments on commit 5f6f1b3

Please sign in to comment.