add core docs

Signed-off-by: Andrey Platov <andrey@hardcoreeng.com>
This commit is contained in:
Andrey Platov 2021-08-04 22:24:30 +02:00
parent 748099568c
commit df20992b09
No known key found for this signature in database
GPG Key ID: C8787EFEB4B64AF0
12 changed files with 287 additions and 16 deletions

View File

@ -0,0 +1,19 @@
//
// 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.
//
const start = require('@anticrm/dev-server')
start (3333)

126
cloud/dev-server/app/package-lock.json generated Normal file
View File

@ -0,0 +1,126 @@
{
"name": "@anticrm/dev-server-app",
"version": "0.6.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@anticrm/core": {
"version": "0.6.4",
"resolved": "https://registry.npmjs.org/@anticrm/core/-/core-0.6.4.tgz",
"integrity": "sha512-R4sy4iOJn+7mTLOmeS03KTLmDlPFLvT4gLAIo7VWSStpslVex+YoyRXulnhTIbBZikQFW88nAvAm5e4fhoiVgA==",
"requires": {
"@anticrm/platform": "~0.6.1",
"simplytyped": "^3.3.0"
}
},
"@anticrm/dev-server": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/@anticrm/dev-server/-/dev-server-0.6.1.tgz",
"integrity": "sha512-Zh04YOsHprDMjCybAzizImZtRntEmuyS7ko8gdTZKgmHq3Bypf4jRIai0WF8sjULVrcOKRAGEAVqdPBhwkwz2Q==",
"requires": {
"@anticrm/core": "~0.6.1",
"@anticrm/dev-storage": "~0.6.1",
"@anticrm/platform": "~0.6.1",
"@anticrm/server-ws": "~0.6.1"
}
},
"@anticrm/dev-storage": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/@anticrm/dev-storage/-/dev-storage-0.6.1.tgz",
"integrity": "sha512-MSmHqp6O50FMYtisuDZdVFds6wslHYhypMZ4QN+DqRaDYWa+rkEIETW3FKs3YLaMvrPCHphcHI8ZCsHL3eX3ew==",
"requires": {
"@anticrm/core": "~0.6.1",
"@anticrm/platform": "~0.6.1"
}
},
"@anticrm/platform": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/@anticrm/platform/-/platform-0.6.1.tgz",
"integrity": "sha512-Ay/deCr9NH5SgztB9CuNOMX2pJSy8GR9JAQbGZXTl9KpzGJhlXyRnCKvPyEeY0mHiVk72jLymRo3+Uis8grNoA==",
"requires": {
"intl-messageformat": "^9.7.1"
}
},
"@anticrm/server-ws": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/@anticrm/server-ws/-/server-ws-0.6.1.tgz",
"integrity": "sha512-hQpDfPeLpia3f2SlITtI+iJ1vXW5JL/U6eKjkufCjQtLzUKtz08FO9MnoFxb3xSPLiHpy/C/d6oPMOMNMgg/Mg==",
"requires": {
"@anticrm/platform": "~0.6.1",
"jwt-simple": "^0.5.6",
"ws": "^8.0.0"
}
},
"@formatjs/ecma402-abstract": {
"version": "1.9.5",
"resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.9.5.tgz",
"integrity": "sha512-cGpEBzrf9bL2lTMEuRZ3gjLrEUEucxAXDIdX4tNqNdNZO81ZN558BfjiFfyPgrhILEuJU/+sgLwWxddSn6usHw==",
"requires": {
"@formatjs/intl-localematcher": "0.2.18",
"tslib": "^2.1.0"
}
},
"@formatjs/fast-memoize": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-1.1.1.tgz",
"integrity": "sha512-mIqBr5uigIlx13eZTOPSEh2buDiy3BCdMYUtewICREQjbb4xarDiVWoXSnrERM7NanZ+0TAHNXSqDe6HpEFQUg=="
},
"@formatjs/icu-messageformat-parser": {
"version": "2.0.8",
"resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.0.8.tgz",
"integrity": "sha512-fZlQ7ls3eQswO4RFB0lSi+ritPvud0Z2EQB6SU8qI5+MIS4qU4AHjq/dFJNvhdEdmJqLWHe31K4yHaRdavkSQQ==",
"requires": {
"@formatjs/ecma402-abstract": "1.9.5",
"@formatjs/icu-skeleton-parser": "1.2.9",
"tslib": "^2.1.0"
}
},
"@formatjs/icu-skeleton-parser": {
"version": "1.2.9",
"resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.2.9.tgz",
"integrity": "sha512-cx8Ug1gxRtv0rRddWd6dt5Sn/BhnhktSHvokbmLUVOEp2dy/6Ehvv2e00wow28AaSIzvBvM6ew1Qwe9wzDzcOw==",
"requires": {
"@formatjs/ecma402-abstract": "1.9.5",
"tslib": "^2.1.0"
}
},
"@formatjs/intl-localematcher": {
"version": "0.2.18",
"resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.2.18.tgz",
"integrity": "sha512-xI9X+mi7wbucbh35GNTY+C0+oMJXAp8ueC73SOyJlBpRNjLuOlSwgw3yJaCZxy3WpjcRBCP0laJ5zlpITO0QpA==",
"requires": {
"tslib": "^2.1.0"
}
},
"intl-messageformat": {
"version": "9.8.1",
"resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-9.8.1.tgz",
"integrity": "sha512-2rSZQu8GmLOlxNiehRvxWjkIqzemW833zm8ZS63JNvSpSuGnpqSWRqqwqv1kEBto/97/UBjtWy14m/CIdwVqFg==",
"requires": {
"@formatjs/fast-memoize": "1.1.1",
"@formatjs/icu-messageformat-parser": "2.0.8",
"tslib": "^2.1.0"
}
},
"jwt-simple": {
"version": "0.5.6",
"resolved": "https://registry.npmjs.org/jwt-simple/-/jwt-simple-0.5.6.tgz",
"integrity": "sha512-40aUybvhH9t2h71ncA1/1SbtTNCVZHgsTsTgqPUxGWDmUDrXyDf2wMNQKEbdBjbf4AI+fQhbECNTV6lWxQKUzg=="
},
"simplytyped": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/simplytyped/-/simplytyped-3.3.0.tgz",
"integrity": "sha512-mz4RaNdKTZiaKXgi6P1k/cdsxV3gz+y1Wh2NXHWD40dExktLh4Xx/h6MFakmQWODZHj/2rKe59acacpL74ZhQA=="
},
"tslib": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz",
"integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="
},
"ws": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.0.0.tgz",
"integrity": "sha512-6AcSIXpBlS0QvCVKk+3cWnWElLsA6SzC0lkQ43ciEglgXJXiCWK3/CGFEJ+Ybgp006CMibamAsqOlxE9s4AvYA=="
}
}
}

View File

@ -0,0 +1,12 @@
{
"name": "@anticrm/dev-server-app",
"version": "0.6.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node ./index.js"
},
"dependencies": {
"@anticrm/dev-server": "^0.6.1"
}
}

View File

@ -14,4 +14,4 @@
// limitations under the License.
//
export { start } from './server'
export { start as default } from './server'

View File

@ -23,8 +23,14 @@ import { TxProcessor } from './tx'
import core from './component'
type TxHander = (tx: Tx) => void
/**
* @public
*/
export type TxHander = (tx: Tx) => void
/**
* @public
*/
export interface Client extends Storage {
getHierarchy: () => Hierarchy
}
@ -53,6 +59,9 @@ class ClientImpl extends TxProcessor implements Storage, Client {
}
}
/**
* @public
*/
export async function createClient (
connect: (txHandler: TxHander) => Promise<Storage>,
notify?: (tx: Tx) => void

View File

@ -17,6 +17,9 @@ import { plugin } from '@anticrm/platform'
import type { Account, Class, Doc, Obj, Ref, Space, AnyAttribute, Tx, TxCreateDoc, TxMixin } from './classes'
import type { TxRemoveDoc, TxUpdateDoc } from './tx'
/**
* @public
*/
export const coreId = 'core' as Plugin
export default plugin(coreId, {

View File

@ -17,13 +17,16 @@ import { PlatformError, Severity, Status } from '@anticrm/platform'
import type { Class, Doc, Ref, Tx, TxCreateDoc, TxMixin } from './classes'
import core from './component'
import type { Hierarchy } from './hierarchy'
import { getOperator } from './operator'
import { _getOperator } from './operator'
import { findProperty, resultSort } from './query'
import type { DocumentQuery, FindOptions, FindResult, Storage, WithLookup, LookupData, Refs } from './storage'
import type { TxRemoveDoc, TxUpdateDoc } from './tx'
import { TxProcessor } from './tx'
class MemDb extends TxProcessor {
/**
* @public
*/
export class MemDb extends TxProcessor {
protected readonly hierarchy: Hierarchy
private readonly objectsByClass = new Map<Ref<Class<Doc>>, Doc[]>()
private readonly objectById = new Map<Ref<Doc>, Doc>()
@ -162,7 +165,7 @@ export class ModelDb extends MemDb implements Storage {
const ops = tx.operations as any
for (const key in ops) {
if (key.startsWith('$')) {
const operator = getOperator(key)
const operator = _getOperator(key)
operator(doc, ops[key])
} else {
doc[key] = ops[key]

View File

@ -16,7 +16,10 @@
import type { Doc, PropertyType } from './classes'
type OperatorFunc = (doc: Doc, op: object) => void
/**
* @internal
*/
export type _OperatorFunc = (doc: Doc, op: object) => void
function $push (document: Doc, keyval: Record<string, PropertyType>): void {
const doc = document as any
@ -30,11 +33,16 @@ function $push (document: Doc, keyval: Record<string, PropertyType>): void {
}
}
const operators: Record<string, OperatorFunc> = {
const operators: Record<string, _OperatorFunc> = {
$push
}
export function getOperator (name: string): OperatorFunc {
/**
* @internal
* @param name -
* @returns
*/
export function _getOperator (name: string): _OperatorFunc {
const operator = operators[name]
if (operator === undefined) throw new Error('unknown operator: ' + name)
return operator

View File

@ -2,14 +2,23 @@ import { Doc } from './classes'
import { createPredicates, isPredicate } from './predicate'
import { SortingQuery } from './storage'
/**
* @public
*/
export const likeSymbol = '%'
/**
* @public
*/
export function checkLikeQuery (value: string, query: string): boolean {
const searchString = query.split(likeSymbol).join('.*')
const regex = RegExp(`^${searchString}$`)
return regex.test(value)
}
/**
* @public
*/
export function findProperty (objects: Doc[], propertyKey: string, value: any): Doc[] {
if (isPredicate(value)) {
const preds = createPredicates(value, propertyKey)
@ -27,6 +36,9 @@ export function findProperty (objects: Doc[], propertyKey: string, value: any):
return result
}
/**
* @public
*/
export function resultSort<T extends Doc> (result: T[], sortOptions: SortingQuery<T>): void {
const sortFunc = (a: any, b: any): number => {
for (const key in sortOptions) {

View File

@ -16,20 +16,35 @@
import type { KeysByType } from 'simplytyped'
import type { Class, Doc, Ref, Tx } from './classes'
/**
* @public
*/
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
export type QuerySelector<T> = {
$in?: T[]
$like?: string
}
/**
* @public
*/
export type ObjQueryType<T> = T | QuerySelector<T>
/**
* @public
*/
export type DocumentQuery<T extends Doc> = {
[P in keyof T]?: ObjQueryType<T[P]>
}
/**
* @public
*/
export type Refs<T extends Doc> = Partial<Pick<T, KeysByType<T, Ref<Doc>>>>
/**
* @public
*/
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
export type FindOptions<T extends Doc> = {
limit?: number
@ -37,29 +52,53 @@ export type FindOptions<T extends Doc> = {
lookup?: Refs<T>
}
/**
* @public
*/
export type SortingQuery<T extends Doc> = {
[P in keyof T]?: T[P] extends object ? never : SortingOrder
}
/**
* @public
*/
export enum SortingOrder {
Ascending = 1,
Descending = -1
}
type RefsAsDocs<T extends Doc> = {
/**
* @public
*/
export type RefsAsDocs<T extends Doc> = {
[P in keyof T]: T[P] extends Ref<infer X> ? X : never
}
type RemoveNever<T extends object> = Omit<T, KeysByType<T, never>>
/**
* @public
*/
export type RemoveNever<T extends object> = Omit<T, KeysByType<T, never>>
/**
* @public
*/
export type LookupData<T extends Doc> = Partial<RemoveNever<RefsAsDocs<T>>>
/**
* @public
*/
export type WithLookup<T extends Doc> = T & {
$lookup?: LookupData<T>
}
/**
* @public
*/
export type FindResult<T extends Doc> = WithLookup<T>[]
/**
* @public
*/
export interface Storage {
findAll: <T extends Doc>(
_class: Ref<Class<T>>,

View File

@ -18,31 +18,58 @@ import type { Class, Data, Doc, Domain, Ref, Account, Space, Arr, Mixin, Tx, TxC
import core from './component'
import { generateId } from './utils'
type ArrayAsElement<T extends Doc> = {
/**
* @public
*/
export type ArrayAsElement<T extends Doc> = {
[P in keyof T]: T[P] extends Arr<infer X> ? X : never
}
type OmitNever<T extends object> = Omit<T, KeysByType<T, never>>
/**
* @public
*/
export type OmitNever<T extends object> = Omit<T, KeysByType<T, never>>
interface PushOptions<T extends Doc> {
/**
* @public
*/
export interface PushOptions<T extends Doc> {
$push?: Partial<OmitNever<ArrayAsElement<T>>>
}
/**
* @public
*/
export type DocumentUpdate<T extends Doc> = Partial<Data<T>> & PushOptions<T>
/**
* @public
*/
export interface TxUpdateDoc<T extends Doc> extends Tx<T> {
operations: DocumentUpdate<T>
}
/**
* @public
*/
export interface TxRemoveDoc<T extends Doc> extends Tx<T> {
}
/**
* @public
*/
export const DOMAIN_TX = 'tx' as Domain
interface WithTx {
/**
* @public
*/
export interface WithTx {
tx: (tx: Tx) => Promise<void>
}
/**
* @public
*/
export class TxProcessor implements WithTx {
async tx (tx: Tx): Promise<void> {
switch (tx._class) {
@ -75,6 +102,9 @@ export class TxProcessor implements WithTx {
protected async txMixin (tx: TxMixin<Doc, Doc>): Promise<void> {}
}
/**
* @public
*/
export interface TxOperations {
createDoc: <T extends Doc>(_class: Ref<Class<T>>, space: Ref<Space>, attributes: Data<T>) => Promise<T>
updateDoc: <T extends Doc>(
@ -86,6 +116,9 @@ export interface TxOperations {
removeDoc: <T extends Doc>(_class: Ref<Class<T>>, space: Ref<Space>, objectId: Ref<T>) => Promise<void>
}
/**
* @public
*/
export function withOperations<T extends WithTx> (user: Ref<Account>, storage: T): T & TxOperations {
const result = storage as T & TxOperations
@ -150,6 +183,9 @@ export function withOperations<T extends WithTx> (user: Ref<Account>, storage: T
return result
}
/**
* @public
*/
export class DefaultTxFactory implements TxFactory {
constructor (readonly account: Ref<Account>) {}

View File

@ -36,6 +36,10 @@ function count (): string {
return toHex(val, 6)
}
/**
* @public
* @returns
*/
export function generateId<T extends Doc> (): Ref<T> {
return (timestamp() + random + count()) as Ref<T>
}