mirror of
https://github.com/hcengineering/platform.git
synced 2025-04-16 13:21:57 +00:00
UBERF-8540: Allow derived operations with apply (#7044)
This commit is contained in:
parent
470861ed09
commit
e11a0a87cb
models/notification/src
packages/core/src
plugins
chunter-resources/src/components
notification-resources/src
workbench-resources/src/components
server
core/src
elastic/src
middleware/src
mongo/src
postgres/src
server-storage/src
tool/src
@ -399,6 +399,18 @@ export const notificationOperation: MigrateOperation = {
|
|||||||
func: async (client: MigrationClient): Promise<void> => {
|
func: async (client: MigrationClient): Promise<void> => {
|
||||||
await client.update(DOMAIN_DOC_NOTIFY, { '%hash%': { $exists: true } }, { $set: { '%hash%': null } })
|
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
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
|
||||||
|
@ -313,8 +313,8 @@ export class TxOperations implements Omit<Client, 'notify'> {
|
|||||||
return this.removeDoc(doc._class, doc.space, doc._id)
|
return this.removeDoc(doc._class, doc.space, doc._id)
|
||||||
}
|
}
|
||||||
|
|
||||||
apply (scope?: string, measure?: string): ApplyOperations {
|
apply (scope?: string, measure?: string, derived?: boolean): ApplyOperations {
|
||||||
return new ApplyOperations(this, scope, measure, this.isDerived)
|
return new ApplyOperations(this, scope, measure, derived ?? this.isDerived)
|
||||||
}
|
}
|
||||||
|
|
||||||
async diffUpdate<T extends Doc = Doc>(
|
async diffUpdate<T extends Doc = Doc>(
|
||||||
|
@ -85,6 +85,8 @@ export interface LowLevelStorage {
|
|||||||
|
|
||||||
rawUpdate: <T extends Doc>(domain: Domain, query: DocumentQuery<T>, operations: DocumentUpdate<T>) => Promise<void>
|
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 documents
|
||||||
traverse: <T extends Doc>(
|
traverse: <T extends Doc>(
|
||||||
domain: Domain,
|
domain: Domain,
|
||||||
|
@ -760,7 +760,7 @@
|
|||||||
|
|
||||||
if (unViewed.length === 0) {
|
if (unViewed.length === 0) {
|
||||||
forceRead = true
|
forceRead = true
|
||||||
const op = client.apply(undefined, 'chunter.forceReadContext')
|
const op = client.apply(undefined, 'chunter.forceReadContext', true)
|
||||||
await inboxClient.readDoc(op, object._id)
|
await inboxClient.readDoc(op, object._id)
|
||||||
await op.commit()
|
await op.commit()
|
||||||
}
|
}
|
||||||
|
@ -419,7 +419,7 @@
|
|||||||
|
|
||||||
if (unViewed.length === 0) {
|
if (unViewed.length === 0) {
|
||||||
forceRead = true
|
forceRead = true
|
||||||
const op = client.apply(undefined, 'chunter.forceReadContext')
|
const op = client.apply(undefined, 'chunter.forceReadContext', true)
|
||||||
await inboxClient.readDoc(op, object._id)
|
await inboxClient.readDoc(op, object._id)
|
||||||
await op.commit()
|
await op.commit()
|
||||||
}
|
}
|
||||||
|
@ -400,7 +400,7 @@ export async function hideActivityChannels (contexts: DocNotifyContext[]): Promi
|
|||||||
export async function readActivityChannels (contexts: DocNotifyContext[]): Promise<void> {
|
export async function readActivityChannels (contexts: DocNotifyContext[]): Promise<void> {
|
||||||
const client = InboxNotificationsClientImpl.getClient()
|
const client = InboxNotificationsClientImpl.getClient()
|
||||||
const notificationsByContext = get(client.inboxNotificationsByContext)
|
const notificationsByContext = get(client.inboxNotificationsByContext)
|
||||||
const ops = getClient().apply(undefined, 'readActivityChannels')
|
const ops = getClient().apply(undefined, 'readActivityChannels', true)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
for (const context of contexts) {
|
for (const context of contexts) {
|
||||||
|
@ -235,7 +235,7 @@ export class InboxNotificationsClientImpl implements InboxNotificationsClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async archiveAllNotifications (): Promise<void> {
|
async archiveAllNotifications (): Promise<void> {
|
||||||
const ops = getClient().apply(undefined, 'archiveAllNotifications')
|
const ops = getClient().apply(undefined, 'archiveAllNotifications', true)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const inboxNotifications = await ops.findAll(
|
const inboxNotifications = await ops.findAll(
|
||||||
@ -260,7 +260,7 @@ export class InboxNotificationsClientImpl implements InboxNotificationsClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async readAllNotifications (): Promise<void> {
|
async readAllNotifications (): Promise<void> {
|
||||||
const ops = getClient().apply(undefined, 'readAllNotifications')
|
const ops = getClient().apply(undefined, 'readAllNotifications', true)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const inboxNotifications = await ops.findAll(
|
const inboxNotifications = await ops.findAll(
|
||||||
@ -285,7 +285,7 @@ export class InboxNotificationsClientImpl implements InboxNotificationsClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async unreadAllNotifications (): Promise<void> {
|
async unreadAllNotifications (): Promise<void> {
|
||||||
const ops = getClient().apply(undefined, 'unreadAllNotifications')
|
const ops = getClient().apply(undefined, 'unreadAllNotifications', true)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const inboxNotifications = await ops.findAll(
|
const inboxNotifications = await ops.findAll(
|
||||||
|
@ -128,7 +128,7 @@ export async function readNotifyContext (doc: DocNotifyContext): Promise<void> {
|
|||||||
const inboxClient = InboxNotificationsClientImpl.getClient()
|
const inboxClient = InboxNotificationsClientImpl.getClient()
|
||||||
const inboxNotifications = get(inboxClient.inboxNotificationsByContext).get(doc._id) ?? []
|
const inboxNotifications = get(inboxClient.inboxNotificationsByContext).get(doc._id) ?? []
|
||||||
|
|
||||||
const ops = getClient().apply(undefined, 'readNotifyContext')
|
const ops = getClient().apply(undefined, 'readNotifyContext', true)
|
||||||
try {
|
try {
|
||||||
await inboxClient.readNotifications(
|
await inboxClient.readNotifications(
|
||||||
ops,
|
ops,
|
||||||
@ -152,7 +152,7 @@ export async function unReadNotifyContext (doc: DocNotifyContext): Promise<void>
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const ops = getClient().apply(undefined, 'unReadNotifyContext')
|
const ops = getClient().apply(undefined, 'unReadNotifyContext', true)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await inboxClient.unreadNotifications(
|
await inboxClient.unreadNotifications(
|
||||||
|
@ -13,24 +13,24 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { Asset, getResource, translate } from '@hcengineering/platform'
|
||||||
|
import { ComponentExtensions, getClient, reduceCalls } from '@hcengineering/presentation'
|
||||||
import {
|
import {
|
||||||
AnySvelteComponent,
|
AnySvelteComponent,
|
||||||
closePanel,
|
closePanel,
|
||||||
getCurrentLocation,
|
getCurrentLocation,
|
||||||
Icon,
|
Icon,
|
||||||
ModernTab,
|
|
||||||
navigate,
|
|
||||||
languageStore,
|
languageStore,
|
||||||
locationToUrl
|
locationToUrl,
|
||||||
|
ModernTab,
|
||||||
|
navigate
|
||||||
} from '@hcengineering/ui'
|
} 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 view from '@hcengineering/view'
|
||||||
import { showMenu } from '@hcengineering/view-resources'
|
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 workbench from '../plugin'
|
||||||
|
import { closeTab, getTabDataByLocation, getTabLocation, selectTab, tabIdStore, tabsStore } from '../workbench'
|
||||||
|
|
||||||
export let tab: WorkbenchTab
|
export let tab: WorkbenchTab
|
||||||
|
|
||||||
@ -63,7 +63,9 @@
|
|||||||
iconProps = data.iconProps
|
iconProps = data.iconProps
|
||||||
|
|
||||||
if (tab.name !== name && tab.location === locationToUrl(tabLoc)) {
|
if (tab.name !== name && tab.location === locationToUrl(tabLoc)) {
|
||||||
|
const op = client.apply(undefined, undefined, true)
|
||||||
await client.diffUpdate(tab, { name })
|
await client.diffUpdate(tab, { name })
|
||||||
|
await op.commit()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,6 +116,8 @@ export class DummyDbAdapter implements DbAdapter {
|
|||||||
query: DocumentQuery<T>,
|
query: DocumentQuery<T>,
|
||||||
operations: DocumentUpdate<T>
|
operations: DocumentUpdate<T>
|
||||||
): Promise<void> {}
|
): Promise<void> {}
|
||||||
|
|
||||||
|
async rawDeleteMany<T extends Doc>(domain: Domain, query: DocumentQuery<T>): Promise<void> {}
|
||||||
}
|
}
|
||||||
|
|
||||||
class InMemoryAdapter extends DummyDbAdapter implements DbAdapter {
|
class InMemoryAdapter extends DummyDbAdapter implements DbAdapter {
|
||||||
|
@ -36,8 +36,7 @@ const serverCore = plugin(serverCoreId, {
|
|||||||
SearchPresenter: '' as Ref<Mixin<SearchPresenter>>
|
SearchPresenter: '' as Ref<Mixin<SearchPresenter>>
|
||||||
},
|
},
|
||||||
space: {
|
space: {
|
||||||
DocIndexState: '' as Ref<Space>,
|
DocIndexState: '' as Ref<Space>
|
||||||
TriggerState: '' as Ref<Space>
|
|
||||||
},
|
},
|
||||||
metadata: {
|
metadata: {
|
||||||
FrontUrl: '' as Metadata<string>,
|
FrontUrl: '' as Metadata<string>,
|
||||||
|
@ -142,6 +142,10 @@ class ElasticDataAdapter implements DbAdapter {
|
|||||||
throw new Error('Method not implemented.')
|
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> {
|
async clean (ctx: MeasureContext, domain: Domain, docs: Ref<Doc>[]): Promise<void> {
|
||||||
const indexExists = await this.client.indices.exists({
|
const indexExists = await this.client.indices.exists({
|
||||||
index: this.indexName
|
index: this.indexName
|
||||||
|
@ -19,10 +19,10 @@ import {
|
|||||||
FindOptions,
|
FindOptions,
|
||||||
type Doc,
|
type Doc,
|
||||||
type Domain,
|
type Domain,
|
||||||
|
type Iterator,
|
||||||
type MeasureContext,
|
type MeasureContext,
|
||||||
type Ref,
|
type Ref,
|
||||||
type StorageIterator,
|
type StorageIterator
|
||||||
type Iterator
|
|
||||||
} from '@hcengineering/core'
|
} from '@hcengineering/core'
|
||||||
import { PlatformError, unknownStatus } from '@hcengineering/platform'
|
import { PlatformError, unknownStatus } from '@hcengineering/platform'
|
||||||
import type { Middleware, PipelineContext } from '@hcengineering/server-core'
|
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)
|
return adapterManager.getAdapter(domain, false).find(ctx, domain, recheck)
|
||||||
},
|
},
|
||||||
|
|
||||||
async load (ctx: MeasureContext, domain: Domain, docs: Ref<Doc>[]): Promise<Doc[]> {
|
load (ctx: MeasureContext, domain: Domain, docs: Ref<Doc>[]): Promise<Doc[]> {
|
||||||
return await adapterManager.getAdapter(domain, false).load(ctx, domain, docs)
|
return adapterManager.getAdapter(domain, false).load(ctx, domain, docs)
|
||||||
},
|
},
|
||||||
|
|
||||||
async upload (ctx: MeasureContext, domain: Domain, docs: Doc[]): Promise<void> {
|
upload (ctx: MeasureContext, domain: Domain, docs: Doc[]): Promise<void> {
|
||||||
await adapterManager.getAdapter(domain, true).upload(ctx, domain, docs)
|
return adapterManager.getAdapter(domain, true).upload(ctx, domain, docs)
|
||||||
},
|
},
|
||||||
|
|
||||||
async clean (ctx: MeasureContext, domain: Domain, docs: Ref<Doc>[]): Promise<void> {
|
async clean (ctx: MeasureContext, domain: Domain, docs: Ref<Doc>[]): Promise<void> {
|
||||||
await adapterManager.getAdapter(domain, true).clean(ctx, domain, docs)
|
await adapterManager.getAdapter(domain, true).clean(ctx, domain, docs)
|
||||||
},
|
},
|
||||||
async groupBy<T>(ctx: MeasureContext, domain: Domain, field: string): Promise<Set<T>> {
|
groupBy<T>(ctx: MeasureContext, domain: Domain, field: string): Promise<Set<T>> {
|
||||||
return await adapterManager.getAdapter(domain, false).groupBy(ctx, domain, field)
|
return adapterManager.getAdapter(domain, false).groupBy(ctx, domain, field)
|
||||||
},
|
},
|
||||||
async rawFindAll<T extends Doc>(domain: Domain, query: DocumentQuery<T>, options?: FindOptions<T>): Promise<T[]> {
|
rawFindAll<T extends Doc>(domain: Domain, query: DocumentQuery<T>, options?: FindOptions<T>): Promise<T[]> {
|
||||||
return await adapterManager.getAdapter(domain, false).rawFindAll(domain, query, options)
|
return adapterManager.getAdapter(domain, false).rawFindAll(domain, query, options)
|
||||||
},
|
},
|
||||||
async rawUpdate<T extends Doc>(
|
rawUpdate<T extends Doc>(domain: Domain, query: DocumentQuery<T>, operations: DocumentUpdate<T>): Promise<void> {
|
||||||
domain: Domain,
|
return adapterManager.getAdapter(domain, true).rawUpdate(domain, query, operations)
|
||||||
query: DocumentQuery<T>,
|
|
||||||
operations: DocumentUpdate<T>
|
|
||||||
): Promise<void> {
|
|
||||||
await 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,
|
domain: Domain,
|
||||||
query: DocumentQuery<T>,
|
query: DocumentQuery<T>,
|
||||||
options?: Pick<FindOptions<T>, 'sort' | 'limit' | 'projection'>
|
options?: Pick<FindOptions<T>, 'sort' | 'limit' | 'projection'>
|
||||||
): Promise<Iterator<T>> {
|
): Promise<Iterator<T>> {
|
||||||
return await adapterManager.getAdapter(domain, false).traverse(domain, query, options)
|
return adapterManager.getAdapter(domain, false).traverse(domain, query, options)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return undefined
|
return undefined
|
||||||
|
@ -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>
|
abstract init (): Promise<void>
|
||||||
|
|
||||||
collection<TSchema extends Document = Document>(domain: Domain): Collection<TSchema> {
|
collection<TSchema extends Document = Document>(domain: Domain): Collection<TSchema> {
|
||||||
|
@ -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>(
|
async findAll<T extends Doc>(
|
||||||
ctx: MeasureContext<SessionData>,
|
ctx: MeasureContext<SessionData>,
|
||||||
_class: Ref<Class<T>>,
|
_class: Ref<Class<T>>,
|
||||||
|
@ -70,6 +70,8 @@ class StorageBlobAdapter implements DbAdapter {
|
|||||||
operations: DocumentUpdate<T>
|
operations: DocumentUpdate<T>
|
||||||
): Promise<void> {}
|
): Promise<void> {}
|
||||||
|
|
||||||
|
async rawDeleteMany<T extends Doc>(domain: Domain, query: DocumentQuery<T>): Promise<void> {}
|
||||||
|
|
||||||
async findAll<T extends Doc>(
|
async findAll<T extends Doc>(
|
||||||
ctx: MeasureContext,
|
ctx: MeasureContext,
|
||||||
_class: Ref<Class<T>>,
|
_class: Ref<Class<T>>,
|
||||||
|
@ -96,12 +96,6 @@ export class MigrateClientImpl implements MigrationClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async deleteMany<T extends Doc>(domain: Domain, query: DocumentQuery<T>): Promise<void> {
|
async deleteMany<T extends Doc>(domain: Domain, query: DocumentQuery<T>): Promise<void> {
|
||||||
const ctx = new MeasureMetricsContext('deleteMany', {})
|
await this.lowLevel.rawDeleteMany(domain, query)
|
||||||
const docs = await this.lowLevel.rawFindAll(domain, query)
|
|
||||||
await this.lowLevel.clean(
|
|
||||||
ctx,
|
|
||||||
domain,
|
|
||||||
docs.map((d) => d._id)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user