mirror of
https://github.com/hcengineering/platform.git
synced 2026-10-01 14:05:05 +02:00
Merge pull request #311 from hcengineering/tx-collection-cud
This commit is contained in:
@@ -28,6 +28,7 @@ function extractBacklinks (backlinkId: Ref<Doc>, message: string, kids: NodeList
|
||||
result.push({
|
||||
attachedTo: kid.getAttribute('data-id') as Ref<Doc>,
|
||||
attachedToClass: kid.getAttribute('data-class') as Ref<Class<Doc>>,
|
||||
collection: kid.getAttribute('data-collection') ?? '',
|
||||
backlinkId,
|
||||
backlinkClass: chunter.class.Message,
|
||||
message
|
||||
|
||||
+340
-326
File diff suppressed because it is too large
Load Diff
+340
-326
File diff suppressed because it is too large
Load Diff
@@ -17,7 +17,7 @@ import type { IntlString } from '@anticrm/platform'
|
||||
import { Builder, Model, Prop, UX, TypeString, Index, TypeTimestamp } from '@anticrm/model'
|
||||
import type { Ref, Doc, Class, Domain } from '@anticrm/core'
|
||||
import { IndexKind } from '@anticrm/core'
|
||||
import core, { TSpace, TDoc } from '@anticrm/model-core'
|
||||
import core, { TSpace, TDoc, TAttachedDoc } from '@anticrm/model-core'
|
||||
import type { Backlink, Channel, Message, Comment, Attachment } from '@anticrm/chunter'
|
||||
import type { AnyComponent } from '@anticrm/ui'
|
||||
|
||||
@@ -42,9 +42,7 @@ export class TMessage extends TDoc implements Message {
|
||||
}
|
||||
|
||||
@Model(chunter.class.Comment, core.class.Doc, DOMAIN_COMMENT)
|
||||
export class TComment extends TDoc implements Comment {
|
||||
attachedTo!: Ref<Doc>
|
||||
attachedToClass!: Ref<Class<Doc>>
|
||||
export class TComment extends TAttachedDoc implements Comment {
|
||||
@Prop(TypeString(), 'Message' as IntlString)
|
||||
@Index(IndexKind.FullText)
|
||||
message!: string
|
||||
@@ -58,9 +56,7 @@ export class TBacklink extends TComment implements Backlink {
|
||||
|
||||
@Model(chunter.class.Attachment, core.class.Doc, DOMAIN_ATTACHMENT)
|
||||
@UX('File' as IntlString)
|
||||
export class TAttachment extends TDoc implements Attachment {
|
||||
attachedTo!: Ref<Doc>
|
||||
attachedToClass!: Ref<Class<Doc>>
|
||||
export class TAttachment extends TAttachedDoc implements Attachment {
|
||||
@Prop(TypeString(), 'Name' as IntlString)
|
||||
name!: string
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
//
|
||||
|
||||
import type { IntlString } from '@anticrm/platform'
|
||||
import type { Account, AnyAttribute, Class, ClassifierKind, Doc, Domain, Mixin, Obj, Ref, Space, Timestamp, Type } from '@anticrm/core'
|
||||
import type { Account, AnyAttribute, AttachedDoc, Class, ClassifierKind, Doc, Domain, Mixin, Obj, Ref, Space, Timestamp, Type } from '@anticrm/core'
|
||||
import { DOMAIN_MODEL } from '@anticrm/core'
|
||||
import { Model, Prop, TypeTimestamp } from '@anticrm/model'
|
||||
import core from './component'
|
||||
@@ -36,6 +36,13 @@ export class TDoc extends TObj implements Doc {
|
||||
modifiedBy!: Ref<Account>
|
||||
}
|
||||
|
||||
@Model(core.class.AttachedDoc, core.class.Doc)
|
||||
export class TAttachedDoc extends TDoc implements AttachedDoc {
|
||||
attachedTo!: Ref<Doc>
|
||||
attachedToClass!: Ref<Class<Doc>>
|
||||
collection!: string
|
||||
}
|
||||
|
||||
@Model(core.class.Class, core.class.Doc, DOMAIN_MODEL)
|
||||
export class TClass extends TDoc implements Class<Obj> {
|
||||
kind!: ClassifierKind
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
|
||||
import { Builder } from '@anticrm/model'
|
||||
import core from './component'
|
||||
import { TAttribute, TClass, TDoc, TMixin, TObj, TType, TTypeString, TTypeBoolean, TTypeTimestamp } from './core'
|
||||
import { TAttribute, TClass, TDoc, TMixin, TObj, TType, TTypeString, TTypeBoolean, TTypeTimestamp, TAttachedDoc } from './core'
|
||||
import { TSpace, TAccount, TState, TSpaceWithStates, TDocWithState } from './security'
|
||||
import { TTx, TTxCreateDoc, TTxMixin, TTxUpdateDoc, TTxCUD, TTxPutBag, TTxRemoveDoc, TTxBulkWrite, TTxAddCollection } from './tx'
|
||||
import { TTx, TTxCreateDoc, TTxMixin, TTxUpdateDoc, TTxCUD, TTxPutBag, TTxRemoveDoc, TTxBulkWrite, TTxCollectionCUD } from './tx'
|
||||
|
||||
export * from './core'
|
||||
export * from './security'
|
||||
@@ -33,7 +33,8 @@ export function createModel (builder: Builder): void {
|
||||
TTx,
|
||||
TTxCUD,
|
||||
TTxCreateDoc,
|
||||
TTxAddCollection,
|
||||
TAttachedDoc,
|
||||
TTxCollectionCUD,
|
||||
TTxPutBag,
|
||||
TTxMixin,
|
||||
TTxUpdateDoc,
|
||||
|
||||
@@ -47,7 +47,7 @@ export class TState extends TDoc implements State {
|
||||
color!: string
|
||||
}
|
||||
|
||||
@Model(core.class.DocWithState, core.class.Doc)
|
||||
@Model(core.class.DocWithState, core.class.AttachedDoc)
|
||||
export class TDocWithState extends TDoc {
|
||||
@Prop(TypeString(), 'State' as IntlString)
|
||||
state!: Ref<State>
|
||||
|
||||
+14
-15
@@ -14,25 +14,25 @@
|
||||
//
|
||||
|
||||
import type {
|
||||
AttachedDoc,
|
||||
Class,
|
||||
Data,
|
||||
Doc,
|
||||
DocumentUpdate,
|
||||
ExtendedAttributes,
|
||||
Mixin,
|
||||
PropertyType,
|
||||
Ref,
|
||||
Space,
|
||||
Tx,
|
||||
TxCUD,
|
||||
TxCreateDoc,
|
||||
TxRemoveDoc,
|
||||
TxUpdateDoc,
|
||||
TxMixin,
|
||||
Mixin,
|
||||
ExtendedAttributes,
|
||||
PropertyType,
|
||||
TxPutBag,
|
||||
TxBulkWrite,
|
||||
AttachedDoc,
|
||||
TxAddCollection
|
||||
TxCollectionCUD,
|
||||
TxCreateDoc,
|
||||
TxCUD,
|
||||
TxMixin,
|
||||
TxPutBag,
|
||||
TxRemoveDoc,
|
||||
TxUpdateDoc
|
||||
} from '@anticrm/core'
|
||||
import { DOMAIN_TX } from '@anticrm/core'
|
||||
import { Model } from '@anticrm/model'
|
||||
@@ -57,11 +57,10 @@ export class TTxCreateDoc<T extends Doc> extends TTxCUD<T> implements TxCreateDo
|
||||
attributes!: Data<T>
|
||||
}
|
||||
|
||||
@Model(core.class.TxAddCollection, core.class.TxCreateDoc)
|
||||
export class TTxAddCollection<T extends AttachedDoc> extends TTxCreateDoc<T> implements TxAddCollection<T> {
|
||||
@Model(core.class.TxCollectionCUD, core.class.TxCUD)
|
||||
export class TTxCollectionCUD<T extends Doc, P extends AttachedDoc> extends TTxCUD<T> implements TxCollectionCUD<T, P> {
|
||||
collection!: string
|
||||
attachedTo!: Ref<Doc>
|
||||
attachedToClass!: Ref<Class<Doc>>
|
||||
tx!: TxCUD<P>
|
||||
}
|
||||
|
||||
@Model(core.class.TxPutBag, core.class.TxCUD)
|
||||
|
||||
@@ -62,6 +62,7 @@ export class TApplicant extends TDocWithState implements Applicant {
|
||||
attachedTo!: Ref<Candidate>
|
||||
|
||||
attachedToClass!: Ref<Class<Candidate>>
|
||||
collection!: string
|
||||
|
||||
@Prop(TypeString(), 'Attachments' as IntlString)
|
||||
attachments?: number
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import type { Class, Obj, Ref } from '../classes'
|
||||
import type { Class, Obj, Ref, Doc } from '../classes'
|
||||
import core from '../component'
|
||||
import { Hierarchy } from '../hierarchy'
|
||||
import { ModelDb, TxDb } from '../memdb'
|
||||
@@ -23,24 +23,37 @@ import { genMinModel, test, TestMixin } from './minmodel'
|
||||
|
||||
const txes = genMinModel()
|
||||
|
||||
async function createModel (): Promise<{ model: ModelDb, hierarchy: Hierarchy }> {
|
||||
async function createModel (): Promise<{ model: ModelDb, hierarchy: Hierarchy, txDb: TxDb }> {
|
||||
const hierarchy = new Hierarchy()
|
||||
for (const tx of txes) hierarchy.tx(tx)
|
||||
for (const tx of txes) {
|
||||
hierarchy.tx(tx)
|
||||
}
|
||||
const model = new ModelDb(hierarchy)
|
||||
for (const tx of txes) await model.tx(tx)
|
||||
return { model, hierarchy }
|
||||
for (const tx of txes) {
|
||||
await model.tx(tx)
|
||||
}
|
||||
const txDb = new TxDb(hierarchy)
|
||||
for (const tx of txes) await txDb.tx(tx)
|
||||
return { model, hierarchy, txDb }
|
||||
}
|
||||
|
||||
describe('memdb', () => {
|
||||
it('should save all tx', async () => {
|
||||
const hierarchy = new Hierarchy()
|
||||
for (const tx of txes) hierarchy.tx(tx)
|
||||
const txDb = new TxDb(hierarchy)
|
||||
for (const tx of txes) await txDb.tx(tx)
|
||||
const { txDb } = await createModel()
|
||||
|
||||
const result = await txDb.findAll(core.class.Tx, {})
|
||||
expect(result.length).toBe(txes.filter((tx) => tx._class === core.class.TxCreateDoc).length)
|
||||
})
|
||||
|
||||
it('should query model', async () => {
|
||||
const { model } = await createModel()
|
||||
|
||||
const result = await model.findAll(core.class.Class, {})
|
||||
expect(result.length).toBeGreaterThan(5)
|
||||
const result2 = await model.findAll('class:workbench.Application' as Ref<Class<Doc>>, { _id: undefined })
|
||||
expect(result2).toHaveLength(0)
|
||||
})
|
||||
|
||||
it('should create space', async () => {
|
||||
const { model } = await createModel()
|
||||
|
||||
@@ -65,7 +78,8 @@ describe('memdb', () => {
|
||||
it('should query model', async () => {
|
||||
const { model } = await createModel()
|
||||
const result = await model.findAll(core.class.Class, {})
|
||||
expect(result.length).toBe(10)
|
||||
const names = result.map(d => d._id)
|
||||
expect(names.includes(core.class.Class)).toBe(true)
|
||||
const result2 = await model.findAll(core.class.Class, { _id: undefined })
|
||||
expect(result2.length).toBe(0)
|
||||
})
|
||||
@@ -103,10 +117,7 @@ describe('memdb', () => {
|
||||
})
|
||||
|
||||
it('should query model with params', async () => {
|
||||
const hierarchy = new Hierarchy()
|
||||
for (const tx of txes) hierarchy.tx(tx)
|
||||
const model = new ModelDb(hierarchy)
|
||||
for (const tx of txes) await model.tx(tx)
|
||||
const { model } = await createModel()
|
||||
const first = await model.findAll(core.class.Class, {
|
||||
_id: txes[1].objectId as Ref<Class<Obj>>,
|
||||
kind: 0
|
||||
@@ -132,10 +143,7 @@ describe('memdb', () => {
|
||||
})
|
||||
|
||||
it('should query model like params', async () => {
|
||||
const hierarchy = new Hierarchy()
|
||||
for (const tx of txes) hierarchy.tx(tx)
|
||||
const model = new ModelDb(hierarchy)
|
||||
for (const tx of txes) await model.tx(tx)
|
||||
const { model } = await createModel()
|
||||
const expectedLength = txes.filter((tx) => tx.objectSpace === core.space.Model).length
|
||||
const without = await model.findAll(core.class.Doc, {
|
||||
space: { $like: core.space.Model }
|
||||
@@ -205,34 +213,17 @@ describe('memdb', () => {
|
||||
expect(numberSort[0].modifiedOn).toBeLessThanOrEqual(numberSort[numberSortDesc.length - 1].modifiedOn)
|
||||
})
|
||||
|
||||
// it('should throw error', async () => {
|
||||
// expect.assertions(1)
|
||||
// const errorTx: TxAddCollection<Doc, Emb> = {
|
||||
// _id: '60b73133d22498e666800cd2' as Ref<TxAddCollection<Doc, Emb>>,
|
||||
// _class: 'class:core.TxAddCollection' as Ref<Class<TxAddCollection<Doc, Emb>>>,
|
||||
// space: core.space.Tx,
|
||||
// modifiedBy: 'xxx' as Ref<Account>,
|
||||
// modifiedOn: 0,
|
||||
// objectId: 'class:test.MyClass' as Ref<Doc>,
|
||||
// objectSpace: core.space.Model,
|
||||
// itemClass: 'class:core.Attribute' as Ref<Class<Doc>>,
|
||||
// collection: 'attributes',
|
||||
// localId: 'name',
|
||||
// attributes: {
|
||||
// _class: 'class:core.Attribute' as Ref<Class<Doc>>,
|
||||
// // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
// __embedded: {
|
||||
// _class: 'class:core.Attribute' as Ref<Class<Doc>>
|
||||
// } as Emb
|
||||
// }
|
||||
// }
|
||||
it('should add attached document', async () => {
|
||||
const { model } = await createModel()
|
||||
|
||||
// const hierarchy = new Hierarchy()
|
||||
// for (const tx of txes) hierarchy.tx(tx)
|
||||
// const model = new ModelDb(hierarchy)
|
||||
const client = new TxOperations(model, core.account.System)
|
||||
const result = await client.findAll(core.class.Space, {})
|
||||
expect(result).toHaveLength(2)
|
||||
|
||||
// await model.tx(errorTx).catch((error: Error) => {
|
||||
// expect(error.message).toBe('ERROR: status:core.ObjectNotFound')
|
||||
// })
|
||||
// })
|
||||
await client.addCollection(test.class.TestComment, core.space.Model, result[0]._id, result[0]._class, 'comments', {
|
||||
message: 'msg'
|
||||
})
|
||||
const result2 = await client.findAll(test.class.TestComment, {})
|
||||
expect(result2).toHaveLength(1)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -13,12 +13,12 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import type { Plugin, IntlString } from '@anticrm/platform'
|
||||
import type { IntlString, Plugin } from '@anticrm/platform'
|
||||
import { plugin } from '@anticrm/platform'
|
||||
import type { Class, Data, Doc, Obj, Ref, Mixin, Arr } from '../classes'
|
||||
import { ClassifierKind, DOMAIN_MODEL } from '../classes'
|
||||
import type { TxCUD, TxCreateDoc } from '../tx'
|
||||
import type { Arr, Class, Data, Doc, Mixin, Obj, Ref } from '../classes'
|
||||
import { AttachedDoc, ClassifierKind, DOMAIN_MODEL } from '../classes'
|
||||
import core from '../component'
|
||||
import type { TxCreateDoc, TxCUD } from '../tx'
|
||||
import { DOMAIN_TX, TxFactory } from '../tx'
|
||||
|
||||
const txFactory = new TxFactory(core.account.System)
|
||||
@@ -35,9 +35,16 @@ export interface TestMixin extends Doc {
|
||||
arr: Arr<string>
|
||||
}
|
||||
|
||||
export interface AttachedComment extends AttachedDoc {
|
||||
message: string
|
||||
}
|
||||
|
||||
export const test = plugin('test' as Plugin, {
|
||||
mixin: {
|
||||
TestMixin: '' as Ref<Mixin<TestMixin>>
|
||||
},
|
||||
class: {
|
||||
TestComment: '' as Ref<Class<AttachedComment>>
|
||||
}
|
||||
})
|
||||
|
||||
@@ -50,17 +57,22 @@ export function genMinModel (): TxCUD<Doc>[] {
|
||||
// Fill Tx'es with basic model classes.
|
||||
txes.push(createClass(core.class.Obj, { label: 'Obj' as IntlString, kind: ClassifierKind.CLASS }))
|
||||
txes.push(createClass(core.class.Doc, { label: 'Doc' as IntlString, extends: core.class.Obj, kind: ClassifierKind.CLASS }))
|
||||
txes.push(createClass(core.class.AttachedDoc, { label: 'AttachedDoc' as IntlString, extends: core.class.Doc, kind: ClassifierKind.MIXIN }))
|
||||
txes.push(createClass(core.class.Class, { label: 'Class' as IntlString, extends: core.class.Doc, kind: ClassifierKind.CLASS, domain: DOMAIN_MODEL }))
|
||||
txes.push(createClass(core.class.Space, { label: 'Space' as IntlString, extends: core.class.Doc, kind: ClassifierKind.CLASS, domain: DOMAIN_MODEL }))
|
||||
txes.push(createClass(core.class.Account, { label: 'Account' as IntlString, extends: core.class.Doc, kind: ClassifierKind.CLASS, domain: DOMAIN_MODEL }))
|
||||
|
||||
txes.push(createClass(core.class.Tx, { label: 'Tx' as IntlString, extends: core.class.Doc, kind: ClassifierKind.CLASS, domain: DOMAIN_TX }))
|
||||
txes.push(createClass(core.class.TxCreateDoc, { label: 'TxCreateDoc' as IntlString, extends: core.class.Tx, kind: ClassifierKind.CLASS }))
|
||||
txes.push(createClass(core.class.TxUpdateDoc, { label: 'TxUpdateDoc' as IntlString, extends: core.class.Tx, kind: ClassifierKind.CLASS }))
|
||||
txes.push(createClass(core.class.TxRemoveDoc, { label: 'TxRemoveDoc' as IntlString, extends: core.class.Tx, kind: ClassifierKind.CLASS }))
|
||||
txes.push(createClass(core.class.TxCUD, { label: 'TxCUD' as IntlString, extends: core.class.Tx, kind: ClassifierKind.CLASS, domain: DOMAIN_TX }))
|
||||
txes.push(createClass(core.class.TxCreateDoc, { label: 'TxCreateDoc' as IntlString, extends: core.class.TxCUD, kind: ClassifierKind.CLASS }))
|
||||
txes.push(createClass(core.class.TxUpdateDoc, { label: 'TxUpdateDoc' as IntlString, extends: core.class.TxCUD, kind: ClassifierKind.CLASS }))
|
||||
txes.push(createClass(core.class.TxRemoveDoc, { label: 'TxRemoveDoc' as IntlString, extends: core.class.TxCUD, kind: ClassifierKind.CLASS }))
|
||||
txes.push(createClass(core.class.TxCollectionCUD, { label: 'TxCollectionCUD' as IntlString, extends: core.class.TxCUD, kind: ClassifierKind.CLASS }))
|
||||
|
||||
txes.push(createClass(test.mixin.TestMixin, { label: 'TestMixin' as IntlString, extends: core.class.Doc, kind: ClassifierKind.MIXIN }))
|
||||
|
||||
txes.push(createClass(test.class.TestComment, { label: 'TestComment' as IntlString, extends: core.class.AttachedDoc, kind: ClassifierKind.CLASS }))
|
||||
|
||||
txes.push(
|
||||
createDoc(core.class.Space, {
|
||||
name: 'Sp1',
|
||||
|
||||
@@ -67,6 +67,7 @@ export interface UXObject extends Obj {
|
||||
export interface AttachedDoc extends Doc {
|
||||
attachedTo: Ref<Doc>
|
||||
attachedToClass: Ref<Class<Doc>>
|
||||
collection: string
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
import type { Plugin, StatusCode } from '@anticrm/platform'
|
||||
import { plugin } from '@anticrm/platform'
|
||||
import type { Account, Class, Doc, Obj, Ref, Space, AnyAttribute, State, Type, PropertyType, SpaceWithStates, Timestamp, DocWithState, AttachedDoc } from './classes'
|
||||
import type { Tx, TxAddCollection, TxBulkWrite, TxCreateDoc, TxCUD, TxMixin, TxPutBag, TxRemoveDoc, TxUpdateDoc } from './tx'
|
||||
import type { Tx, TxCollectionCUD, TxBulkWrite, TxCreateDoc, TxCUD, TxMixin, TxPutBag, TxRemoveDoc, TxUpdateDoc } from './tx'
|
||||
|
||||
/**
|
||||
* @public
|
||||
@@ -26,13 +26,14 @@ export default plugin(coreId, {
|
||||
class: {
|
||||
Obj: '' as Ref<Class<Obj>>,
|
||||
Doc: '' as Ref<Class<Doc>>,
|
||||
AttachedDoc: '' as Ref<Class<AttachedDoc>>,
|
||||
Class: '' as Ref<Class<Class<Obj>>>,
|
||||
Attribute: '' as Ref<Class<AnyAttribute>>,
|
||||
Tx: '' as Ref<Class<Tx>>,
|
||||
TxBulkWrite: '' as Ref<Class<TxBulkWrite>>,
|
||||
TxCUD: '' as Ref<Class<TxCUD<Doc>>>,
|
||||
TxCreateDoc: '' as Ref<Class<TxCreateDoc<Doc>>>,
|
||||
TxAddCollection: '' as Ref<Class<TxAddCollection<AttachedDoc>>>,
|
||||
TxCollectionCUD: '' as Ref<Class<TxCollectionCUD<Doc, AttachedDoc>>>,
|
||||
TxMixin: '' as Ref<Class<TxMixin<Doc, Doc>>>,
|
||||
TxUpdateDoc: '' as Ref<Class<TxUpdateDoc<Doc>>>,
|
||||
TxRemoveDoc: '' as Ref<Class<TxRemoveDoc<Doc>>>,
|
||||
|
||||
+67
-24
@@ -42,12 +42,14 @@ export interface TxCreateDoc<T extends Doc> extends TxCUD<T> {
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Will perform create/update/delete of attached documents.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface TxAddCollection<T extends AttachedDoc> extends TxCreateDoc<T> {
|
||||
export interface TxCollectionCUD<T extends Doc, P extends AttachedDoc> extends TxCUD<T> {
|
||||
collection: string
|
||||
attachedTo: Ref<Doc>
|
||||
attachedToClass: Ref<Class<Doc>>
|
||||
tx: TxCUD<P>
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -193,8 +195,8 @@ export abstract class TxProcessor implements WithTx {
|
||||
switch (tx._class) {
|
||||
case core.class.TxCreateDoc:
|
||||
return await this.txCreateDoc(tx as TxCreateDoc<Doc>)
|
||||
case core.class.TxAddCollection:
|
||||
return await this.txAddCollection(tx as TxAddCollection<AttachedDoc>)
|
||||
case core.class.TxCollectionCUD:
|
||||
return await this.txCollectionCUD(tx as TxCollectionCUD<Doc, AttachedDoc>)
|
||||
case core.class.TxUpdateDoc:
|
||||
return await this.txUpdateDoc(tx as TxUpdateDoc<Doc>)
|
||||
case core.class.TxRemoveDoc:
|
||||
@@ -209,7 +211,7 @@ export abstract class TxProcessor implements WithTx {
|
||||
throw new Error('TxProcessor: unhandled transaction class: ' + tx._class)
|
||||
}
|
||||
|
||||
static createDoc2Doc<T extends Doc> (tx: TxCreateDoc<T>): T {
|
||||
static createDoc2Doc<T extends Doc>(tx: TxCreateDoc<T>): T {
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
return {
|
||||
_id: tx.objectId,
|
||||
@@ -227,15 +229,26 @@ export abstract class TxProcessor implements WithTx {
|
||||
protected abstract txRemoveDoc (tx: TxRemoveDoc<Doc>): Promise<TxResult>
|
||||
protected abstract txMixin (tx: TxMixin<Doc, Doc>): Promise<TxResult>
|
||||
|
||||
protected txAddCollection (tx: TxAddCollection<AttachedDoc>): Promise<TxResult> {
|
||||
const createTx: TxCreateDoc<Doc> = { ...tx }
|
||||
createTx.attributes = { ...tx.attributes, attachedTo: tx.attachedTo, attachedToClass: tx.attachedToClass }
|
||||
return this.txCreateDoc(createTx)
|
||||
protected txCollectionCUD (tx: TxCollectionCUD<Doc, AttachedDoc>): Promise<TxResult> {
|
||||
// We need update only create transactions to contain attached, attachedToClass.
|
||||
if (tx.tx._class === core.class.TxCreateDoc) {
|
||||
const createTx = tx.tx as TxCreateDoc<AttachedDoc>
|
||||
const d: TxCreateDoc<AttachedDoc> = {
|
||||
...createTx,
|
||||
attributes: {
|
||||
...createTx.attributes,
|
||||
attachedTo: tx.objectId,
|
||||
attachedToClass: tx.objectClass,
|
||||
collection: tx.collection
|
||||
}
|
||||
}
|
||||
return this.txCreateDoc(d)
|
||||
}
|
||||
return this.tx(tx.tx)
|
||||
}
|
||||
|
||||
protected async txBulkWrite (bulkTx: TxBulkWrite): Promise<TxResult> {
|
||||
for (const tx of bulkTx.txes) {
|
||||
console.log('bulk', tx)
|
||||
await this.tx(tx)
|
||||
}
|
||||
return {}
|
||||
@@ -275,16 +288,42 @@ export class TxOperations implements Storage {
|
||||
return tx.objectId
|
||||
}
|
||||
|
||||
async addCollection<T extends AttachedDoc> (
|
||||
_class: Ref<Class<T>>,
|
||||
async addCollection<T extends Doc, P extends AttachedDoc>(
|
||||
_class: Ref<Class<P>>,
|
||||
space: Ref<Space>,
|
||||
attachedTo: Ref<Doc>,
|
||||
attachedToClass: Ref<Class<Doc>>,
|
||||
attachedTo: Ref<T>,
|
||||
attachedToClass: Ref<Class<T>>,
|
||||
collection: string,
|
||||
attributes: AttachedData<T>,
|
||||
id?: Ref<T>
|
||||
attributes: AttachedData<P>,
|
||||
id?: Ref<P>
|
||||
): Promise<Ref<T>> {
|
||||
const tx = this.txFactory.createTxAddCollection(_class, space, attributes, attachedTo, attachedToClass, collection, id)
|
||||
const tx = this.txFactory.createTxCollectionCUD<T, P>(
|
||||
attachedToClass,
|
||||
attachedTo,
|
||||
space,
|
||||
collection,
|
||||
this.txFactory.createTxCreateDoc<P>(_class, space, attributes as unknown as Data<P>, id)
|
||||
)
|
||||
await this.storage.tx(tx)
|
||||
return tx.objectId
|
||||
}
|
||||
|
||||
async updateCollection<T extends Doc, P extends AttachedDoc>(
|
||||
_class: Ref<Class<P>>,
|
||||
space: Ref<Space>,
|
||||
objectId: Ref<P>,
|
||||
attachedTo: Ref<T>,
|
||||
attachedToClass: Ref<Class<T>>,
|
||||
collection: string,
|
||||
operations: DocumentUpdate<P>
|
||||
): Promise<Ref<T>> {
|
||||
const tx = this.txFactory.createTxCollectionCUD(
|
||||
attachedToClass,
|
||||
attachedTo,
|
||||
space,
|
||||
collection,
|
||||
this.txFactory.createTxUpdateDoc(_class, space, objectId, operations)
|
||||
)
|
||||
await this.storage.tx(tx)
|
||||
return tx.objectId
|
||||
}
|
||||
@@ -352,20 +391,24 @@ export class TxFactory {
|
||||
}
|
||||
}
|
||||
|
||||
createTxAddCollection<T extends AttachedDoc>(_class: Ref<Class<T>>, space: Ref<Space>, attributes: AttachedData<T>, attachedTo: Ref<Doc>, attachedToClass: Ref<Class<Doc>>, collection: string, objectId?: Ref<T>): TxAddCollection<T> {
|
||||
createTxCollectionCUD<T extends Doc, P extends AttachedDoc>(
|
||||
_class: Ref<Class<T>>,
|
||||
objectId: Ref<T>,
|
||||
space: Ref<Space>,
|
||||
collection: string,
|
||||
tx: TxCUD<P>
|
||||
): TxCollectionCUD<T, P> {
|
||||
return {
|
||||
_id: generateId(),
|
||||
_class: core.class.TxAddCollection,
|
||||
_class: core.class.TxCollectionCUD,
|
||||
space: core.space.Tx,
|
||||
objectId: objectId ?? generateId(),
|
||||
objectId,
|
||||
objectClass: _class,
|
||||
objectSpace: space,
|
||||
modifiedOn: Date.now(),
|
||||
modifiedBy: this.account,
|
||||
attributes: attributes as Data<T>,
|
||||
collection,
|
||||
attachedTo,
|
||||
attachedToClass
|
||||
tx
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,13 +15,13 @@
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import type { IntlString, Asset } from '@anticrm/platform'
|
||||
import type { Asset } from '@anticrm/platform'
|
||||
import type { Doc } from '@anticrm/core'
|
||||
import { SortingOrder } from '@anticrm/core'
|
||||
import { getClient, createQuery, Backlink } from '@anticrm/presentation'
|
||||
import type { AnySvelteComponent } from '@anticrm/ui'
|
||||
import { ReferenceInput } from '@anticrm/text-editor'
|
||||
import { IconClose, IconExpand, IconActivity, ScrollBox, Grid, Label, Icon, IconToDo } from '@anticrm/ui'
|
||||
import { IconClose, IconExpand, IconActivity, ScrollBox, Grid, Icon, IconToDo } from '@anticrm/ui'
|
||||
import type { Comment } from '@anticrm/chunter'
|
||||
import ActivityMsg from './ActivityMsg.svelte'
|
||||
|
||||
@@ -43,9 +43,7 @@
|
||||
$: query.query(chunter.class.Comment, { attachedTo: object._id }, result => { comments = result }, { sort: { modifiedOn: SortingOrder.Descending } })
|
||||
|
||||
function onMessage(event: CustomEvent) {
|
||||
client.createDoc(chunter.class.Comment, object.space, {
|
||||
attachedTo: object._id,
|
||||
attachedToClass: object._class,
|
||||
client.addCollection(chunter.class.Comment, object.space, object._id, object._class, 'comments', {
|
||||
message: event.detail
|
||||
})
|
||||
console.log(event.detail)
|
||||
|
||||
@@ -75,9 +75,7 @@
|
||||
console.log('resume name', resume.name)
|
||||
|
||||
if (resume.uuid !== undefined) {
|
||||
client.createDoc(chunter.class.Attachment, space, {
|
||||
attachedTo: id,
|
||||
attachedToClass: recruit.class.Candidate,
|
||||
client.addCollection(chunter.class.Attachment, space, id, recruit.class.Candidate, 'attachments', {
|
||||
name: resume.name,
|
||||
file: resume.uuid,
|
||||
size: resume.size,
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import type { Ref, Class, Doc, Space, SpaceWithStates, FindOptions, State, TxBulkWrite, TxCUD } from '@anticrm/core'
|
||||
import type { Ref, Class, Doc, Space, SpaceWithStates, FindOptions, State, TxBulkWrite, TxCUD, AttachedDoc } from '@anticrm/core'
|
||||
import { getResource } from '@anticrm/platform'
|
||||
import { buildModel } from '../utils'
|
||||
import { getClient } from '@anticrm/presentation'
|
||||
@@ -81,7 +81,13 @@
|
||||
const txes: TxCUD<Doc>[] = []
|
||||
|
||||
if (dragCardInitialState !== state) {
|
||||
client.updateDoc(_class, space, id, { state })
|
||||
if (client.getHierarchy().isDerived(_class, core.class.AttachedDoc)) {
|
||||
const adoc: AttachedDoc = dragCard as AttachedDoc
|
||||
// We need to update using updateCollection
|
||||
client.updateCollection(_class, space, id as Ref<AttachedDoc>, adoc.attachedTo, adoc.attachedToClass, adoc.collection, { state })
|
||||
} else {
|
||||
client.updateDoc(_class, space, id, { state })
|
||||
}
|
||||
// txes.push(client.txFactory.createTxUpdateDoc(_class, space, id, { state }))
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import type { Tx, TxCreateDoc, Data, Ref, Doc, TxFactory, Class } from '@anticrm/core'
|
||||
import type { Tx, TxCreateDoc, Data, Ref, Doc, TxFactory, Class, TxCollectionCUD, AttachedDoc } from '@anticrm/core'
|
||||
import type { FindAll } from '@anticrm/server-core'
|
||||
import type { Message, Backlink } from '@anticrm/chunter'
|
||||
import { parse, Node, HTMLElement } from 'node-html-parser'
|
||||
@@ -29,6 +29,7 @@ function extractBacklinks (backlinkId: Ref<Doc>, message: string, kids: Node[]):
|
||||
result.push({
|
||||
attachedTo: (kid as HTMLElement).getAttribute('data-id') as Ref<Doc>,
|
||||
attachedToClass: (kid as HTMLElement).getAttribute('data-class') as Ref<Class<Doc>>,
|
||||
collection: (kid as HTMLElement).getAttribute('data-collection') ?? '',
|
||||
backlinkId,
|
||||
backlinkClass: chunter.class.Message,
|
||||
message
|
||||
@@ -48,6 +49,9 @@ function getBacklinks (backlinkId: Ref<Doc>, content: string): Data<Backlink>[]
|
||||
* @public
|
||||
*/
|
||||
export async function OnMessage (tx: Tx, txFactory: TxFactory): Promise<Tx[]> {
|
||||
if (tx._class === core.class.TxCollectionCUD) {
|
||||
tx = (tx as TxCollectionCUD<Doc, AttachedDoc>).tx
|
||||
}
|
||||
if (tx._class === core.class.TxCreateDoc) {
|
||||
const createTx = tx as TxCreateDoc<Message>
|
||||
if (createTx.objectClass === chunter.class.Message) {
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import type { ServerStorage, Domain, Tx, TxCUD, Doc, Ref, Class, DocumentQuery, FindResult, FindOptions, Storage, TxBulkWrite, TxResult, TxAddCollection, AttachedDoc } from '@anticrm/core'
|
||||
import type { ServerStorage, Domain, Tx, TxCUD, Doc, Ref, Class, DocumentQuery, FindResult, FindOptions, Storage, TxBulkWrite, TxResult, TxCollectionCUD, AttachedDoc } from '@anticrm/core'
|
||||
import core, { Hierarchy, DOMAIN_TX, ModelDb, TxFactory } from '@anticrm/core'
|
||||
import type { FullTextAdapterFactory, FullTextAdapter } from './types'
|
||||
import { FullTextIndex } from './fulltext'
|
||||
@@ -107,13 +107,16 @@ class TServerStorage implements ServerStorage {
|
||||
}
|
||||
|
||||
async processCollection (tx: Tx): Promise<Tx[]> {
|
||||
if (tx._class === core.class.TxAddCollection) {
|
||||
const createTx = tx as TxAddCollection<AttachedDoc>
|
||||
const _id = createTx.attachedTo
|
||||
const _class = createTx.attachedToClass
|
||||
const attachedTo = (await this.findAll(_class, { _id }))[0]
|
||||
const txFactory = new TxFactory(tx.modifiedBy)
|
||||
return [txFactory.createTxUpdateDoc(_class, attachedTo.space, _id, { $inc: { [createTx.collection]: 1 } })]
|
||||
if (tx._class === core.class.TxCollectionCUD) {
|
||||
const colTx = tx as TxCollectionCUD<Doc, AttachedDoc>
|
||||
const _id = colTx.objectId
|
||||
const _class = colTx.objectClass
|
||||
let attachedTo: Doc | undefined
|
||||
if (colTx.tx._class === core.class.TxCreateDoc) {
|
||||
attachedTo = (await this.findAll(_class, { _id }))[0]
|
||||
const txFactory = new TxFactory(tx.modifiedBy)
|
||||
return [txFactory.createTxUpdateDoc(_class, attachedTo.space, _id, { $inc: { [colTx.collection]: 1 } })]
|
||||
}
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import type { Tx, Doc, TxCreateDoc, Ref, Account, Hierarchy } from '@anticrm/core'
|
||||
import type { Tx, Doc, TxCreateDoc, Ref, Account, Hierarchy, TxCollectionCUD, AttachedDoc } from '@anticrm/core'
|
||||
import core, { TxFactory } from '@anticrm/core'
|
||||
|
||||
import { getResource } from '@anticrm/platform'
|
||||
@@ -29,6 +29,9 @@ export class Triggers {
|
||||
private readonly triggers: TriggerFunc[] = []
|
||||
|
||||
async tx (tx: Tx): Promise<void> {
|
||||
if (tx._class === core.class.TxCollectionCUD) {
|
||||
tx = (tx as TxCollectionCUD<Doc, AttachedDoc>).tx
|
||||
}
|
||||
if (tx._class === core.class.TxCreateDoc) {
|
||||
const createTx = tx as TxCreateDoc<Doc>
|
||||
if (createTx.objectClass === serverCore.class.Trigger) {
|
||||
|
||||
@@ -19,9 +19,9 @@
|
||||
"eslint":"^7.32.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@anticrm/core": "~0.6.11",
|
||||
"@anticrm/core": "~0.6.12",
|
||||
"@anticrm/platform": "~0.6.5",
|
||||
"@anticrm/server-core": "~0.6.0",
|
||||
"@anticrm/server-core": "~0.6.1",
|
||||
"@anticrm/view": "~0.6.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import type { Tx, TxFactory, Doc, TxCreateDoc, DocWithState, State, TxRemoveDoc } from '@anticrm/core'
|
||||
import type { Tx, TxFactory, Doc, TxCreateDoc, DocWithState, State, TxRemoveDoc, TxCollectionCUD, AttachedDoc } from '@anticrm/core'
|
||||
import type { FindAll } from '@anticrm/server-core'
|
||||
|
||||
import core, { Hierarchy } from '@anticrm/core'
|
||||
@@ -24,6 +24,10 @@ import view, { Kanban } from '@anticrm/view'
|
||||
* @public
|
||||
*/
|
||||
export async function OnDocWithState (tx: Tx, txFactory: TxFactory, findAll: FindAll<Doc>, hierarchy: Hierarchy): Promise<Tx[]> {
|
||||
if (tx._class === core.class.TxCollectionCUD) {
|
||||
tx = (tx as TxCollectionCUD<Doc, AttachedDoc>).tx
|
||||
}
|
||||
|
||||
if (hierarchy.isDerived(tx._class, core.class.TxCreateDoc)) {
|
||||
const createTx = tx as TxCreateDoc<DocWithState>
|
||||
if (hierarchy.isDerived(createTx.objectClass, core.class.DocWithState)) {
|
||||
|
||||
+340
-326
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user