Some checks failed
Build & Test / Analyze (javascript, affine) (push) Failing after 4s
Build & Test / Analyze (typescript, affine) (push) Failing after 3s
Build & Test / Rust test filter (push) Failing after 4s
Build & Test / Check yarn binary (push) Failing after 3s
Build & Test / E2E BlockSuite Test (3) (push) Failing after 3s
Build & Test / Analyze (javascript, blocksuite) (push) Failing after 3s
Build & Test / Analyze (typescript, blocksuite) (push) Failing after 3s
Build & Test / Mobile native build filter (push) Failing after 3s
Build & Test / E2E BlockSuite Test (1) (push) Failing after 4s
Build & Test / E2E BlockSuite Test (2) (push) Failing after 4s
Build & Test / E2E Mobile Test (1) (push) Failing after 3s
Build & Test / Unit Test (1) (push) Has been skipped
Build & Test / Unit Test (2) (push) Has been skipped
Build & Test / Unit Test (3) (push) Has been skipped
Build & Test / Unit Test (4) (push) Has been skipped
Build & Test / Unit Test (5) (push) Has been skipped
Build & Test / Native Unit Test (push) Has been skipped
Build & Test / E2E BlockSuite Test (4) (push) Failing after 3s
Build & Test / E2E BlockSuite Test (5) (push) Failing after 3s
Build & Test / E2E BlockSuite Cross Browser Test (push) Failing after 3s
Build & Test / E2E Mobile Test (2) (push) Failing after 3s
Build & Test / Build AFFiNE native (x86_64-unknown-linux-gnu) (push) Failing after 3s
Build & Test / Build Server native (push) Failing after 3s
Build & Test / Check Git Status (push) Has been skipped
Build & Test / Server Test (0, 4) (push) Has been skipped
Build & Test / Server Test (1, 4) (push) Has been skipped
Build & Test / Server Test (2, 4) (push) Has been skipped
Build & Test / Server Test (3, 4) (push) Has been skipped
Build & Test / Server Test with Elasticsearch (push) Has been skipped
Build & Test / Build @affine/electron renderer (push) Failing after 3s
Build & Test / Copilot test filter (push) Failing after 4s
Build & Test / Lint Rust (push) Has been skipped
Build & Test / Server Test with Embedded Search (push) Has been skipped
Build & Test / Server Test with Manticore Search (push) Has been skipped
Build & Test / Server E2E Test (push) Has been skipped
Build & Test / Cloud Desktop E2E Test (push) Has been skipped
Build & Test / Cloud E2E Test 1/2 (push) Has been skipped
Build & Test / Cloud E2E Test 2/2 (push) Has been skipped
Build & Test / Build Android app (push) Has been skipped
Build & Test / Test Android app (push) Has been skipped
Build & Test / Run native tests (push) Has been skipped
Build & Test / Server Copilot Api Test (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (1, 5) (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (2, 5) (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (3, 5) (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (4, 5) (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (5, 5) (push) Has been skipped
Release / Canary Gate (push) Has been skipped
Build & Test / Build AFFiNE native (aarch64-apple-darwin) (push) Has been cancelled
Build & Test / Lint (push) Has been cancelled
Build & Test / Typecheck (push) Has been cancelled
Build & Test / Build AFFiNE native (x86_64-apple-darwin) (push) Has been cancelled
Build & Test / Desktop Test (ubuntu-latest, linux, x64, x86_64-unknown-linux-gnu, true) (push) Has been cancelled
Build & Test / Desktop Test (windows-latest, windows, x64, x86_64-pc-windows-msvc, true) (push) Has been cancelled
Build & Test / E2E Test (1) (push) Has been cancelled
Build & Test / E2E Test (2) (push) Has been cancelled
Build & Test / E2E Test (3) (push) Has been cancelled
Build & Test / E2E Test (4) (push) Has been cancelled
Build & Test / E2E Test (5) (push) Has been cancelled
Build & Test / Build AFFiNE native (aarch64-pc-windows-msvc) (push) Has been cancelled
Build & Test / Build AFFiNE native (x86_64-pc-windows-msvc) (push) Has been cancelled
Build & Test / Desktop Test (macos-latest, macos, arm64, aarch64-apple-darwin, true) (push) Has been cancelled
Build & Test / Desktop Test (macos-latest, macos, x64, x86_64-apple-darwin, false) (push) Has been cancelled
Build & Test / 3, 2, 1 Launch (push) Has been cancelled
Build & Test / Build iOS app (push) Has been cancelled
Copilot Test Automatically / Setup Test (push) Failing after 1s
Release / Prepare (push) Failing after 2s
Release / Release Cloud (push) Has been skipped
Release / Release Desktop (push) Has been skipped
Release / Release Docker Image (push) Has been skipped
Release / Release Mobile (push) Has been skipped
245 lines
6.3 KiB
TypeScript
245 lines
6.3 KiB
TypeScript
import { AutoReconnectConnection } from '../../connection';
|
|
import type {
|
|
BlobRecord,
|
|
CrawlResult,
|
|
DocClock,
|
|
DocIndexedClock,
|
|
DocRecord,
|
|
ListedBlobRecord,
|
|
} from '../../storage';
|
|
import { type SpaceType, universalId } from '../../utils/universal-id';
|
|
|
|
export interface SqliteNativeDBOptions {
|
|
readonly flavour: string;
|
|
readonly type: SpaceType;
|
|
readonly id: string;
|
|
}
|
|
|
|
export interface NativeIndexField {
|
|
field: string;
|
|
values: string[];
|
|
}
|
|
|
|
export interface NativeIndexQuery {
|
|
kind: 'match' | 'exists' | 'all' | 'boolean' | 'boost';
|
|
field?: string;
|
|
value?: string;
|
|
occur?: 'must' | 'should' | 'must_not';
|
|
clauses?: NativeIndexQuery[];
|
|
boost?: number;
|
|
}
|
|
|
|
export interface NativeIndexSearchOptions {
|
|
limit: number;
|
|
offset: number;
|
|
fields: string[];
|
|
highlights: string[];
|
|
}
|
|
|
|
export interface NativeIndexHit {
|
|
id: string;
|
|
score: number;
|
|
fields: NativeIndexField[];
|
|
highlights: {
|
|
field: string;
|
|
values: { valueIndex: number; spans: { start: number; end: number }[] }[];
|
|
}[];
|
|
}
|
|
|
|
export interface NativeIndexSearchResult {
|
|
total: number;
|
|
hits: NativeIndexHit[];
|
|
}
|
|
|
|
export interface NativeDBApis {
|
|
connect: (id: string) => Promise<void>;
|
|
disconnect: (id: string) => Promise<void>;
|
|
pushUpdate: (id: string, docId: string, update: Uint8Array) => Promise<Date>;
|
|
getDocSnapshot: (id: string, docId: string) => Promise<DocRecord | null>;
|
|
setDocSnapshot: (id: string, snapshot: DocRecord) => Promise<boolean>;
|
|
getDocUpdates: (id: string, docId: string) => Promise<DocRecord[]>;
|
|
markUpdatesMerged: (
|
|
id: string,
|
|
docId: string,
|
|
updates: Date[]
|
|
) => Promise<number>;
|
|
deleteDoc: (id: string, docId: string) => Promise<void>;
|
|
getDocClocks: (id: string, after?: Date | null) => Promise<DocClock[]>;
|
|
getDocClock: (id: string, docId: string) => Promise<DocClock | null>;
|
|
getDocIndexedClock: (
|
|
id: string,
|
|
docId: string
|
|
) => Promise<DocIndexedClock | null>;
|
|
setDocIndexedClock: (
|
|
id: string,
|
|
docId: string,
|
|
indexedClock: Date,
|
|
indexerVersion: number
|
|
) => Promise<void>;
|
|
setDocIndexedClocks: (id: string, clocks: DocIndexedClock[]) => Promise<void>;
|
|
clearDocIndexedClock: (id: string, docId: string) => Promise<void>;
|
|
getBlob: (id: string, key: string) => Promise<BlobRecord | null>;
|
|
setBlob: (id: string, blob: BlobRecord) => Promise<void>;
|
|
deleteBlob: (id: string, key: string, permanently: boolean) => Promise<void>;
|
|
releaseBlobs: (id: string) => Promise<void>;
|
|
listBlobs: (id: string) => Promise<ListedBlobRecord[]>;
|
|
getPeerRemoteClocks: (id: string, peer: string) => Promise<DocClock[]>;
|
|
getPeerRemoteClock: (
|
|
id: string,
|
|
peer: string,
|
|
docId: string
|
|
) => Promise<DocClock | null>;
|
|
setPeerRemoteClock: (
|
|
id: string,
|
|
peer: string,
|
|
docId: string,
|
|
clock: Date
|
|
) => Promise<void>;
|
|
getPeerPulledRemoteClocks: (id: string, peer: string) => Promise<DocClock[]>;
|
|
getPeerPulledRemoteClock: (
|
|
id: string,
|
|
peer: string,
|
|
docId: string
|
|
) => Promise<DocClock | null>;
|
|
setPeerPulledRemoteClock: (
|
|
id: string,
|
|
peer: string,
|
|
docId: string,
|
|
clock: Date
|
|
) => Promise<void>;
|
|
getPeerPushedClocks: (id: string, peer: string) => Promise<DocClock[]>;
|
|
getPeerPushedClock: (
|
|
id: string,
|
|
peer: string,
|
|
docId: string
|
|
) => Promise<DocClock | null>;
|
|
setPeerPushedClock: (
|
|
id: string,
|
|
peer: string,
|
|
docId: string,
|
|
clock: Date
|
|
) => Promise<void>;
|
|
clearClocks: (id: string) => Promise<void>;
|
|
setBlobUploadedAt: (
|
|
id: string,
|
|
peer: string,
|
|
blobId: string,
|
|
uploadedAt: Date | null
|
|
) => Promise<void>;
|
|
getBlobUploadedAt: (
|
|
id: string,
|
|
peer: string,
|
|
blobId: string
|
|
) => Promise<Date | null>;
|
|
crawlDocData: (id: string, docId: string) => Promise<CrawlResult>;
|
|
indexUpsert: (
|
|
id: string,
|
|
table: string,
|
|
document: { id: string; fields: NativeIndexField[] }
|
|
) => Promise<void>;
|
|
indexDelete: (id: string, table: string, docId: string) => Promise<void>;
|
|
indexSearch: (
|
|
id: string,
|
|
table: string,
|
|
query: NativeIndexQuery,
|
|
options: NativeIndexSearchOptions
|
|
) => Promise<NativeIndexSearchResult>;
|
|
indexAggregate: (
|
|
id: string,
|
|
table: string,
|
|
query: NativeIndexQuery,
|
|
field: string,
|
|
limit: number,
|
|
offset: number,
|
|
hits?: NativeIndexSearchOptions
|
|
) => Promise<{
|
|
total: number;
|
|
buckets: {
|
|
key: string;
|
|
count: number;
|
|
score: number;
|
|
hits: NativeIndexHit[];
|
|
}[];
|
|
}>;
|
|
indexDeleteByQuery: (
|
|
id: string,
|
|
table: string,
|
|
query: NativeIndexQuery
|
|
) => Promise<number>;
|
|
indexFlush: (id: string) => Promise<void>;
|
|
indexVersion: () => Promise<number>;
|
|
}
|
|
|
|
type NativeDBApisWrapper = NativeDBApis extends infer APIs
|
|
? {
|
|
[K in keyof APIs]: APIs[K] extends (...args: any[]) => any
|
|
? Parameters<APIs[K]> extends [string, ...infer Rest]
|
|
? (...args: Rest) => ReturnType<APIs[K]>
|
|
: (...args: Parameters<APIs[K]>) => ReturnType<APIs[K]>
|
|
: never;
|
|
}
|
|
: never;
|
|
|
|
let apis: NativeDBApis | null = null;
|
|
|
|
export function bindNativeDBApis(a: NativeDBApis) {
|
|
apis = a;
|
|
}
|
|
|
|
export class NativeDBConnection extends AutoReconnectConnection<void> {
|
|
readonly apis: NativeDBApisWrapper;
|
|
|
|
readonly flavour = this.options.flavour;
|
|
readonly type = this.options.type;
|
|
readonly id = this.options.id;
|
|
|
|
constructor(private readonly options: SqliteNativeDBOptions) {
|
|
super();
|
|
|
|
if (!apis) {
|
|
throw new Error('Not in native context.');
|
|
}
|
|
|
|
this.apis = this.warpApis(apis);
|
|
}
|
|
|
|
override get shareId(): string {
|
|
return `sqlite:${this.flavour}:${this.type}:${this.id}`;
|
|
}
|
|
|
|
warpApis(originalApis: NativeDBApis): NativeDBApisWrapper {
|
|
const id = universalId({
|
|
peer: this.flavour,
|
|
type: this.type,
|
|
id: this.id,
|
|
});
|
|
return new Proxy(
|
|
{},
|
|
{
|
|
get: (_target, key: keyof NativeDBApisWrapper) => {
|
|
const v = originalApis[key];
|
|
|
|
return async (...args: any[]) => {
|
|
return v.call(
|
|
originalApis,
|
|
id,
|
|
// @ts-expect-error I don't know why it complains ts(2556)
|
|
...args
|
|
);
|
|
};
|
|
},
|
|
}
|
|
) as unknown as NativeDBApisWrapper;
|
|
}
|
|
|
|
override async doConnect() {
|
|
await this.apis.connect();
|
|
}
|
|
|
|
override doDisconnect() {
|
|
this.apis.disconnect().catch(err => {
|
|
console.error('NativeDBConnection close failed', err);
|
|
});
|
|
}
|
|
}
|