add create by

This commit is contained in:
Simon Larsen 2023-10-01 12:46:51 +01:00
parent c06c0f8b38
commit e728501ddb
No known key found for this signature in database
GPG Key ID: AB45983AA9C81CDE
13 changed files with 333 additions and 96 deletions

View File

@ -2,6 +2,7 @@ import TableColumnType from '../Types/BaseDatabase/TableColumnType';
import AnalyticsTableColumn from '../Types/AnalyticsDatabase/TableColumn'; import AnalyticsTableColumn from '../Types/AnalyticsDatabase/TableColumn';
import BadDataException from '../Types/Exception/BadDataException'; import BadDataException from '../Types/Exception/BadDataException';
import AnalyticsTableEngine from '../Types/AnalyticsDatabase/AnalyticsTableEngine'; import AnalyticsTableEngine from '../Types/AnalyticsDatabase/AnalyticsTableEngine';
import { JSONValue } from '../Types/JSON';
export default class AnalyticsDataModel { export default class AnalyticsDataModel {
private _tableColumns: Array<AnalyticsTableColumn> = []; private _tableColumns: Array<AnalyticsTableColumn> = [];
@ -101,4 +102,65 @@ export default class AnalyticsDataModel {
this.primaryKeys = data.primaryKeys; this.primaryKeys = data.primaryKeys;
this.tableColumns = columns; this.tableColumns = columns;
} }
public setColumnValue(
columnName: string,
value: JSONValue
): void {
if (this.getTableColumn(columnName)) {
return ((this as any)[columnName] = value as any);
}
}
public getTableColumn(name: string): AnalyticsTableColumn | null {
const column: AnalyticsTableColumn | undefined = this.tableColumns.find(
(column: AnalyticsTableColumn) => {
return column.key === name;
}
);
if (!column) {
return null;
}
return column;
}
public getTableColumns(): Array<AnalyticsTableColumn> {
return this.tableColumns;
}
public getTenantColumn(): AnalyticsTableColumn | null {
const column: AnalyticsTableColumn | undefined = this.tableColumns.find(
(column: AnalyticsTableColumn) => {
return column.isTenantId;
}
);
if (!column) {
return null;
}
return column;
}
public getRequiredColumns(): Array<AnalyticsTableColumn> {
return this.tableColumns.filter((column: AnalyticsTableColumn) => {
return column.required;
});
}
public isDefaultValueColumn(columnName: string): boolean {
const column: AnalyticsTableColumn | null = this.getTableColumn(
columnName
);
if (!column) {
return false;
}
return column.isDefaultValueColumn;
}
} }

View File

@ -33,6 +33,16 @@ export default class AnalyticsTableColumn {
this._required = v; this._required = v;
} }
private _isTenantId : boolean = false;
public get isTenantId() : boolean {
return this._isTenantId;
}
public set isTenantId(v : boolean) {
this._isTenantId = v;
}
private _type: TableColumnType = TableColumnType.ShortText; private _type: TableColumnType = TableColumnType.ShortText;
public get type(): TableColumnType { public get type(): TableColumnType {
return this._type; return this._type;
@ -40,6 +50,23 @@ export default class AnalyticsTableColumn {
public set type(v: TableColumnType) { public set type(v: TableColumnType) {
this._type = v; this._type = v;
} }
private _forceGetDefaultValueOnCreate?: (() => Date | string | number | boolean) | undefined;
public get forceGetDefaultValueOnCreate(): (() => Date | string | number | boolean) | undefined {
return this._forceGetDefaultValueOnCreate;
}
public set forceGetDefaultValueOnCreate(v: (() => Date | string | number | boolean) | undefined) {
this._forceGetDefaultValueOnCreate = v;
}
private _isDefaultValueColumn : boolean = false;
public get isDefaultValueColumn() : boolean {
return this._isDefaultValueColumn;
}
public set isDefaultValueColumn(v : boolean) {
this._isDefaultValueColumn = v;
}
public constructor(data: { public constructor(data: {
key: string; key: string;
@ -47,11 +74,17 @@ export default class AnalyticsTableColumn {
description: string; description: string;
required: boolean; required: boolean;
type: TableColumnType; type: TableColumnType;
isDefaultValueColumn? : boolean | undefined;
isTenantId?: boolean | undefined;
forceGetDefaultValueOnCreate?: (() => Date | string | number | boolean) | undefined;
}) { }) {
this.key = data.key; this.key = data.key;
this.title = data.title; this.title = data.title;
this.description = data.description; this.description = data.description;
this.required = data.required; this.required = data.required;
this.type = data.type; this.type = data.type;
this.isTenantId = data.isTenantId || false;
this.forceGetDefaultValueOnCreate = data.forceGetDefaultValueOnCreate;
this.isDefaultValueColumn = data.isDefaultValueColumn || false;
} }
} }

View File

@ -4,11 +4,14 @@ import ClickhouseDatabase, {
ClickhouseClient, ClickhouseClient,
} from '../Infrastructure/ClickhouseDatabase'; } from '../Infrastructure/ClickhouseDatabase';
import BaseService from './BaseService'; import BaseService from './BaseService';
import AnalyticsBaseModel from 'Common/Models/AnalyticsBaseModel'; import AnalyticsBaseModel from 'Common/AnalyticsModels/BaseModel';
import BadDataException from 'Common/Types/Exception/BadDataException'; import BadDataException from 'Common/Types/Exception/BadDataException';
import logger from '../Utils/Logger'; import logger from '../Utils/Logger';
import AnalyticsTableColumn from 'Common/Types/AnalyticsDatabase/TableColumn'; import AnalyticsTableColumn from 'Common/Types/AnalyticsDatabase/TableColumn';
// import CreateBy from "../Types/AnalyticsDatabase/CreateBy"; import CreateBy from '../Types/AnalyticsDatabase/CreateBy';
import { OnCreate } from '../Types/AnalyticsDatabase/Hooks';
import Typeof from 'Common/Types/Typeof';
import ModelPermission from '../Utils/ModelPermission';
export default class AnalyticsDatabaseService< export default class AnalyticsDatabaseService<
TBaseModel extends AnalyticsBaseModel TBaseModel extends AnalyticsBaseModel
@ -59,6 +62,19 @@ export default class AnalyticsDatabaseService<
return statement; return statement;
} }
protected generateDefaultValues(data: TBaseModel): TBaseModel {
const tableColumns: Array<AnalyticsTableColumn> = data.getTableColumns();
for (const column of tableColumns) {
if (column.forceGetDefaultValueOnCreate) {
data.setColumnValue(column.key, column.forceGetDefaultValueOnCreate());
}
}
return data;
}
public useDefaultDatabase(): void { public useDefaultDatabase(): void {
this.database = ClickhouseAppInstance; this.database = ClickhouseAppInstance;
this.databaseClient = this.database.getDataSource() as ClickhouseClient; this.databaseClient = this.database.getDataSource() as ClickhouseClient;
@ -74,99 +90,120 @@ export default class AnalyticsDatabaseService<
}); });
} }
// public async create(createBy: CreateBy<TBaseModel>): Promise<TBaseModel> { protected async onBeforeCreate(
createBy: CreateBy<TBaseModel>
): Promise<OnCreate<TBaseModel>> {
// A place holder method used for overriding.
return Promise.resolve({
createBy: createBy as CreateBy<TBaseModel>,
carryForward: undefined,
});
}
// const onCreate: OnCreate<TBaseModel> = createBy.props.ignoreHooks private async _onBeforeCreate(
// ? { createBy, carryForward: [] } createBy: CreateBy<TBaseModel>
// : await this._onBeforeCreate(createBy); ): Promise<OnCreate<TBaseModel>> {
// Private method that runs before create.
const projectIdColumn: string | null = this.model.getTenantColumn()?.key || null;
// let _createdBy: CreateBy<TBaseModel> = onCreate.createBy; if (projectIdColumn && createBy.props.tenantId) {
(createBy.data as any)[projectIdColumn] = createBy.props.tenantId;
}
// const carryForward: any = onCreate.carryForward; return await this.onBeforeCreate(createBy);
}
// _createdBy = this.generateSlug(_createdBy); public async create(createBy: CreateBy<TBaseModel>): Promise<TBaseModel> {
// let data: TBaseModel = _createdBy.data; const onCreate: OnCreate<TBaseModel> = createBy.props.ignoreHooks
? { createBy, carryForward: [] }
: await this._onBeforeCreate(createBy);
// // add tenantId if present. let _createdBy: CreateBy<TBaseModel> = onCreate.createBy;
// const tenantColumnName: string | null = data.getTenantColumn();
// if (tenantColumnName && _createdBy.props.tenantId) { const carryForward: any = onCreate.carryForward;
// data.setColumnValue(tenantColumnName, _createdBy.props.tenantId);
// }
// data = this.generateDefaultValues(data); let data: TBaseModel = _createdBy.data;
// data = this.checkRequiredFields(data);
// if (!this.isValid(data)) { // add tenantId if present.
// throw new BadDataException('Data is not valid'); const tenantColumnName: string | null = data.getTenantColumn()?.key || null;
// }
// // check total items by. if (tenantColumnName && _createdBy.props.tenantId) {
data.setColumnValue(tenantColumnName, _createdBy.props.tenantId);
}
// await this.checkTotalItemsBy(_createdBy); data = this.generateDefaultValues(data);
data = this.checkRequiredFields(data);
// // Encrypt data if (!this.isValid(data)) {
// data = this.encrypt(data); throw new BadDataException('Data is not valid');
}
// // hash data // check total items by
// data = await this.hash(data);
// ModelPermission.checkCreatePermissions( ModelPermission.checkCreatePermissions(
// this.entityType, this.entityType,
// data, data,
// _createdBy.props _createdBy.props
// ); );
// createBy.data = data; createBy.data = data;
// // check uniqueColumns by: // check uniqueColumns by:
// createBy = await this.checkUniqueColumnBy(createBy); createBy = await this.checkUniqueColumnBy(createBy);
// // serialize. // serialize.
// createBy.data = (await this.sanitizeCreateOrUpdate( createBy.data = (await this.sanitizeCreateOrUpdate(
// createBy.data, createBy.data,
// createBy.props createBy.props
// )) as TBaseModel; )) as TBaseModel;
// try { try {
// createBy.data = await this.getRepository().save(createBy.data); createBy.data = await this.getRepository().save(createBy.data);
// if (!createBy.props.ignoreHooks) { if (!createBy.props.ignoreHooks) {
// createBy.data = await this.onCreateSuccess( createBy.data = await this.onCreateSuccess(
// { {
// createBy, createBy,
// carryForward, carryForward,
// }, },
// createBy.data createBy.data
// ); );
// } }
// // hit workflow.; // hit workflow.;
// if (this.getModel().enableWorkflowOn?.create) { if (this.getModel().enableWorkflowOn?.create) {
// let tenantId: ObjectID | undefined = createBy.props.tenantId; let tenantId: ObjectID | undefined = createBy.props.tenantId;
// if (!tenantId && this.getModel().getTenantColumn()) { if (!tenantId && this.getModel().getTenantColumn()) {
// tenantId = createBy.data.getValue<ObjectID>( tenantId = createBy.data.getValue<ObjectID>(
// this.getModel().getTenantColumn()! this.getModel().getTenantColumn()!
// ); );
// } }
// if (tenantId) { if (tenantId) {
// await this.onTrigger( await this.onTrigger(
// createBy.data.id!, createBy.data.id!,
// tenantId, tenantId,
// 'on-create' 'on-create'
// ); );
// } }
// } }
// return createBy.data; return createBy.data;
// } catch (error) { } catch (error) {
// await this.onCreateError(error as Exception); await this.onCreateError(error as Exception);
// throw this.getException(error as Exception); throw this.getException(error as Exception);
// } }
// } }
protected isValid(data: TBaseModel): boolean {
if (!data) {
throw new BadDataException('Data cannot be null');
}
return true;
}
public toColumnsCreateStatement(): string { public toColumnsCreateStatement(): string {
let columns: string = ''; let columns: string = '';
@ -180,6 +217,32 @@ export default class AnalyticsDatabaseService<
return columns; return columns;
} }
protected checkRequiredFields(data: TBaseModel): TBaseModel {
// Check required fields.
for (const columns of data.getRequiredColumns()) {
const requiredField: string = columns.key;
if (typeof (data as any)[requiredField] === Typeof.Boolean) {
if (
!(data as any)[requiredField] &&
(data as any)[requiredField] !== false &&
!data.isDefaultValueColumn(requiredField)
) {
throw new BadDataException(`${requiredField} is required`);
}
} else if (
!(data as any)[requiredField] &&
!data.isDefaultValueColumn(requiredField)
) {
throw new BadDataException(`${requiredField} is required`);
}
}
return data;
}
public toColumnType(type: TableColumnType): string { public toColumnType(type: TableColumnType): string {
if (type === TableColumnType.ShortText) { if (type === TableColumnType.ShortText) {
return 'String'; return 'String';

View File

@ -53,28 +53,9 @@ import Text from 'Common/Types/Text';
import logger from '../Utils/Logger'; import logger from '../Utils/Logger';
import BaseService from './BaseService'; import BaseService from './BaseService';
import { getMaxLengthFromTableColumnType } from 'Common/Types/Database/ColumnLength'; import { getMaxLengthFromTableColumnType } from 'Common/Types/Database/ColumnLength';
import { OnCreate, OnDelete, OnFind, OnUpdate } from '../Types/Database/Hooks';
export type DatabaseTriggerType = 'on-create' | 'on-update' | 'on-delete';
export interface OnCreate<TBaseModel extends BaseModel> {
createBy: CreateBy<TBaseModel>;
carryForward: any;
}
export interface OnFind<TBaseModel extends BaseModel> {
findBy: FindBy<TBaseModel>;
carryForward: any;
}
export interface OnDelete<TBaseModel extends BaseModel> {
deleteBy: DeleteBy<TBaseModel>;
carryForward: any;
}
export interface OnUpdate<TBaseModel extends BaseModel> {
updateBy: UpdateBy<TBaseModel>;
carryForward: any;
}
class DatabaseService<TBaseModel extends BaseModel> extends BaseService { class DatabaseService<TBaseModel extends BaseModel> extends BaseService {
private postgresDatabase!: PostgresDatabase; private postgresDatabase!: PostgresDatabase;

View File

@ -1,4 +1,4 @@
import AnalyticsBaseModel from 'Common/Models/AnalyticsBaseModel'; import AnalyticsBaseModel from 'Common/AnalyticsModels/BaseModel';
import DatabaseCommonInteractionProps from 'Common/Types/Database/DatabaseCommonInteractionProps'; import DatabaseCommonInteractionProps from 'Common/Types/Database/DatabaseCommonInteractionProps';
export default interface CreateBy<TBaseModel extends AnalyticsBaseModel> { export default interface CreateBy<TBaseModel extends AnalyticsBaseModel> {

View File

@ -0,0 +1,7 @@
import AnalyticsBaseModel from 'Common/Models/AnalyticsBaseModel';
import DatabaseCommonInteractionProps from 'Common/Types/Database/DatabaseCommonInteractionProps';
export default interface DeleteBy<TBaseModel extends AnalyticsBaseModel> {
data: TBaseModel;
props: DatabaseCommonInteractionProps;
}

View File

@ -0,0 +1,7 @@
import AnalyticsBaseModel from 'Common/Models/AnalyticsBaseModel';
import DatabaseCommonInteractionProps from 'Common/Types/Database/DatabaseCommonInteractionProps';
export default interface FindBy<TBaseModel extends AnalyticsBaseModel> {
data: TBaseModel;
props: DatabaseCommonInteractionProps;
}

View File

@ -0,0 +1,27 @@
import BaseModel from "Common/AnalyticsModels/BaseModel";
import CreateBy from "./CreateBy";
import DeleteBy from "./DeleteBy";
import FindBy from "./FindBy";
import UpdateBy from "./UpdateBy";
export type DatabaseTriggerType = 'on-create' | 'on-update' | 'on-delete';
export interface OnCreate<TBaseModel extends BaseModel> {
createBy: CreateBy<TBaseModel>;
carryForward: any;
}
export interface OnFind<TBaseModel extends BaseModel> {
findBy: FindBy<TBaseModel>;
carryForward: any;
}
export interface OnDelete<TBaseModel extends BaseModel> {
deleteBy: DeleteBy<TBaseModel>;
carryForward: any;
}
export interface OnUpdate<TBaseModel extends BaseModel> {
updateBy: UpdateBy<TBaseModel>;
carryForward: any;
}

View File

@ -0,0 +1,7 @@
import AnalyticsBaseModel from 'Common/Models/AnalyticsBaseModel';
import DatabaseCommonInteractionProps from 'Common/Types/Database/DatabaseCommonInteractionProps';
export default interface UpdateBy<TBaseModel extends AnalyticsBaseModel> {
data: TBaseModel;
props: DatabaseCommonInteractionProps;
}

View File

@ -0,0 +1,27 @@
import BaseModel from "Common/Models/BaseModel";
import CreateBy from "./CreateBy";
import DeleteBy from "./DeleteBy";
import FindBy from "./FindBy";
import UpdateBy from "./UpdateBy";
export type DatabaseTriggerType = 'on-create' | 'on-update' | 'on-delete';
export interface OnCreate<TBaseModel extends BaseModel> {
createBy: CreateBy<TBaseModel>;
carryForward: any;
}
export interface OnFind<TBaseModel extends BaseModel> {
findBy: FindBy<TBaseModel>;
carryForward: any;
}
export interface OnDelete<TBaseModel extends BaseModel> {
deleteBy: DeleteBy<TBaseModel>;
carryForward: any;
}
export interface OnUpdate<TBaseModel extends BaseModel> {
updateBy: UpdateBy<TBaseModel>;
carryForward: any;
}

23
Llama/Dockerfile.tpl Normal file
View File

@ -0,0 +1,23 @@
ARG TAG=latest
FROM continuumio/miniconda3:$TAG
RUN apt-get update \
&& DEBIAN_FRONTEND="noninteractive" apt-get install -y --no-install-recommends \
git \
locales \
sudo \
build-essential \
dpkg-dev \
wget \
openssh-server \
nano \
&& rm -rf /var/lib/apt/lists/*
# Setting up locales
RUN locale-gen en_US.UTF-8
ENV LANG en_US.UTF-8
# Updating conda to the latest version
RUN conda update conda -y

View File

@ -1,4 +1,4 @@
import AnalyticsBaseModel from 'Common/Models/AnalyticsBaseModel'; import AnalyticsBaseModel from 'Common/AnalyticsModels/BaseModel';
import AnalyticsTableColumn from 'Common/Types/AnalyticsDatabase/TableColumn'; import AnalyticsTableColumn from 'Common/Types/AnalyticsDatabase/TableColumn';
import TableColumnType from 'Common/Types/BaseDatabase/TableColumnType'; import TableColumnType from 'Common/Types/BaseDatabase/TableColumnType';
import AnalyticsTableEngine from 'Common/Types/AnalyticsDatabase/AnalyticsTableEngine'; import AnalyticsTableEngine from 'Common/Types/AnalyticsDatabase/AnalyticsTableEngine';

View File

@ -32,8 +32,8 @@ If you need advanced features, such as API Access, Advances Workflows, or Advanc
## Installation ## Installation
- [Install on Kubernetes with Helm](https://artifacthub.io/packages/helm/oneuptime/oneuptime) (recommended for production) - [Install on Kubernetes with Helm](https://artifacthub.io/packages/helm/oneuptime/oneuptime) (recommended for production)
- [Install with Docker Compose](https://github.com/OneUptime/oneuptime/blob/master/Docs/Installation/DockerCompose.md) (hobby install, not recommended for production use) - [Install with Docker Compose](https://github.com/OneUptime/oneuptime/blob/master/Docs/Installation/DockerCompose.md) (hobby install, not recommended for production)
- [Install for local development](https://github.com/OneUptime/oneuptime/blob/master/Docs/Installation/Development.md) - [Install for Local Development](https://github.com/OneUptime/oneuptime/blob/master/Docs/Installation/Development.md)
## Philosophy ## Philosophy