mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-13 21:05:19 +00:00
@@ -3,11 +3,13 @@ import { CloudAwarenessStorage } from './awareness';
|
||||
import { CloudBlobStorage } from './blob';
|
||||
import { CloudDocStorage } from './doc';
|
||||
import { StaticCloudDocStorage } from './doc-static';
|
||||
import { CloudIndexerStorage } from './indexer';
|
||||
|
||||
export * from './awareness';
|
||||
export * from './blob';
|
||||
export * from './doc';
|
||||
export * from './doc-static';
|
||||
export * from './indexer';
|
||||
export * from './socket';
|
||||
|
||||
export const cloudStorages = [
|
||||
@@ -15,4 +17,5 @@ export const cloudStorages = [
|
||||
StaticCloudDocStorage,
|
||||
CloudBlobStorage,
|
||||
CloudAwarenessStorage,
|
||||
CloudIndexerStorage,
|
||||
] satisfies StorageConstructor[];
|
||||
|
||||
142
packages/common/nbstore/src/impls/cloud/indexer.ts
Normal file
142
packages/common/nbstore/src/impls/cloud/indexer.ts
Normal file
@@ -0,0 +1,142 @@
|
||||
import {
|
||||
type AggregateInput,
|
||||
indexerAggregateQuery,
|
||||
indexerSearchQuery,
|
||||
type SearchInput,
|
||||
} from '@affine/graphql';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
import {
|
||||
type AggregateOptions,
|
||||
type AggregateResult,
|
||||
type IndexerDocument,
|
||||
type IndexerSchema,
|
||||
IndexerStorageBase,
|
||||
type Query,
|
||||
type SearchOptions,
|
||||
type SearchResult,
|
||||
} from '../../storage/indexer';
|
||||
import { HttpConnection } from './http';
|
||||
|
||||
interface CloudIndexerStorageOptions {
|
||||
serverBaseUrl: string;
|
||||
id: string;
|
||||
}
|
||||
|
||||
export class CloudIndexerStorage extends IndexerStorageBase {
|
||||
static readonly identifier = 'CloudIndexerStorage';
|
||||
readonly isReadonly = true;
|
||||
readonly connection = new HttpConnection(this.options.serverBaseUrl);
|
||||
|
||||
constructor(private readonly options: CloudIndexerStorageOptions) {
|
||||
super();
|
||||
}
|
||||
|
||||
override async search<
|
||||
T extends keyof IndexerSchema,
|
||||
const O extends SearchOptions<T>,
|
||||
>(table: T, query: Query<T>, options?: O): Promise<SearchResult<T, O>> {
|
||||
const res = await this.connection.gql({
|
||||
query: indexerSearchQuery,
|
||||
variables: {
|
||||
id: this.options.id,
|
||||
input: {
|
||||
table,
|
||||
query,
|
||||
options,
|
||||
} as SearchInput,
|
||||
},
|
||||
});
|
||||
const result = res.workspace.search as unknown as SearchResult<T, O>;
|
||||
return result;
|
||||
}
|
||||
|
||||
override search$<
|
||||
T extends keyof IndexerSchema,
|
||||
const O extends SearchOptions<T>,
|
||||
>(table: T, query: Query<T>, options?: O): Observable<SearchResult<T, O>> {
|
||||
return new Observable(observer => {
|
||||
this.search(table, query, options)
|
||||
.then(data => {
|
||||
observer.next(data);
|
||||
observer.complete();
|
||||
})
|
||||
.catch(error => {
|
||||
observer.error(error);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
override async aggregate<
|
||||
T extends keyof IndexerSchema,
|
||||
const O extends AggregateOptions<T>,
|
||||
>(
|
||||
table: T,
|
||||
query: Query<T>,
|
||||
field: keyof IndexerSchema[T],
|
||||
options?: O
|
||||
): Promise<AggregateResult<T, O>> {
|
||||
const res = await this.connection.gql({
|
||||
query: indexerAggregateQuery,
|
||||
variables: {
|
||||
id: this.options.id,
|
||||
input: { table, query, field, options } as AggregateInput,
|
||||
},
|
||||
});
|
||||
const result = res.workspace.aggregate as unknown as AggregateResult<T, O>;
|
||||
return result;
|
||||
}
|
||||
|
||||
override aggregate$<
|
||||
T extends keyof IndexerSchema,
|
||||
const O extends AggregateOptions<T>,
|
||||
>(
|
||||
table: T,
|
||||
query: Query<T>,
|
||||
field: keyof IndexerSchema[T],
|
||||
options?: O
|
||||
): Observable<AggregateResult<T, O>> {
|
||||
return new Observable(observer => {
|
||||
this.aggregate(table, query, field, options)
|
||||
.then(data => {
|
||||
observer.next(data);
|
||||
observer.complete();
|
||||
})
|
||||
.catch(error => {
|
||||
observer.error(error);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
override deleteByQuery<T extends keyof IndexerSchema>(
|
||||
_table: T,
|
||||
_query: Query<T>
|
||||
): Promise<void> {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
override insert<T extends keyof IndexerSchema>(
|
||||
_table: T,
|
||||
_document: IndexerDocument<T>
|
||||
): Promise<void> {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
override delete<T extends keyof IndexerSchema>(
|
||||
_table: T,
|
||||
_id: string
|
||||
): Promise<void> {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
override update<T extends keyof IndexerSchema>(
|
||||
_table: T,
|
||||
_document: IndexerDocument<T>
|
||||
): Promise<void> {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
override refresh<T extends keyof IndexerSchema>(_table: T): Promise<void> {
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import type { FlagInfo } from './types';
|
||||
// const isNotStableBuild = BUILD_CONFIG.appBuildType !== 'stable';
|
||||
const isDesktopEnvironment = BUILD_CONFIG.isElectron;
|
||||
const isCanaryBuild = BUILD_CONFIG.appBuildType === 'canary';
|
||||
const isBetaBuild = BUILD_CONFIG.appBuildType === 'beta';
|
||||
const isMobile = BUILD_CONFIG.isMobileEdition;
|
||||
|
||||
export const AFFINE_FLAGS = {
|
||||
@@ -317,6 +318,13 @@ export const AFFINE_FLAGS = {
|
||||
configurable: isCanaryBuild,
|
||||
defaultState: false,
|
||||
},
|
||||
enable_cloud_indexer: {
|
||||
category: 'affine',
|
||||
displayName: 'Enable Cloud Indexer',
|
||||
description: 'Use cloud indexer to search docs',
|
||||
configurable: isBetaBuild || isCanaryBuild,
|
||||
defaultState: false,
|
||||
},
|
||||
} satisfies { [key in string]: FlagInfo };
|
||||
|
||||
// oxlint-disable-next-line no-redeclare
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { FeatureFlagService } from '@affine/core/modules/feature-flag';
|
||||
import { DebugLogger } from '@affine/debug';
|
||||
import {
|
||||
createWorkspaceMutation,
|
||||
@@ -85,6 +86,7 @@ const logger = new DebugLogger('affine:cloud-workspace-flavour-provider');
|
||||
class CloudWorkspaceFlavourProvider implements WorkspaceFlavourProvider {
|
||||
private readonly authService: AuthService;
|
||||
private readonly graphqlService: GraphQLService;
|
||||
private readonly featureFlagService: FeatureFlagService;
|
||||
private readonly unsubscribeAccountChanged: () => void;
|
||||
|
||||
constructor(
|
||||
@@ -93,6 +95,7 @@ class CloudWorkspaceFlavourProvider implements WorkspaceFlavourProvider {
|
||||
) {
|
||||
this.authService = server.scope.get(AuthService);
|
||||
this.graphqlService = server.scope.get(GraphQLService);
|
||||
this.featureFlagService = server.scope.get(FeatureFlagService);
|
||||
this.unsubscribeAccountChanged = this.server.scope.eventBus.on(
|
||||
AccountChanged,
|
||||
() => {
|
||||
@@ -474,14 +477,24 @@ class CloudWorkspaceFlavourProvider implements WorkspaceFlavourProvider {
|
||||
id: `${this.flavour}:${workspaceId}`,
|
||||
},
|
||||
},
|
||||
indexer: {
|
||||
name: 'IndexedDBIndexerStorage',
|
||||
opts: {
|
||||
flavour: this.flavour,
|
||||
type: 'workspace',
|
||||
id: workspaceId,
|
||||
},
|
||||
},
|
||||
indexer: this.featureFlagService.flags.enable_cloud_indexer.value
|
||||
? {
|
||||
name: 'CloudIndexerStorage',
|
||||
opts: {
|
||||
flavour: this.flavour,
|
||||
type: 'workspace',
|
||||
id: workspaceId,
|
||||
serverBaseUrl: this.server.serverMetadata.baseUrl,
|
||||
},
|
||||
}
|
||||
: {
|
||||
name: 'IndexedDBIndexerStorage',
|
||||
opts: {
|
||||
flavour: this.flavour,
|
||||
type: 'workspace',
|
||||
id: workspaceId,
|
||||
},
|
||||
},
|
||||
indexerSync: {
|
||||
name: 'IndexedDBIndexerSyncStorage',
|
||||
opts: {
|
||||
|
||||
Reference in New Issue
Block a user