Skip to content

Commit

Permalink
POC implementation of findNearest
Browse files Browse the repository at this point in the history
  • Loading branch information
MarkDuckworth committed Sep 25, 2024
1 parent ff0475c commit d64b354
Show file tree
Hide file tree
Showing 49 changed files with 4,441 additions and 1,940 deletions.
38 changes: 36 additions & 2 deletions common/api-review/firestore-lite.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,9 @@ export function getCount<AppModelType, DbModelType extends DocumentData>(query:
export function getDoc<AppModelType, DbModelType extends DocumentData>(reference: DocumentReference<AppModelType, DbModelType>): Promise<DocumentSnapshot<AppModelType, DbModelType>>;

// @public
export function getDocs<AppModelType, DbModelType extends DocumentData>(query: VectorQuery<AppModelType, DbModelType>): Promise<VectorQuerySnapshot<AppModelType, DbModelType>>;

// @public (undocumented)
export function getDocs<AppModelType, DbModelType extends DocumentData>(query: Query<AppModelType, DbModelType>): Promise<QuerySnapshot<AppModelType, DbModelType>>;

// @public
Expand Down Expand Up @@ -320,7 +323,7 @@ export class QueryEndAtConstraint extends QueryConstraint {
}

// @public
export function queryEqual<AppModelType, DbModelType extends DocumentData>(left: Query<AppModelType, DbModelType>, right: Query<AppModelType, DbModelType>): boolean;
export function queryEqual<AppModelType, DbModelType extends DocumentData>(left: Query<AppModelType, DbModelType> | VectorQuery<AppModelType, DbModelType>, right: Query<AppModelType, DbModelType> | VectorQuery<AppModelType, DbModelType>): boolean;

// @public
export class QueryFieldFilterConstraint extends QueryConstraint {
Expand Down Expand Up @@ -390,7 +393,7 @@ export interface Settings {
}

// @public
export function snapshotEqual<AppModelType, DbModelType extends DocumentData>(left: DocumentSnapshot<AppModelType, DbModelType> | QuerySnapshot<AppModelType, DbModelType>, right: DocumentSnapshot<AppModelType, DbModelType> | QuerySnapshot<AppModelType, DbModelType>): boolean;
export function snapshotEqual<AppModelType, DbModelType extends DocumentData>(left: DocumentSnapshot<AppModelType, DbModelType> | QuerySnapshot<AppModelType, DbModelType> | VectorQuerySnapshot<AppModelType, DbModelType>, right: DocumentSnapshot<AppModelType, DbModelType> | QuerySnapshot<AppModelType, DbModelType> | VectorQuerySnapshot<AppModelType, DbModelType>): boolean;

// @public
export function startAfter<AppModelType, DbModelType extends DocumentData>(snapshot: DocumentSnapshot<AppModelType, DbModelType>): QueryStartAtConstraint;
Expand Down Expand Up @@ -463,6 +466,37 @@ export function updateDoc<AppModelType, DbModelType extends DocumentData>(refere
// @public
export function vector(values?: number[]): VectorValue;

// @public (undocumented)
export class VectorQuery<AppModelType = DocumentData, DbModelType extends DocumentData = DocumentData> {
protected constructor();
get query(): Query<AppModelType, DbModelType>;
}

// @public (undocumented)
export interface VectorQueryOptions {
// (undocumented)
distanceMeasure: 'EUCLIDEAN' | 'COSINE' | 'DOT_PRODUCT';
// (undocumented)
distanceResultField?: string | FieldPath;
// (undocumented)
distanceThreshold?: number;
// (undocumented)
limit: number;
// (undocumented)
queryVector: VectorValue | number[];
// (undocumented)
vectorField: string | FieldPath;
}

// @public (undocumented)
export class VectorQuerySnapshot<AppModelType = DocumentData, DbModelType extends DocumentData = DocumentData> {
get docs(): Array<QueryDocumentSnapshot<AppModelType, DbModelType>>;
get empty(): boolean;
forEach(callback: (result: QueryDocumentSnapshot<AppModelType, DbModelType>) => void, thisArg?: unknown): void;
readonly query: VectorQuery<AppModelType, DbModelType>;
get size(): number;
}

// @public
export class VectorValue {
/* Excluded from this release type: __constructor */
Expand Down
40 changes: 39 additions & 1 deletion common/api-review/firestore.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,9 @@ export abstract class FieldValue {
abstract isEqual(other: FieldValue): boolean;
}

// @public (undocumented)
export function findNearest<AppModelType, DbModelType extends DocumentData>(query: Query<AppModelType, DbModelType>, options: VectorQueryOptions): VectorQuery<AppModelType, DbModelType>;

// @public
export class Firestore {
get app(): FirebaseApp;
Expand Down Expand Up @@ -299,6 +302,9 @@ export function getDocsFromCache<AppModelType, DbModelType extends DocumentData>
// @public
export function getDocsFromServer<AppModelType, DbModelType extends DocumentData>(query: Query<AppModelType, DbModelType>): Promise<QuerySnapshot<AppModelType, DbModelType>>;

// @public
export function getDocsFromServer<AppModelType, DbModelType extends DocumentData>(vectorQuery: VectorQuery<AppModelType, DbModelType>): Promise<VectorQuerySnapshot<AppModelType, DbModelType>>;

// @public
export function getFirestore(): Firestore;

Expand Down Expand Up @@ -578,7 +584,7 @@ export class QueryEndAtConstraint extends QueryConstraint {
}

// @public
export function queryEqual<AppModelType, DbModelType extends DocumentData>(left: Query<AppModelType, DbModelType>, right: Query<AppModelType, DbModelType>): boolean;
export function queryEqual<AppModelType, DbModelType extends DocumentData>(left: Query<AppModelType, DbModelType> | VectorQuery<AppModelType, DbModelType>, right: Query<AppModelType, DbModelType> | VectorQuery<AppModelType, DbModelType>): boolean;

// @public
export class QueryFieldFilterConstraint extends QueryConstraint {
Expand Down Expand Up @@ -748,6 +754,38 @@ export function updateDoc<AppModelType, DbModelType extends DocumentData>(refere
// @public
export function vector(values?: number[]): VectorValue;

// @public (undocumented)
export class VectorQuery<AppModelType = DocumentData, DbModelType extends DocumentData = DocumentData> {
protected constructor();
get query(): Query<AppModelType, DbModelType>;
}

// @public (undocumented)
export interface VectorQueryOptions {
// (undocumented)
distanceMeasure: 'EUCLIDEAN' | 'COSINE' | 'DOT_PRODUCT';
// (undocumented)
distanceResultField?: string | FieldPath;
// (undocumented)
distanceThreshold?: number;
// (undocumented)
limit: number;
// (undocumented)
queryVector: VectorValue | number[];
// (undocumented)
vectorField: string | FieldPath;
}

// @public
export class VectorQuerySnapshot<AppModelType = DocumentData, DbModelType extends DocumentData = DocumentData> {
get docs(): Array<QueryDocumentSnapshot<AppModelType, DbModelType>>;
get empty(): boolean;
forEach(callback: (result: QueryDocumentSnapshot<AppModelType, DbModelType>) => void, thisArg?: unknown): void;
readonly metadata: SnapshotMetadata;
readonly query: VectorQuery<AppModelType, DbModelType>;
get size(): number;
}

// @public
export class VectorValue {
/* Excluded from this release type: __constructor */
Expand Down
3 changes: 3 additions & 0 deletions packages/firestore/lite/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,9 @@ export {
} from '../src/lite-api/snapshot';

export { VectorValue } from '../src/lite-api/vector_value';
export { VectorQuery } from '../src/lite-api/vector_query';
export { VectorQuerySnapshot } from '../src/lite-api/vector_query_snapshot';
export { VectorQueryOptions } from '../src/lite-api/vector_query_options';

export { WriteBatch, writeBatch } from '../src/lite-api/write_batch';

Expand Down
1 change: 1 addition & 0 deletions packages/firestore/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@
"chai-exclude": "2.1.0",
"json-stable-stringify": "1.1.1",
"protobufjs": "7.2.6",
"protobufjs-cli": "^1.1.3",
"rollup": "2.79.1",
"rollup-plugin-copy": "3.5.0",
"rollup-plugin-copy-assets": "2.0.3",
Expand Down
7 changes: 6 additions & 1 deletion packages/firestore/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,12 @@ export {
vector
} from './api/field_value_impl';

export { VectorValue } from './lite-api/vector_value';
export { VectorValue } from './api/vector_value';
export { VectorQuery } from './api/vector_query';
export { VectorQuerySnapshot } from './api/vector_query_snapshot';
export { VectorQueryOptions } from './api/vector_query_options';

export { findNearest } from './api/find_nearest';

export { LogLevelString as LogLevel, setLogLevel } from './util/log';

Expand Down
18 changes: 18 additions & 0 deletions packages/firestore/src/api/find_nearest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* @license
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

export { findNearest } from '../lite-api/find_nearest';
103 changes: 93 additions & 10 deletions packages/firestore/src/api/reference_impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import {
NextFn,
PartialObserver
} from '../api/observer';
import { QueryDocumentSnapshot } from '../api/snapshot';
import { VectorQuerySnapshot } from '../api/vector_query_snapshot';
import { ListenerDataSource } from '../core/event_manager';
import {
firestoreClientAddSnapshotsInSyncListener,
Expand All @@ -32,6 +34,7 @@ import {
firestoreClientGetDocumentsViaSnapshotListener,
firestoreClientGetDocumentViaSnapshotListener,
firestoreClientListen,
firestoreClientRunVectorQuery,
firestoreClientWrite
} from '../core/firestore_client';
import { newQueryForPath, Query as InternalQuery } from '../core/query';
Expand Down Expand Up @@ -59,6 +62,7 @@ import {
parseUpdateVarargs
} from '../lite-api/user_data_reader';
import { AbstractUserDataWriter } from '../lite-api/user_data_writer';
import { VectorQuery } from '../lite-api/vector_query';
import { DeleteMutation, Mutation, Precondition } from '../model/mutation';
import { debugAssert } from '../util/assert';
import { ByteString } from '../util/byte_string';
Expand Down Expand Up @@ -270,17 +274,96 @@ export function getDocsFromServer<
DbModelType extends DocumentData
>(
query: Query<AppModelType, DbModelType>
): Promise<QuerySnapshot<AppModelType, DbModelType>> {
query = cast<Query<AppModelType, DbModelType>>(query, Query);
const firestore = cast(query.firestore, Firestore);
const client = ensureFirestoreConfigured(firestore);
const userDataWriter = new ExpUserDataWriter(firestore);
): Promise<QuerySnapshot<AppModelType, DbModelType>>;

return firestoreClientGetDocumentsViaSnapshotListener(client, query._query, {
source: 'server'
}).then(
snapshot => new QuerySnapshot(firestore, userDataWriter, query, snapshot)
);
/**
* Executes the query and returns the results as a `QuerySnapshot` from the
* server. Returns an error if the network is not available.
*
* @returns A `Promise` that will be resolved with the results of the query.
*/
export function getDocsFromServer<
AppModelType,
DbModelType extends DocumentData
>(
vectorQuery: VectorQuery<AppModelType, DbModelType>
): Promise<VectorQuerySnapshot<AppModelType, DbModelType>>;

/**
* Executes the query and returns the results as a `QuerySnapshot` from the
* server. Returns an error if the network is not available.
*
* @returns A `Promise` that will be resolved with the results of the query.
*/
export function getDocsFromServer<
AppModelType,
DbModelType extends DocumentData
>(
queryOrVectorQuery:
| Query<AppModelType, DbModelType>
| VectorQuery<AppModelType, DbModelType>
): Promise<
| QuerySnapshot<AppModelType, DbModelType>
| VectorQuerySnapshot<AppModelType, DbModelType>
> {
// If the query is a Query instance
if (
'type' in queryOrVectorQuery &&
(queryOrVectorQuery.type! === 'query' ||
queryOrVectorQuery.type! === 'collection')
) {
const query = cast<Query<AppModelType, DbModelType>>(
queryOrVectorQuery,
Query
);

const firestore = cast(query.firestore, Firestore);
const client = ensureFirestoreConfigured(firestore);
const userDataWriter = new ExpUserDataWriter(firestore);

return firestoreClientGetDocumentsViaSnapshotListener(
client,
query._query,
{
source: 'server'
}
).then(
snapshot => new QuerySnapshot(firestore, userDataWriter, query, snapshot)
);
} else {
// the query is a VectorQuery instance
const vectorQuery: VectorQuery<AppModelType, DbModelType> = cast<
VectorQuery<AppModelType, DbModelType>
>(queryOrVectorQuery, VectorQuery);

const firestore = cast(vectorQuery.query.firestore, Firestore);
const client = ensureFirestoreConfigured(firestore);
const userDataWriter = new ExpUserDataWriter(firestore);

// Run the aggregation and convert the results
return firestoreClientRunVectorQuery(client, vectorQuery._vectorQuery).then(
result => {
const docs = result.map(
doc =>
new QueryDocumentSnapshot<AppModelType, DbModelType>(
firestore,
userDataWriter,
doc.key,
doc,
new SnapshotMetadata(false, false),
vectorQuery.query.converter
)
);

return new VectorQuerySnapshot<AppModelType, DbModelType>(
firestore,
userDataWriter,
vectorQuery,
docs
);
}
);
}
}

/**
Expand Down
6 changes: 4 additions & 2 deletions packages/firestore/src/api/snapshot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,12 @@ import {
} from '../lite-api/reference';
import {
DocumentSnapshot as LiteDocumentSnapshot,
fieldPathFromArgument,
FirestoreDataConverter as LiteFirestoreDataConverter
} from '../lite-api/snapshot';
import { UntypedFirestoreDataConverter } from '../lite-api/user_data_reader';
import {
fieldPathFromArgument,
UntypedFirestoreDataConverter
} from '../lite-api/user_data_reader';
import { AbstractUserDataWriter } from '../lite-api/user_data_writer';
import { Document } from '../model/document';
import { DocumentKey } from '../model/document_key';
Expand Down
18 changes: 18 additions & 0 deletions packages/firestore/src/api/vector_query.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* @license
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

export { VectorQuery } from '../lite-api/vector_query';
18 changes: 18 additions & 0 deletions packages/firestore/src/api/vector_query_options.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* @license
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

export { VectorQueryOptions } from '../lite-api/vector_query_options';
Loading

0 comments on commit d64b354

Please sign in to comment.