Model lookup ()

Signed-off-by: Andrey Platov <andrey@hardcoreeng.com>
This commit is contained in:
Andrey Platov 2021-10-13 10:38:35 +02:00 committed by GitHub
parent 56deb3a4b0
commit 771188e72f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 1010 additions and 876 deletions
dev
storage/src
tool/src
models/core/src
plugins
recruit-resources
view-resources/src
server
core/src
mongo/src
server/src
workspace/src

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -26,7 +26,9 @@ export const DOMAIN_STATE = 'state' as Domain
@Model(core.class.Space, core.class.Doc, DOMAIN_MODEL)
export class TSpace extends TDoc implements Space {
@Prop(TypeString(), 'Name' as IntlString)
name!: string
description!: string
private!: boolean
members!: Arr<Ref<Account>>

View File

@ -31,6 +31,7 @@
"deep-equal": "^2.0.5",
"@anticrm/panel": "~0.6.0",
"@anticrm/chunter-resources": "~0.6.0",
"@anticrm/view": "~0.6.0"
"@anticrm/view": "~0.6.0",
"@anticrm/view-resources": "~0.6.0"
}
}

View File

@ -28,8 +28,9 @@
import Edit from './icons/Edit.svelte'
import SocialEditor from './SocialEditor.svelte'
import AttributesBar from './AttributesBar.svelte'
import { TableView } from '@anticrm/view-resources'
import chunter from '@anticrm/chunter'
import core from '@anticrm/core'
import recruit from '../plugin'
import { combineName, formatName, getFirstName, getLastName } from '@anticrm/contact'
@ -88,6 +89,23 @@
</div>
</div>
Applications
<TableView
_class={recruit.class.Applicant}
config={['$lookup.candidate', '$lookup.state', '$lookup.candidate.city', '$lookup.space.name']}
options={
{
lookup: {
candidate: recruit.class.Candidate,
state: core.class.State,
space: core.class.Space
}
}
}
search=""
/>
<div class="attachments">
<Attachments objectId={object._id} _class={object._class} space={object.space} {object}/>
</div>

View File

@ -0,0 +1,24 @@
<!--
// Copyright © 2020, 2021 Anticrm Platform Contributors.
// Copyright © 2021 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. You may
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
-->
<script lang="ts">
import type { Space } from '@anticrm/core'
export let value: Space
</script>
{value.name}

View File

@ -38,7 +38,7 @@
let objects: Doc[]
const query = createQuery()
$: query.query(_class, search === '' ? { space } : { $search: search }, result => { objects = result }, { sort: { [sortKey]: sortOrder }, ...options })
$: query.query(_class, search === '' ? (space ? { space } : {}) : { $search: search }, result => { objects = result }, { sort: { [sortKey]: sortOrder }, ...options })
function getValue(doc: Doc, key: string): any {
if (key.length === 0)

View File

@ -25,6 +25,8 @@ import KanbanView from './components/KanbanView.svelte'
import { getClient } from '@anticrm/presentation'
export { TableView }
async function Delete(object: Doc): Promise<void> {
const client = getClient()
await client.removeDoc(object._class, object.space, object._id)

View File

@ -15,7 +15,7 @@
//
import type { ServerStorage, Domain, Tx, TxCUD, Doc, Ref, Class, DocumentQuery, FindResult, FindOptions, Storage, TxBulkWrite } from '@anticrm/core'
import core, { Hierarchy, DOMAIN_TX } from '@anticrm/core'
import core, { Hierarchy, DOMAIN_TX, ModelDb } from '@anticrm/core'
import type { FullTextAdapterFactory, FullTextAdapter } from './types'
import { FullTextIndex } from './fulltext'
import { Triggers } from './triggers'
@ -40,7 +40,7 @@ export interface TxAdapter extends DbAdapter {
/**
* @public
*/
export type DbAdapterFactory = (hierarchy: Hierarchy, url: string, db: string) => Promise<DbAdapter>
export type DbAdapterFactory = (hierarchy: Hierarchy, url: string, db: string, modelDb: ModelDb) => Promise<DbAdapter>
/**
* @public
@ -73,7 +73,8 @@ class TServerStorage implements ServerStorage {
private readonly adapters: Map<string, DbAdapter>,
private readonly hierarchy: Hierarchy,
private readonly triggers: Triggers,
fulltextAdapter: FullTextAdapter
fulltextAdapter: FullTextAdapter,
private readonly modelDb: ModelDb
) {
this.fulltext = new FullTextIndex(hierarchy, fulltextAdapter, this)
}
@ -125,8 +126,8 @@ class TServerStorage implements ServerStorage {
// maintain hiearachy and triggers
this.hierarchy.tx(tx)
await this.triggers.tx(tx)
return []
} else {
await this.modelDb.tx(tx)
}
// store object
await this.routeTx(tx)
// invoke triggers and store derived objects
@ -144,7 +145,6 @@ class TServerStorage implements ServerStorage {
return derived
}
}
}
/**
* @public
@ -153,10 +153,11 @@ export async function createServerStorage (conf: DbConfiguration): Promise<Serve
const hierarchy = new Hierarchy()
const triggers = new Triggers()
const adapters = new Map<string, DbAdapter>()
const modelDb = new ModelDb(hierarchy)
for (const key in conf.adapters) {
const adapterConf = conf.adapters[key]
adapters.set(key, await adapterConf.factory(hierarchy, adapterConf.url, conf.workspace))
adapters.set(key, await adapterConf.factory(hierarchy, adapterConf.url, conf.workspace, modelDb))
}
const txAdapter = adapters.get(conf.domains[DOMAIN_TX]) as TxAdapter
@ -171,11 +172,15 @@ export async function createServerStorage (conf: DbConfiguration): Promise<Serve
await triggers.tx(tx)
}
for (const tx of model) {
await modelDb.tx(tx)
}
for (const [, adapter] of adapters) {
await adapter.init(model)
}
const fulltextAdapter = await conf.fulltextAdapter.factory(conf.fulltextAdapter.url, conf.workspace)
return new TServerStorage(conf.domains, conf.defaultAdapter, adapters, hierarchy, triggers, fulltextAdapter)
return new TServerStorage(conf.domains, conf.defaultAdapter, adapters, hierarchy, triggers, fulltextAdapter, modelDb)
}

View File

@ -14,7 +14,7 @@
//
import type { Tx, Ref, Doc, Class, DocumentQuery, FindResult, FindOptions, TxCreateDoc, TxUpdateDoc, TxMixin, TxPutBag, TxRemoveDoc } from '@anticrm/core'
import core, { DOMAIN_TX, SortingOrder, TxProcessor, Hierarchy, isOperator } from '@anticrm/core'
import core, { DOMAIN_TX, DOMAIN_MODEL, SortingOrder, TxProcessor, Hierarchy, isOperator, ModelDb } from '@anticrm/core'
import type { DbAdapter, TxAdapter } from '@anticrm/server-core'
@ -27,7 +27,8 @@ function translateDoc (doc: Doc): Document {
abstract class MongoAdapterBase extends TxProcessor {
constructor (
protected readonly db: Db,
protected readonly hierarchy: Hierarchy
protected readonly hierarchy: Hierarchy,
protected readonly modelDb: ModelDb
) {
super()
}
@ -63,14 +64,17 @@ abstract class MongoAdapterBase extends TxProcessor {
const lookups = options.lookup as any
for (const key in lookups) {
const clazz = lookups[key]
const domain = this.hierarchy.getDomain(clazz)
if (domain !== DOMAIN_MODEL) {
const step = {
from: this.hierarchy.getDomain(clazz),
from: domain,
localField: key,
foreignField: '_id',
as: key + '_lookup'
}
pipeline.push({ $lookup: step })
}
}
const domain = this.hierarchy.getDomain(clazz)
const cursor = this.db.collection(domain).aggregate(pipeline)
const result = await cursor.toArray() as FindResult<T>
@ -78,8 +82,14 @@ abstract class MongoAdapterBase extends TxProcessor {
const object = row as any
object.$lookup = {}
for (const key in lookups) {
const clazz = lookups[key]
const domain = this.hierarchy.getDomain(clazz)
if (domain !== DOMAIN_MODEL) {
const arr = object[key + '_lookup']
object.$lookup[key] = arr[0]
} else {
object.$lookup[key] = this.modelDb.getObject(object[key])
}
}
}
return result
@ -214,19 +224,19 @@ class MongoTxAdapter extends MongoAdapterBase implements TxAdapter {
/**
* @public
*/
export async function createMongoAdapter (hierarchy: Hierarchy, url: string, dbName: string): Promise<DbAdapter> {
export async function createMongoAdapter (hierarchy: Hierarchy, url: string, dbName: string, modelDb: ModelDb): Promise<DbAdapter> {
const client = new MongoClient(url)
await client.connect()
const db = client.db(dbName)
return new MongoAdapter(db, hierarchy)
return new MongoAdapter(db, hierarchy, modelDb)
}
/**
* @public
*/
export async function createMongoTxAdapter (hierarchy: Hierarchy, url: string, dbName: string): Promise<TxAdapter> {
export async function createMongoTxAdapter (hierarchy: Hierarchy, url: string, dbName: string, modelDb: ModelDb): Promise<TxAdapter> {
const client = new MongoClient(url)
await client.connect()
const db = client.db(dbName)
return new MongoTxAdapter(db, hierarchy)
return new MongoTxAdapter(db, hierarchy, modelDb)
}

View File

@ -14,18 +14,28 @@
// limitations under the License.
//
import { DOMAIN_TX } from '@anticrm/core'
import { Class, Doc, DocumentQuery, DOMAIN_MODEL, DOMAIN_TX, FindOptions, FindResult, Hierarchy, ModelDb, Ref, Tx } from '@anticrm/core'
import { start as startJsonRpc } from '@anticrm/server-ws'
import { createMongoAdapter, createMongoTxAdapter } from '@anticrm/mongo'
import { createElasticAdapter } from '@anticrm/elastic'
import { createServerStorage } from '@anticrm/server-core'
import type { DbConfiguration } from '@anticrm/server-core'
import type { DbConfiguration, DbAdapter } from '@anticrm/server-core'
import { addLocation } from '@anticrm/platform'
import { serverChunterId } from '@anticrm/server-chunter'
import { serverRecruitId } from '@anticrm/server-recruit'
import { serverViewId } from '@anticrm/server-view'
class NullDbAdapter implements DbAdapter {
async init (model: Tx[]): Promise<void> {}
async findAll <T extends Doc>(_class: Ref<Class<T>>, query: DocumentQuery<T>, options?: FindOptions<T> | undefined): Promise<FindResult<T>> { return [] }
async tx (tx: Tx): Promise<void> {}
}
async function createNullAdapter (hierarchy: Hierarchy, url: string, db: string, modelDb: ModelDb): Promise<DbAdapter> {
return new NullDbAdapter()
}
/**
* @public
*/
@ -37,7 +47,8 @@ export async function start (dbUrl: string, fullTextUrl: string, port: number, h
startJsonRpc((workspace: string) => {
const conf: DbConfiguration = {
domains: {
[DOMAIN_TX]: 'MongoTx'
[DOMAIN_TX]: 'MongoTx',
[DOMAIN_MODEL]: 'Null'
},
defaultAdapter: 'Mongo',
adapters: {
@ -48,6 +59,10 @@ export async function start (dbUrl: string, fullTextUrl: string, port: number, h
Mongo: {
factory: createMongoAdapter,
url: dbUrl
},
Null: {
factory: createNullAdapter,
url: ''
}
},
fulltextAdapter: {

File diff suppressed because it is too large Load Diff