mirror of
https://github.com/hcengineering/platform.git
synced 2024-11-26 13:47:26 +03:00
Model lookup (#259)
Signed-off-by: Andrey Platov <andrey@hardcoreeng.com>
This commit is contained in:
parent
56deb3a4b0
commit
771188e72f
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -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>>
|
||||
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
@ -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>
|
||||
|
24
plugins/view-resources/src/components/SpacePresenter.svelte
Normal file
24
plugins/view-resources/src/components/SpacePresenter.svelte
Normal 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}
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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,24 +126,23 @@ class TServerStorage implements ServerStorage {
|
||||
// maintain hiearachy and triggers
|
||||
this.hierarchy.tx(tx)
|
||||
await this.triggers.tx(tx)
|
||||
return []
|
||||
} else {
|
||||
// store object
|
||||
await this.routeTx(tx)
|
||||
// invoke triggers and store derived objects
|
||||
const derived = await this.triggers.apply(tx.modifiedBy, tx, this.findAll.bind(this), this.hierarchy)
|
||||
for (const tx of derived) {
|
||||
await this.routeTx(tx)
|
||||
}
|
||||
// index object
|
||||
await this.fulltext.tx(tx)
|
||||
// index derived objects
|
||||
for (const tx of derived) {
|
||||
await this.fulltext.tx(tx)
|
||||
}
|
||||
|
||||
return derived
|
||||
await this.modelDb.tx(tx)
|
||||
}
|
||||
// store object
|
||||
await this.routeTx(tx)
|
||||
// invoke triggers and store derived objects
|
||||
const derived = await this.triggers.apply(tx.modifiedBy, tx, this.findAll.bind(this), this.hierarchy)
|
||||
for (const tx of derived) {
|
||||
await this.routeTx(tx)
|
||||
}
|
||||
// index object
|
||||
await this.fulltext.tx(tx)
|
||||
// index derived objects
|
||||
for (const tx of derived) {
|
||||
await this.fulltext.tx(tx)
|
||||
}
|
||||
|
||||
return derived
|
||||
}
|
||||
}
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
@ -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,13 +64,16 @@ abstract class MongoAdapterBase extends TxProcessor {
|
||||
const lookups = options.lookup as any
|
||||
for (const key in lookups) {
|
||||
const clazz = lookups[key]
|
||||
const step = {
|
||||
from: this.hierarchy.getDomain(clazz),
|
||||
localField: key,
|
||||
foreignField: '_id',
|
||||
as: key + '_lookup'
|
||||
const domain = this.hierarchy.getDomain(clazz)
|
||||
if (domain !== DOMAIN_MODEL) {
|
||||
const step = {
|
||||
from: domain,
|
||||
localField: key,
|
||||
foreignField: '_id',
|
||||
as: key + '_lookup'
|
||||
}
|
||||
pipeline.push({ $lookup: step })
|
||||
}
|
||||
pipeline.push({ $lookup: step })
|
||||
}
|
||||
const domain = this.hierarchy.getDomain(clazz)
|
||||
const cursor = this.db.collection(domain).aggregate(pipeline)
|
||||
@ -78,8 +82,14 @@ abstract class MongoAdapterBase extends TxProcessor {
|
||||
const object = row as any
|
||||
object.$lookup = {}
|
||||
for (const key in lookups) {
|
||||
const arr = object[key + '_lookup']
|
||||
object.$lookup[key] = arr[0]
|
||||
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)
|
||||
}
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user