UBERF-8540: Allow derived operations with apply (#7044)

This commit is contained in:
Andrey Sobolev 2024-10-26 21:17:37 +07:00 committed by GitHub
parent 470861ed09
commit e11a0a87cb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 71 additions and 44 deletions

View File

@ -399,6 +399,18 @@ export const notificationOperation: MigrateOperation = {
func: async (client: MigrationClient): Promise<void> => {
await client.update(DOMAIN_DOC_NOTIFY, { '%hash%': { $exists: true } }, { $set: { '%hash%': null } })
}
},
{
state: 'remove-update-txes-docnotify-ctx',
func: async (client) => {
await client.deleteMany(DOMAIN_TX, {
_class: core.class.TxUpdateDoc,
objectClass: notification.class.DocNotifyContext,
'operations.lastViewedTimestamp': {
$exists: true
}
})
}
}
])

View File

@ -313,8 +313,8 @@ export class TxOperations implements Omit<Client, 'notify'> {
return this.removeDoc(doc._class, doc.space, doc._id)
}
apply (scope?: string, measure?: string): ApplyOperations {
return new ApplyOperations(this, scope, measure, this.isDerived)
apply (scope?: string, measure?: string, derived?: boolean): ApplyOperations {
return new ApplyOperations(this, scope, measure, derived ?? this.isDerived)
}
async diffUpdate<T extends Doc = Doc>(

View File

@ -85,6 +85,8 @@ export interface LowLevelStorage {
rawUpdate: <T extends Doc>(domain: Domain, query: DocumentQuery<T>, operations: DocumentUpdate<T>) => Promise<void>
rawDeleteMany: <T extends Doc>(domain: Domain, query: DocumentQuery<T>) => Promise<void>
// Traverse documents
traverse: <T extends Doc>(
domain: Domain,

View File

@ -760,7 +760,7 @@
if (unViewed.length === 0) {
forceRead = true
const op = client.apply(undefined, 'chunter.forceReadContext')
const op = client.apply(undefined, 'chunter.forceReadContext', true)
await inboxClient.readDoc(op, object._id)
await op.commit()
}

View File

@ -419,7 +419,7 @@
if (unViewed.length === 0) {
forceRead = true
const op = client.apply(undefined, 'chunter.forceReadContext')
const op = client.apply(undefined, 'chunter.forceReadContext', true)
await inboxClient.readDoc(op, object._id)
await op.commit()
}

View File

@ -400,7 +400,7 @@ export async function hideActivityChannels (contexts: DocNotifyContext[]): Promi
export async function readActivityChannels (contexts: DocNotifyContext[]): Promise<void> {
const client = InboxNotificationsClientImpl.getClient()
const notificationsByContext = get(client.inboxNotificationsByContext)
const ops = getClient().apply(undefined, 'readActivityChannels')
const ops = getClient().apply(undefined, 'readActivityChannels', true)
try {
for (const context of contexts) {

View File

@ -235,7 +235,7 @@ export class InboxNotificationsClientImpl implements InboxNotificationsClient {
}
async archiveAllNotifications (): Promise<void> {
const ops = getClient().apply(undefined, 'archiveAllNotifications')
const ops = getClient().apply(undefined, 'archiveAllNotifications', true)
try {
const inboxNotifications = await ops.findAll(
@ -260,7 +260,7 @@ export class InboxNotificationsClientImpl implements InboxNotificationsClient {
}
async readAllNotifications (): Promise<void> {
const ops = getClient().apply(undefined, 'readAllNotifications')
const ops = getClient().apply(undefined, 'readAllNotifications', true)
try {
const inboxNotifications = await ops.findAll(
@ -285,7 +285,7 @@ export class InboxNotificationsClientImpl implements InboxNotificationsClient {
}
async unreadAllNotifications (): Promise<void> {
const ops = getClient().apply(undefined, 'unreadAllNotifications')
const ops = getClient().apply(undefined, 'unreadAllNotifications', true)
try {
const inboxNotifications = await ops.findAll(

View File

@ -128,7 +128,7 @@ export async function readNotifyContext (doc: DocNotifyContext): Promise<void> {
const inboxClient = InboxNotificationsClientImpl.getClient()
const inboxNotifications = get(inboxClient.inboxNotificationsByContext).get(doc._id) ?? []
const ops = getClient().apply(undefined, 'readNotifyContext')
const ops = getClient().apply(undefined, 'readNotifyContext', true)
try {
await inboxClient.readNotifications(
ops,
@ -152,7 +152,7 @@ export async function unReadNotifyContext (doc: DocNotifyContext): Promise<void>
return
}
const ops = getClient().apply(undefined, 'unReadNotifyContext')
const ops = getClient().apply(undefined, 'unReadNotifyContext', true)
try {
await inboxClient.unreadNotifications(

View File

@ -13,24 +13,24 @@
// limitations under the License.
-->
<script lang="ts">
import { Asset, getResource, translate } from '@hcengineering/platform'
import { ComponentExtensions, getClient, reduceCalls } from '@hcengineering/presentation'
import {
AnySvelteComponent,
closePanel,
getCurrentLocation,
Icon,
ModernTab,
navigate,
languageStore,
locationToUrl
locationToUrl,
ModernTab,
navigate
} from '@hcengineering/ui'
import { ComponentExtensions, getClient, reduceCalls } from '@hcengineering/presentation'
import { Asset, getResource, translate } from '@hcengineering/platform'
import { WorkbenchTab } from '@hcengineering/workbench'
import view from '@hcengineering/view'
import { showMenu } from '@hcengineering/view-resources'
import { WorkbenchTab } from '@hcengineering/workbench'
import { closeTab, getTabDataByLocation, getTabLocation, selectTab, tabIdStore, tabsStore } from '../workbench'
import workbench from '../plugin'
import { closeTab, getTabDataByLocation, getTabLocation, selectTab, tabIdStore, tabsStore } from '../workbench'
export let tab: WorkbenchTab
@ -63,7 +63,9 @@
iconProps = data.iconProps
if (tab.name !== name && tab.location === locationToUrl(tabLoc)) {
const op = client.apply(undefined, undefined, true)
await client.diffUpdate(tab, { name })
await op.commit()
}
}

View File

@ -116,6 +116,8 @@ export class DummyDbAdapter implements DbAdapter {
query: DocumentQuery<T>,
operations: DocumentUpdate<T>
): Promise<void> {}
async rawDeleteMany<T extends Doc>(domain: Domain, query: DocumentQuery<T>): Promise<void> {}
}
class InMemoryAdapter extends DummyDbAdapter implements DbAdapter {

View File

@ -36,8 +36,7 @@ const serverCore = plugin(serverCoreId, {
SearchPresenter: '' as Ref<Mixin<SearchPresenter>>
},
space: {
DocIndexState: '' as Ref<Space>,
TriggerState: '' as Ref<Space>
DocIndexState: '' as Ref<Space>
},
metadata: {
FrontUrl: '' as Metadata<string>,

View File

@ -142,6 +142,10 @@ class ElasticDataAdapter implements DbAdapter {
throw new Error('Method not implemented.')
}
async rawDeleteMany<T extends Doc>(domain: Domain, query: DocumentQuery<T>): Promise<void> {
throw new Error('Method not implemented')
}
async clean (ctx: MeasureContext, domain: Domain, docs: Ref<Doc>[]): Promise<void> {
const indexExists = await this.client.indices.exists({
index: this.indexName

View File

@ -19,10 +19,10 @@ import {
FindOptions,
type Doc,
type Domain,
type Iterator,
type MeasureContext,
type Ref,
type StorageIterator,
type Iterator
type StorageIterator
} from '@hcengineering/core'
import { PlatformError, unknownStatus } from '@hcengineering/platform'
import type { Middleware, PipelineContext } from '@hcengineering/server-core'
@ -47,36 +47,35 @@ export class LowLevelMiddleware extends BaseMiddleware implements Middleware {
return adapterManager.getAdapter(domain, false).find(ctx, domain, recheck)
},
async load (ctx: MeasureContext, domain: Domain, docs: Ref<Doc>[]): Promise<Doc[]> {
return await adapterManager.getAdapter(domain, false).load(ctx, domain, docs)
load (ctx: MeasureContext, domain: Domain, docs: Ref<Doc>[]): Promise<Doc[]> {
return adapterManager.getAdapter(domain, false).load(ctx, domain, docs)
},
async upload (ctx: MeasureContext, domain: Domain, docs: Doc[]): Promise<void> {
await adapterManager.getAdapter(domain, true).upload(ctx, domain, docs)
upload (ctx: MeasureContext, domain: Domain, docs: Doc[]): Promise<void> {
return adapterManager.getAdapter(domain, true).upload(ctx, domain, docs)
},
async clean (ctx: MeasureContext, domain: Domain, docs: Ref<Doc>[]): Promise<void> {
await adapterManager.getAdapter(domain, true).clean(ctx, domain, docs)
},
async groupBy<T>(ctx: MeasureContext, domain: Domain, field: string): Promise<Set<T>> {
return await adapterManager.getAdapter(domain, false).groupBy(ctx, domain, field)
groupBy<T>(ctx: MeasureContext, domain: Domain, field: string): Promise<Set<T>> {
return adapterManager.getAdapter(domain, false).groupBy(ctx, domain, field)
},
async rawFindAll<T extends Doc>(domain: Domain, query: DocumentQuery<T>, options?: FindOptions<T>): Promise<T[]> {
return await adapterManager.getAdapter(domain, false).rawFindAll(domain, query, options)
rawFindAll<T extends Doc>(domain: Domain, query: DocumentQuery<T>, options?: FindOptions<T>): Promise<T[]> {
return adapterManager.getAdapter(domain, false).rawFindAll(domain, query, options)
},
async rawUpdate<T extends Doc>(
domain: Domain,
query: DocumentQuery<T>,
operations: DocumentUpdate<T>
): Promise<void> {
await adapterManager.getAdapter(domain, true).rawUpdate(domain, query, operations)
rawUpdate<T extends Doc>(domain: Domain, query: DocumentQuery<T>, operations: DocumentUpdate<T>): Promise<void> {
return adapterManager.getAdapter(domain, true).rawUpdate(domain, query, operations)
},
async traverse<T extends Doc>(
rawDeleteMany (domain, query) {
return adapterManager.getAdapter(domain, true).rawDeleteMany(domain, query)
},
traverse<T extends Doc>(
domain: Domain,
query: DocumentQuery<T>,
options?: Pick<FindOptions<T>, 'sort' | 'limit' | 'projection'>
): Promise<Iterator<T>> {
return await adapterManager.getAdapter(domain, false).traverse(domain, query, options)
return adapterManager.getAdapter(domain, false).traverse(domain, query, options)
}
}
return undefined

View File

@ -262,6 +262,10 @@ abstract class MongoAdapterBase implements DbAdapter {
}
}
async rawDeleteMany<T extends Doc>(domain: Domain, query: DocumentQuery<T>): Promise<void> {
await this.db.collection(domain).deleteMany(this.translateRawQuery(query))
}
abstract init (): Promise<void>
collection<TSchema extends Document = Document>(domain: Domain): Collection<TSchema> {

View File

@ -327,6 +327,13 @@ abstract class PostgresAdapterBase implements DbAdapter {
})
}
async rawDeleteMany<T extends Doc>(domain: Domain, query: DocumentQuery<T>): Promise<void> {
const translatedQuery = this.buildRawQuery(domain, query)
await this.retryTxn(this.client, async (client) => {
await client.query(`DELETE FROM ${translateDomain(domain)} WHERE ${translatedQuery}`)
})
}
async findAll<T extends Doc>(
ctx: MeasureContext<SessionData>,
_class: Ref<Class<T>>,

View File

@ -70,6 +70,8 @@ class StorageBlobAdapter implements DbAdapter {
operations: DocumentUpdate<T>
): Promise<void> {}
async rawDeleteMany<T extends Doc>(domain: Domain, query: DocumentQuery<T>): Promise<void> {}
async findAll<T extends Doc>(
ctx: MeasureContext,
_class: Ref<Class<T>>,

View File

@ -96,12 +96,6 @@ export class MigrateClientImpl implements MigrationClient {
}
async deleteMany<T extends Doc>(domain: Domain, query: DocumentQuery<T>): Promise<void> {
const ctx = new MeasureMetricsContext('deleteMany', {})
const docs = await this.lowLevel.rawFindAll(domain, query)
await this.lowLevel.clean(
ctx,
domain,
docs.map((d) => d._id)
)
await this.lowLevel.rawDeleteMany(domain, query)
}
}