[MM-65984] DB changes to handle Playbook Run Attributes (#9172)
* db changes * temp tests * missing mock models * test helpers improvement * address naming errors * added comments to schema * x2 * minor corrections * Update app/products/playbooks/database/models/playbook_run_attribute_value.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * docs --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
parent
597e03d7d8
commit
87395e1210
24 changed files with 1297 additions and 17 deletions
|
|
@ -22,7 +22,7 @@ import AppDataOperator from '@database/operator/app_data_operator';
|
|||
import ServerDataOperator from '@database/operator/server_data_operator';
|
||||
import {schema as appSchema} from '@database/schema/app';
|
||||
import {serverSchema} from '@database/schema/server';
|
||||
import {PlaybookRunModel, PlaybookChecklistModel, PlaybookChecklistItemModel} from '@playbooks/database/models';
|
||||
import {PlaybookRunModel, PlaybookChecklistModel, PlaybookChecklistItemModel, PlaybookRunAttributeModel, PlaybookRunAttributeValueModel} from '@playbooks/database/models';
|
||||
import {deleteIOSDatabase} from '@utils/mattermost_managed';
|
||||
import {urlSafeBase64Encode} from '@utils/security';
|
||||
import {removeProtocol} from '@utils/url';
|
||||
|
|
@ -54,7 +54,7 @@ class DatabaseManagerSingleton {
|
|||
PostModel, PostsInChannelModel, PostsInThreadModel, PreferenceModel, ReactionModel, RoleModel,
|
||||
ScheduledPostModel, SystemModel, TeamModel, TeamChannelHistoryModel, TeamMembershipModel, TeamSearchHistoryModel,
|
||||
ThreadModel, ThreadParticipantModel, ThreadInTeamModel, TeamThreadsSyncModel, UserModel,
|
||||
PlaybookRunModel, PlaybookChecklistModel, PlaybookChecklistItemModel,
|
||||
PlaybookRunModel, PlaybookChecklistModel, PlaybookChecklistItemModel, PlaybookRunAttributeModel, PlaybookRunAttributeValueModel,
|
||||
];
|
||||
this.databaseDirectory = '';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ import ServerDataOperator from '@database/operator/server_data_operator';
|
|||
import {schema as appSchema} from '@database/schema/app';
|
||||
import {serverSchema} from '@database/schema/server';
|
||||
import {beforeUpgrade} from '@helpers/database/upgrade';
|
||||
import {PlaybookRunModel, PlaybookChecklistModel, PlaybookChecklistItemModel} from '@playbooks/database/models';
|
||||
import {PlaybookRunModel, PlaybookChecklistModel, PlaybookChecklistItemModel, PlaybookRunAttributeModel, PlaybookRunAttributeValueModel} from '@playbooks/database/models';
|
||||
import {getActiveServer, getServer, getServerByIdentifier} from '@queries/app/servers';
|
||||
import {logDebug, logError} from '@utils/log';
|
||||
import {deleteIOSDatabase, getIOSAppGroupDetails, renameIOSDatabase} from '@utils/mattermost_managed';
|
||||
|
|
@ -50,7 +50,7 @@ class DatabaseManagerSingleton {
|
|||
PostModel, PostsInChannelModel, PostsInThreadModel, PreferenceModel, ReactionModel, RoleModel,
|
||||
ScheduledPostModel, SystemModel, TeamModel, TeamChannelHistoryModel, TeamMembershipModel, TeamSearchHistoryModel,
|
||||
ThreadModel, ThreadParticipantModel, ThreadInTeamModel, TeamThreadsSyncModel, UserModel,
|
||||
PlaybookRunModel, PlaybookChecklistModel, PlaybookChecklistItemModel,
|
||||
PlaybookRunModel, PlaybookChecklistModel, PlaybookChecklistItemModel, PlaybookRunAttributeModel, PlaybookRunAttributeValueModel,
|
||||
];
|
||||
|
||||
this.databaseDirectory = Platform.OS === 'ios' ? getIOSAppGroupDetails().appGroupDatabase : `${documentDirectory}/databases/`;
|
||||
|
|
|
|||
|
|
@ -22,9 +22,36 @@ const {
|
|||
SCHEDULED_POST,
|
||||
} = MM_TABLES.SERVER;
|
||||
|
||||
const {PLAYBOOK_RUN, PLAYBOOK_CHECKLIST, PLAYBOOK_CHECKLIST_ITEM} = PLAYBOOK_TABLES;
|
||||
const {PLAYBOOK_RUN, PLAYBOOK_CHECKLIST, PLAYBOOK_CHECKLIST_ITEM, PLAYBOOK_RUN_ATTRIBUTE, PLAYBOOK_RUN_ATTRIBUTE_VALUE} = PLAYBOOK_TABLES;
|
||||
|
||||
export default schemaMigrations({migrations: [
|
||||
{
|
||||
toVersion: 14,
|
||||
steps: [
|
||||
createTable({
|
||||
name: PLAYBOOK_RUN_ATTRIBUTE,
|
||||
columns: [
|
||||
{name: 'group_id', type: 'string'},
|
||||
{name: 'name', type: 'string'},
|
||||
{name: 'type', type: 'string'},
|
||||
{name: 'target_id', type: 'string'},
|
||||
{name: 'target_type', type: 'string'},
|
||||
{name: 'create_at', type: 'number'},
|
||||
{name: 'update_at', type: 'number'},
|
||||
{name: 'delete_at', type: 'number'},
|
||||
{name: 'attrs', type: 'string', isOptional: true},
|
||||
],
|
||||
}),
|
||||
createTable({
|
||||
name: PLAYBOOK_RUN_ATTRIBUTE_VALUE,
|
||||
columns: [
|
||||
{name: 'attribute_id', type: 'string', isIndexed: true},
|
||||
{name: 'run_id', type: 'string', isIndexed: true},
|
||||
{name: 'value', type: 'string'},
|
||||
],
|
||||
}),
|
||||
],
|
||||
},
|
||||
{
|
||||
toVersion: 13,
|
||||
steps: [
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
import {type AppSchema, appSchema} from '@nozbe/watermelondb';
|
||||
|
||||
import {PlaybookRunSchema, PlaybookChecklistSchema, PlaybookChecklistItemSchema} from '@playbooks/database/schema';
|
||||
import {PlaybookRunSchema, PlaybookChecklistSchema, PlaybookChecklistItemSchema, PlaybookRunAttributeSchema, PlaybookRunAttributeValueSchema} from '@playbooks/database/schema';
|
||||
|
||||
import {
|
||||
CategorySchema,
|
||||
|
|
@ -45,7 +45,7 @@ import {
|
|||
} from './table_schemas';
|
||||
|
||||
export const serverSchema: AppSchema = appSchema({
|
||||
version: 13,
|
||||
version: 14,
|
||||
tables: [
|
||||
CategorySchema,
|
||||
CategoryChannelSchema,
|
||||
|
|
@ -69,6 +69,8 @@ export const serverSchema: AppSchema = appSchema({
|
|||
PlaybookRunSchema,
|
||||
PlaybookChecklistSchema,
|
||||
PlaybookChecklistItemSchema,
|
||||
PlaybookRunAttributeSchema,
|
||||
PlaybookRunAttributeValueSchema,
|
||||
PostInThreadSchema,
|
||||
PostSchema,
|
||||
PostsInChannelSchema,
|
||||
|
|
|
|||
|
|
@ -47,12 +47,12 @@ const {
|
|||
USER,
|
||||
} = MM_TABLES.SERVER;
|
||||
|
||||
const {PLAYBOOK_RUN, PLAYBOOK_CHECKLIST, PLAYBOOK_CHECKLIST_ITEM} = PLAYBOOK_TABLES;
|
||||
const {PLAYBOOK_RUN, PLAYBOOK_CHECKLIST, PLAYBOOK_CHECKLIST_ITEM, PLAYBOOK_RUN_ATTRIBUTE, PLAYBOOK_RUN_ATTRIBUTE_VALUE} = PLAYBOOK_TABLES;
|
||||
|
||||
describe('*** Test schema for SERVER database ***', () => {
|
||||
it('=> The SERVER SCHEMA should strictly match', () => {
|
||||
expect(serverSchema).toEqual({
|
||||
version: 13,
|
||||
version: 14,
|
||||
unsafeSql: undefined,
|
||||
tables: {
|
||||
[CATEGORY]: {
|
||||
|
|
@ -553,6 +553,46 @@ describe('*** Test schema for SERVER database ***', () => {
|
|||
{name: 'update_at', type: 'number'},
|
||||
],
|
||||
},
|
||||
[PLAYBOOK_RUN_ATTRIBUTE]: {
|
||||
name: PLAYBOOK_RUN_ATTRIBUTE,
|
||||
unsafeSql: undefined,
|
||||
columns: {
|
||||
group_id: {name: 'group_id', type: 'string'},
|
||||
name: {name: 'name', type: 'string'},
|
||||
type: {name: 'type', type: 'string'},
|
||||
target_id: {name: 'target_id', type: 'string'},
|
||||
target_type: {name: 'target_type', type: 'string'},
|
||||
create_at: {name: 'create_at', type: 'number'},
|
||||
update_at: {name: 'update_at', type: 'number'},
|
||||
delete_at: {name: 'delete_at', type: 'number'},
|
||||
attrs: {name: 'attrs', type: 'string', isOptional: true},
|
||||
},
|
||||
columnArray: [
|
||||
{name: 'group_id', type: 'string'},
|
||||
{name: 'name', type: 'string'},
|
||||
{name: 'type', type: 'string'},
|
||||
{name: 'target_id', type: 'string'},
|
||||
{name: 'target_type', type: 'string'},
|
||||
{name: 'create_at', type: 'number'},
|
||||
{name: 'update_at', type: 'number'},
|
||||
{name: 'delete_at', type: 'number'},
|
||||
{name: 'attrs', type: 'string', isOptional: true},
|
||||
],
|
||||
},
|
||||
[PLAYBOOK_RUN_ATTRIBUTE_VALUE]: {
|
||||
name: PLAYBOOK_RUN_ATTRIBUTE_VALUE,
|
||||
unsafeSql: undefined,
|
||||
columns: {
|
||||
attribute_id: {name: 'attribute_id', type: 'string', isIndexed: true},
|
||||
run_id: {name: 'run_id', type: 'string', isIndexed: true},
|
||||
value: {name: 'value', type: 'string'},
|
||||
},
|
||||
columnArray: [
|
||||
{name: 'attribute_id', type: 'string', isIndexed: true},
|
||||
{name: 'run_id', type: 'string', isIndexed: true},
|
||||
{name: 'value', type: 'string'},
|
||||
],
|
||||
},
|
||||
[POSTS_IN_THREAD]: {
|
||||
name: POSTS_IN_THREAD,
|
||||
unsafeSql: undefined,
|
||||
|
|
|
|||
|
|
@ -5,4 +5,6 @@ export const PLAYBOOK_TABLES = {
|
|||
PLAYBOOK_RUN: 'PlaybookRun',
|
||||
PLAYBOOK_CHECKLIST: 'PlaybookChecklist',
|
||||
PLAYBOOK_CHECKLIST_ITEM: 'PlaybookChecklistItem',
|
||||
PLAYBOOK_RUN_ATTRIBUTE: 'PlaybookRunAttribute',
|
||||
PLAYBOOK_RUN_ATTRIBUTE_VALUE: 'PlaybookRunAttributeValue',
|
||||
};
|
||||
|
|
|
|||
|
|
@ -4,3 +4,5 @@
|
|||
export {default as PlaybookRunModel} from './playbook_run';
|
||||
export {default as PlaybookChecklistModel} from './playbook_checklist';
|
||||
export {default as PlaybookChecklistItemModel} from './playbook_checklist_item';
|
||||
export {default as PlaybookRunAttributeModel} from './playbook_run_attribute';
|
||||
export {default as PlaybookRunAttributeValueModel} from './playbook_run_attribute_value';
|
||||
|
|
|
|||
|
|
@ -0,0 +1,113 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import DatabaseManager from '@database/manager';
|
||||
import {PLAYBOOK_TABLES} from '@playbooks/constants/database';
|
||||
import TestHelper from '@test/test_helper';
|
||||
|
||||
import PlaybookRunAttributeModel from './playbook_run_attribute';
|
||||
|
||||
import type ServerDataOperator from '@database/operator/server_data_operator';
|
||||
|
||||
const {PLAYBOOK_RUN_ATTRIBUTE} = PLAYBOOK_TABLES;
|
||||
|
||||
const SERVER_URL = `playbookRunAttributeModel.test.${Date.now()}.com`;
|
||||
|
||||
const applyMockData = (attribute: PlaybookRunAttributeModel, mockData: PlaybookRunAttribute, includeAttrs = true) => {
|
||||
attribute._raw.id = mockData.id;
|
||||
attribute.groupId = mockData.group_id;
|
||||
attribute.name = mockData.name;
|
||||
attribute.type = mockData.type;
|
||||
attribute.targetId = mockData.target_id;
|
||||
attribute.targetType = mockData.target_type;
|
||||
attribute.createAt = mockData.create_at;
|
||||
attribute.updateAt = mockData.update_at;
|
||||
attribute.deleteAt = mockData.delete_at;
|
||||
if (includeAttrs) {
|
||||
attribute.attrs = mockData.attrs || '{"placeholder": "Enter value"}';
|
||||
}
|
||||
};
|
||||
|
||||
describe('PlaybookRunAttributeModel', () => {
|
||||
let operator: ServerDataOperator;
|
||||
let playbook_run_attribute: PlaybookRunAttributeModel;
|
||||
|
||||
beforeEach(async () => {
|
||||
await DatabaseManager.init([SERVER_URL]);
|
||||
operator = DatabaseManager.serverDatabases[SERVER_URL]!.operator;
|
||||
const {database} = operator;
|
||||
|
||||
await database.write(async () => {
|
||||
playbook_run_attribute = await database.get<PlaybookRunAttributeModel>(PLAYBOOK_RUN_ATTRIBUTE).create((attribute: PlaybookRunAttributeModel) => {
|
||||
applyMockData(attribute, TestHelper.createPlaybookRunAttribute('test', 0));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await DatabaseManager.destroyServerDatabase(SERVER_URL);
|
||||
});
|
||||
|
||||
it('=> should match model', () => {
|
||||
expect(playbook_run_attribute).toBeDefined();
|
||||
expect(playbook_run_attribute.id).toBe('test-attribute_0');
|
||||
expect(playbook_run_attribute.groupId).toBe('group_1');
|
||||
expect(playbook_run_attribute.name).toBe('Attribute 1');
|
||||
expect(playbook_run_attribute.type).toBe('text');
|
||||
expect(playbook_run_attribute.targetId).toBe('test');
|
||||
expect(playbook_run_attribute.targetType).toBe('playbook_run');
|
||||
expect(playbook_run_attribute.createAt).toBeGreaterThan(0);
|
||||
expect(playbook_run_attribute.updateAt).toBeGreaterThan(0);
|
||||
expect(playbook_run_attribute.deleteAt).toBe(0);
|
||||
expect(playbook_run_attribute.attrs).toBe('{"placeholder": "Enter value"}');
|
||||
});
|
||||
|
||||
it('=> should have the correct table name', () => {
|
||||
expect(PlaybookRunAttributeModel.table).toBe(PLAYBOOK_RUN_ATTRIBUTE);
|
||||
});
|
||||
|
||||
it('=> should handle optional attrs field', async () => {
|
||||
let attributeWithoutAttrs: PlaybookRunAttributeModel;
|
||||
const {database} = operator;
|
||||
|
||||
await database.write(async () => {
|
||||
attributeWithoutAttrs = await database.get<PlaybookRunAttributeModel>(PLAYBOOK_RUN_ATTRIBUTE).create((attribute: PlaybookRunAttributeModel) => {
|
||||
applyMockData(attribute, TestHelper.createPlaybookRunAttribute('test', 1), false);
|
||||
});
|
||||
});
|
||||
|
||||
expect(attributeWithoutAttrs!).toBeDefined();
|
||||
expect(attributeWithoutAttrs!.id).toBe('test-attribute_1');
|
||||
expect(attributeWithoutAttrs!.attrs).toBeNull();
|
||||
});
|
||||
|
||||
it('=> should allow updating fields', async () => {
|
||||
const {database} = operator;
|
||||
|
||||
await database.write(async () => {
|
||||
await playbook_run_attribute.update((attribute: PlaybookRunAttributeModel) => {
|
||||
attribute.name = 'Updated Attribute Name';
|
||||
attribute.type = 'number';
|
||||
attribute.updateAt = 1620000005000;
|
||||
attribute.attrs = '{"min": 0, "max": 100}';
|
||||
});
|
||||
});
|
||||
|
||||
expect(playbook_run_attribute.name).toBe('Updated Attribute Name');
|
||||
expect(playbook_run_attribute.type).toBe('number');
|
||||
expect(playbook_run_attribute.updateAt).toBe(1620000005000);
|
||||
expect(playbook_run_attribute.attrs).toBe('{"min": 0, "max": 100}');
|
||||
});
|
||||
|
||||
it('=> should handle deleteAt field correctly', async () => {
|
||||
const {database} = operator;
|
||||
|
||||
await database.write(async () => {
|
||||
await playbook_run_attribute.update((attribute: PlaybookRunAttributeModel) => {
|
||||
attribute.deleteAt = 1620000010000;
|
||||
});
|
||||
});
|
||||
|
||||
expect(playbook_run_attribute.deleteAt).toBe(1620000010000);
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {field} from '@nozbe/watermelondb/decorators';
|
||||
import Model, {type Associations} from '@nozbe/watermelondb/Model';
|
||||
|
||||
import {PLAYBOOK_TABLES} from '@playbooks/constants/database';
|
||||
|
||||
import type PlaybookRunAttributeModelInterface from '@playbooks/types/database/models/playbook_run_attribute';
|
||||
|
||||
const {PLAYBOOK_RUN_ATTRIBUTE, PLAYBOOK_RUN_ATTRIBUTE_VALUE} = PLAYBOOK_TABLES;
|
||||
|
||||
/**
|
||||
* The model represents a playbook run attribute definition in the Mattermost app.
|
||||
*/
|
||||
export default class PlaybookRunAttributeModel extends Model implements PlaybookRunAttributeModelInterface {
|
||||
/** table (name) : PlaybookRunAttribute */
|
||||
static table = PLAYBOOK_RUN_ATTRIBUTE;
|
||||
|
||||
/** associations : Describes every relationship to this table. */
|
||||
static associations: Associations = {
|
||||
[PLAYBOOK_RUN_ATTRIBUTE_VALUE]: {type: 'has_many', foreignKey: 'attribute_id'},
|
||||
};
|
||||
|
||||
/** groupId : The group ID of the attribute */
|
||||
@field('group_id') groupId!: string;
|
||||
|
||||
/** name : The name of the attribute */
|
||||
@field('name') name!: string;
|
||||
|
||||
/** type : The type of the attribute */
|
||||
@field('type') type!: string;
|
||||
|
||||
/** targetId : The target ID of the attribute */
|
||||
@field('target_id') targetId!: string;
|
||||
|
||||
/** targetType : The target type of the attribute */
|
||||
@field('target_type') targetType!: string;
|
||||
|
||||
/** createAt : The timestamp of when the attribute was created */
|
||||
@field('create_at') createAt!: number;
|
||||
|
||||
/** updateAt : The timestamp of when the attribute was last updated */
|
||||
@field('update_at') updateAt!: number;
|
||||
|
||||
/** deleteAt : The timestamp of when the attribute was deleted */
|
||||
@field('delete_at') deleteAt!: number;
|
||||
|
||||
/** attrs : Additional attributes for the attribute (JSON string) */
|
||||
@field('attrs') attrs?: string;
|
||||
}
|
||||
|
|
@ -0,0 +1,175 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import DatabaseManager from '@database/manager';
|
||||
import {PLAYBOOK_TABLES} from '@playbooks/constants/database';
|
||||
import TestHelper from '@test/test_helper';
|
||||
|
||||
import PlaybookRunModel from './playbook_run';
|
||||
import PlaybookRunAttributeModel from './playbook_run_attribute';
|
||||
import PlaybookRunAttributeValueModel from './playbook_run_attribute_value';
|
||||
|
||||
import type ServerDataOperator from '@database/operator/server_data_operator';
|
||||
|
||||
const {PLAYBOOK_RUN_ATTRIBUTE_VALUE, PLAYBOOK_RUN_ATTRIBUTE, PLAYBOOK_RUN} = PLAYBOOK_TABLES;
|
||||
|
||||
const SERVER_URL = `playbookRunAttributeValueModel.test.${Date.now()}.com`;
|
||||
|
||||
const applyRunData = (run: PlaybookRunModel, mockData: PlaybookRun) => {
|
||||
run._raw.id = mockData.id;
|
||||
run.playbookId = mockData.playbook_id;
|
||||
run.postId = mockData.post_id ?? null;
|
||||
run.ownerUserId = mockData.owner_user_id;
|
||||
run.teamId = mockData.team_id;
|
||||
run.channelId = mockData.channel_id;
|
||||
run.createAt = mockData.create_at;
|
||||
run.endAt = mockData.end_at;
|
||||
run.name = mockData.name;
|
||||
run.description = mockData.description;
|
||||
run.isActive = mockData.is_active;
|
||||
run.activeStage = mockData.active_stage;
|
||||
run.activeStageTitle = mockData.active_stage_title;
|
||||
run.participantIds = mockData.participant_ids;
|
||||
run.summary = mockData.summary;
|
||||
run.currentStatus = mockData.current_status;
|
||||
run.lastStatusUpdateAt = mockData.last_status_update_at;
|
||||
run.retrospectiveEnabled = mockData.retrospective_enabled;
|
||||
run.retrospective = mockData.retrospective;
|
||||
run.retrospectivePublishedAt = mockData.retrospective_published_at;
|
||||
run.updateAt = mockData.update_at;
|
||||
};
|
||||
|
||||
const applyAttributeData = (attribute: PlaybookRunAttributeModel, mockData: PlaybookRunAttribute) => {
|
||||
attribute._raw.id = mockData.id;
|
||||
attribute.groupId = mockData.group_id;
|
||||
attribute.name = mockData.name;
|
||||
attribute.type = mockData.type;
|
||||
attribute.targetId = mockData.target_id;
|
||||
attribute.targetType = mockData.target_type;
|
||||
attribute.createAt = mockData.create_at;
|
||||
attribute.updateAt = mockData.update_at;
|
||||
attribute.deleteAt = mockData.delete_at;
|
||||
attribute.attrs = mockData.attrs;
|
||||
};
|
||||
|
||||
const applyAttributeValueData = (attributeValue: PlaybookRunAttributeValueModel, mockData: PlaybookRunAttributeValue) => {
|
||||
attributeValue._raw.id = mockData.id;
|
||||
attributeValue.attributeId = mockData.attribute_id;
|
||||
attributeValue.runId = mockData.run_id;
|
||||
attributeValue.value = mockData.value;
|
||||
};
|
||||
|
||||
describe('PlaybookRunAttributeValueModel', () => {
|
||||
let operator: ServerDataOperator;
|
||||
let playbook_run_attribute_value: PlaybookRunAttributeValueModel;
|
||||
|
||||
beforeEach(async () => {
|
||||
await DatabaseManager.init([SERVER_URL]);
|
||||
operator = DatabaseManager.serverDatabases[SERVER_URL]!.operator;
|
||||
const {database} = operator;
|
||||
|
||||
const mockRun = TestHelper.createPlaybookRuns(1, 0, 0)[0];
|
||||
const mockAttribute = TestHelper.createPlaybookRunAttribute('test', 0);
|
||||
const mockAttributeValue = TestHelper.createPlaybookRunAttributeValue(mockAttribute.id, mockRun.id, 0);
|
||||
|
||||
await database.write(async () => {
|
||||
await database.get<PlaybookRunModel>(PLAYBOOK_RUN).create((run) => applyRunData(run, mockRun));
|
||||
await database.get<PlaybookRunAttributeModel>(PLAYBOOK_RUN_ATTRIBUTE).create((attr) => applyAttributeData(attr, mockAttribute));
|
||||
playbook_run_attribute_value = await database.get<PlaybookRunAttributeValueModel>(PLAYBOOK_RUN_ATTRIBUTE_VALUE).create((attrVal) => applyAttributeValueData(attrVal, mockAttributeValue));
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await DatabaseManager.destroyServerDatabase(SERVER_URL);
|
||||
});
|
||||
|
||||
it('=> should match model', () => {
|
||||
expect(playbook_run_attribute_value).toBeDefined();
|
||||
expect(playbook_run_attribute_value.id).toBe('playbook_run_0-test-attribute_0-value_0');
|
||||
expect(playbook_run_attribute_value.attributeId).toBe('test-attribute_0');
|
||||
expect(playbook_run_attribute_value.runId).toBe('playbook_run_0');
|
||||
expect(playbook_run_attribute_value.value).toBe('Value 1');
|
||||
});
|
||||
|
||||
it('=> should have the correct table name', () => {
|
||||
expect(PlaybookRunAttributeValueModel.table).toBe(PLAYBOOK_RUN_ATTRIBUTE_VALUE);
|
||||
});
|
||||
|
||||
it('=> should have correct associations defined', () => {
|
||||
expect(PlaybookRunAttributeValueModel.associations).toBeDefined();
|
||||
expect(PlaybookRunAttributeValueModel.associations[PLAYBOOK_RUN_ATTRIBUTE]).toEqual({
|
||||
type: 'belongs_to',
|
||||
key: 'attribute_id',
|
||||
});
|
||||
expect(PlaybookRunAttributeValueModel.associations[PLAYBOOK_RUN]).toEqual({
|
||||
type: 'belongs_to',
|
||||
key: 'run_id',
|
||||
});
|
||||
});
|
||||
|
||||
it('=> should have attribute relation', async () => {
|
||||
const attributeRelation = playbook_run_attribute_value.attribute;
|
||||
expect(attributeRelation).toBeDefined();
|
||||
|
||||
const relatedAttribute = await attributeRelation.fetch();
|
||||
expect(relatedAttribute).toBeDefined();
|
||||
expect(relatedAttribute!.id).toBe('test-attribute_0');
|
||||
expect(relatedAttribute!.name).toBe('Attribute 1');
|
||||
});
|
||||
|
||||
it('=> should have run relation', async () => {
|
||||
const runRelation = playbook_run_attribute_value.run;
|
||||
expect(runRelation).toBeDefined();
|
||||
|
||||
const relatedRun = await runRelation.fetch();
|
||||
expect(relatedRun).toBeDefined();
|
||||
expect(relatedRun!.id).toBe('playbook_run_0');
|
||||
expect(relatedRun!.name).toBe('Playbook Run 1');
|
||||
});
|
||||
|
||||
it('=> should allow updating value', async () => {
|
||||
const {database} = operator;
|
||||
|
||||
await database.write(async () => {
|
||||
await playbook_run_attribute_value.update((attributeValue: PlaybookRunAttributeValueModel) => {
|
||||
attributeValue.value = 'Updated Test Value';
|
||||
});
|
||||
});
|
||||
|
||||
expect(playbook_run_attribute_value.value).toBe('Updated Test Value');
|
||||
});
|
||||
|
||||
it('=> should handle empty value', async () => {
|
||||
let attributeValueWithEmptyValue: PlaybookRunAttributeValueModel;
|
||||
const {database} = operator;
|
||||
|
||||
await database.write(async () => {
|
||||
const mockData = TestHelper.createPlaybookRunAttributeValue('test-attribute_0', 'playbook_run_0', 1);
|
||||
attributeValueWithEmptyValue = await database.get<PlaybookRunAttributeValueModel>(PLAYBOOK_RUN_ATTRIBUTE_VALUE).create((attributeValue: PlaybookRunAttributeValueModel) => {
|
||||
applyAttributeValueData(attributeValue, mockData);
|
||||
attributeValue.value = '';
|
||||
});
|
||||
});
|
||||
|
||||
expect(attributeValueWithEmptyValue!).toBeDefined();
|
||||
expect(attributeValueWithEmptyValue!.value).toBe('');
|
||||
});
|
||||
|
||||
it('=> should handle long text values', async () => {
|
||||
const longValue = 'This is a very long text value that might be used to store detailed information about the playbook run attribute. It could contain multiple sentences and various types of content.';
|
||||
|
||||
let attributeValueWithLongText: PlaybookRunAttributeValueModel;
|
||||
const {database} = operator;
|
||||
|
||||
await database.write(async () => {
|
||||
const mockData = TestHelper.createPlaybookRunAttributeValue('test-attribute_0', 'playbook_run_0', 2);
|
||||
attributeValueWithLongText = await database.get<PlaybookRunAttributeValueModel>(PLAYBOOK_RUN_ATTRIBUTE_VALUE).create((attributeValue: PlaybookRunAttributeValueModel) => {
|
||||
applyAttributeValueData(attributeValue, mockData);
|
||||
attributeValue.value = longValue;
|
||||
});
|
||||
});
|
||||
|
||||
expect(attributeValueWithLongText!).toBeDefined();
|
||||
expect(attributeValueWithLongText!.value).toBe(longValue);
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {field, immutableRelation} from '@nozbe/watermelondb/decorators';
|
||||
import Model, {type Associations} from '@nozbe/watermelondb/Model';
|
||||
|
||||
import {PLAYBOOK_TABLES} from '@playbooks/constants/database';
|
||||
|
||||
import type PlaybookRunModel from './playbook_run';
|
||||
import type PlaybookRunAttributeModel from './playbook_run_attribute';
|
||||
import type {Relation} from '@nozbe/watermelondb';
|
||||
import type PlaybookRunAttributeValueModelInterface from '@playbooks/types/database/models/playbook_run_attribute_value';
|
||||
|
||||
const {PLAYBOOK_RUN, PLAYBOOK_RUN_ATTRIBUTE, PLAYBOOK_RUN_ATTRIBUTE_VALUE} = PLAYBOOK_TABLES;
|
||||
|
||||
/**
|
||||
* The PlaybookRunAttributeValue model represents a playbook run attribute value in the Mattermost app.
|
||||
*/
|
||||
export default class PlaybookRunAttributeValueModel extends Model implements PlaybookRunAttributeValueModelInterface {
|
||||
/** table (name) : PlaybookRunAttributeValue */
|
||||
static table = PLAYBOOK_RUN_ATTRIBUTE_VALUE;
|
||||
|
||||
/** associations : Describes every relationship to this table. */
|
||||
static associations: Associations = {
|
||||
|
||||
/** A PLAYBOOK_RUN_ATTRIBUTE is associated to a PLAYBOOK_RUN_ATTRIBUTE_VALUE (relationship is 1:1) */
|
||||
[PLAYBOOK_RUN_ATTRIBUTE]: {type: 'belongs_to', key: 'attribute_id'},
|
||||
|
||||
/** A PLAYBOOK_RUN is associated to a PLAYBOOK_RUN_ATTRIBUTE (relationship is 1:1) */
|
||||
[PLAYBOOK_RUN]: {type: 'belongs_to', key: 'run_id'},
|
||||
};
|
||||
|
||||
/** attributeId : The ID of the attribute this attribute value belongs to */
|
||||
@field('attribute_id') attributeId!: string;
|
||||
|
||||
/** runId : The ID of the playbook run this attribute belongs to */
|
||||
@field('run_id') runId!: string;
|
||||
|
||||
/** value : The value of the attribute */
|
||||
@field('value') value!: string;
|
||||
|
||||
/** attribute : The attribute this attribute value belongs to */
|
||||
@immutableRelation(PLAYBOOK_RUN_ATTRIBUTE, 'attribute_id') attribute!: Relation<PlaybookRunAttributeModel>;
|
||||
|
||||
/** run : The playbook run this attribute belongs to */
|
||||
@immutableRelation(PLAYBOOK_RUN, 'run_id') run!: Relation<PlaybookRunModel>;
|
||||
}
|
||||
|
|
@ -8,7 +8,7 @@ import TestHelper from '@test/test_helper';
|
|||
|
||||
import type ServerDataOperator from '@database/operator/server_data_operator';
|
||||
|
||||
const {PLAYBOOK_RUN, PLAYBOOK_CHECKLIST, PLAYBOOK_CHECKLIST_ITEM} = PLAYBOOK_TABLES;
|
||||
const {PLAYBOOK_RUN, PLAYBOOK_CHECKLIST, PLAYBOOK_CHECKLIST_ITEM, PLAYBOOK_RUN_ATTRIBUTE, PLAYBOOK_RUN_ATTRIBUTE_VALUE} = PLAYBOOK_TABLES;
|
||||
|
||||
describe('PlaybookHandler', () => {
|
||||
let operator: ServerDataOperator;
|
||||
|
|
@ -553,4 +553,154 @@ describe('PlaybookHandler', () => {
|
|||
expect(checklistItemRecords.length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('handlePlaybookRunAttribute', () => {
|
||||
it('should return an empty array if attributes is undefined or empty', async () => {
|
||||
const spyOnPrepareRecords = jest.spyOn(operator, 'prepareRecords');
|
||||
|
||||
let result = await operator.handlePlaybookRunAttribute({
|
||||
attributes: undefined,
|
||||
prepareRecordsOnly: true,
|
||||
});
|
||||
|
||||
expect(result).toEqual([]);
|
||||
expect(spyOnPrepareRecords).not.toHaveBeenCalled();
|
||||
|
||||
result = await operator.handlePlaybookRunAttribute({
|
||||
attributes: [],
|
||||
prepareRecordsOnly: true,
|
||||
});
|
||||
|
||||
expect(result).toEqual([]);
|
||||
expect(spyOnPrepareRecords).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should process attributes correctly', async () => {
|
||||
const mockAttributes = [
|
||||
TestHelper.createPlaybookRunAttribute('attribute_1', 0),
|
||||
TestHelper.createPlaybookRunAttribute('attribute_2', 1),
|
||||
].map<PartialPlaybookRunAttribute>((attribute, index) => ({
|
||||
...attribute,
|
||||
run_id: 'playbook_run_1',
|
||||
order: index,
|
||||
}));
|
||||
|
||||
const spyOnPrepareRecords = jest.spyOn(operator, 'prepareRecords');
|
||||
const spyOnBatchOperation = jest.spyOn(operator, 'batchRecords');
|
||||
|
||||
const result = await operator.handlePlaybookRunAttribute({
|
||||
attributes: mockAttributes,
|
||||
prepareRecordsOnly: false,
|
||||
});
|
||||
|
||||
expect(result).toBeDefined();
|
||||
expect(result.length).toBe(mockAttributes.length);
|
||||
expect(spyOnPrepareRecords).toHaveBeenCalledTimes(1);
|
||||
expect(spyOnBatchOperation).toHaveBeenCalledTimes(1);
|
||||
|
||||
const {database} = operator;
|
||||
|
||||
const attributeRecords = await database.get(PLAYBOOK_RUN_ATTRIBUTE).query().fetch();
|
||||
expect(attributeRecords.length).toBe(mockAttributes.length);
|
||||
});
|
||||
|
||||
it('should only prepare records when prepareRecordsOnly is true', async () => {
|
||||
const mockAttributes = [
|
||||
TestHelper.createPlaybookRunAttribute('attribute_3', 2),
|
||||
].map<PartialPlaybookRunAttribute>((attribute, index) => ({
|
||||
...attribute,
|
||||
run_id: 'playbook_run_1',
|
||||
order: index,
|
||||
}));
|
||||
|
||||
const spyOnPrepareRecords = jest.spyOn(operator, 'prepareRecords');
|
||||
const spyOnBatchOperation = jest.spyOn(operator, 'batchRecords');
|
||||
|
||||
const result = await operator.handlePlaybookRunAttribute({
|
||||
attributes: mockAttributes,
|
||||
prepareRecordsOnly: true,
|
||||
});
|
||||
|
||||
expect(result).toBeDefined();
|
||||
expect(result.length).toBe(mockAttributes.length);
|
||||
expect(spyOnPrepareRecords).toHaveBeenCalledTimes(1);
|
||||
expect(spyOnBatchOperation).not.toHaveBeenCalled();
|
||||
|
||||
const {database} = operator;
|
||||
|
||||
const attributeRecords = await database.get(PLAYBOOK_RUN_ATTRIBUTE).query().fetch();
|
||||
expect(attributeRecords.length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('handlePlaybookRunAttributeValue', () => {
|
||||
it('should return an empty array if attributeValues is undefined or empty', async () => {
|
||||
const spyOnPrepareRecords = jest.spyOn(operator, 'prepareRecords');
|
||||
|
||||
let result = await operator.handlePlaybookRunAttributeValue({
|
||||
attributeValues: undefined,
|
||||
prepareRecordsOnly: true,
|
||||
});
|
||||
|
||||
expect(result).toEqual([]);
|
||||
expect(spyOnPrepareRecords).not.toHaveBeenCalled();
|
||||
|
||||
result = await operator.handlePlaybookRunAttributeValue({
|
||||
attributeValues: [],
|
||||
prepareRecordsOnly: true,
|
||||
});
|
||||
|
||||
expect(result).toEqual([]);
|
||||
expect(spyOnPrepareRecords).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should process attribute values correctly', async () => {
|
||||
const mockAttributeValues = [
|
||||
TestHelper.createPlaybookRunAttributeValue('attribute_1', 'playbook_run_1', 0),
|
||||
TestHelper.createPlaybookRunAttributeValue('attribute_2', 'playbook_run_2', 1),
|
||||
];
|
||||
|
||||
const spyOnPrepareRecords = jest.spyOn(operator, 'prepareRecords');
|
||||
const spyOnBatchOperation = jest.spyOn(operator, 'batchRecords');
|
||||
|
||||
const result = await operator.handlePlaybookRunAttributeValue({
|
||||
attributeValues: mockAttributeValues,
|
||||
prepareRecordsOnly: false,
|
||||
});
|
||||
|
||||
expect(result).toBeDefined();
|
||||
expect(result.length).toBe(mockAttributeValues.length);
|
||||
expect(spyOnPrepareRecords).toHaveBeenCalledTimes(1);
|
||||
expect(spyOnBatchOperation).toHaveBeenCalledTimes(1);
|
||||
|
||||
const {database} = operator;
|
||||
|
||||
const attributeValueRecords = await database.get(PLAYBOOK_RUN_ATTRIBUTE_VALUE).query().fetch();
|
||||
expect(attributeValueRecords.length).toBe(mockAttributeValues.length);
|
||||
});
|
||||
|
||||
it('should only prepare records when prepareRecordsOnly is true', async () => {
|
||||
const mockAttributeValues = [
|
||||
TestHelper.createPlaybookRunAttributeValue('attribute_3', 'playbook_run_3', 2),
|
||||
];
|
||||
|
||||
const spyOnPrepareRecords = jest.spyOn(operator, 'prepareRecords');
|
||||
const spyOnBatchOperation = jest.spyOn(operator, 'batchRecords');
|
||||
|
||||
const result = await operator.handlePlaybookRunAttributeValue({
|
||||
attributeValues: mockAttributeValues,
|
||||
prepareRecordsOnly: true,
|
||||
});
|
||||
|
||||
expect(result).toBeDefined();
|
||||
expect(result.length).toBe(mockAttributeValues.length);
|
||||
expect(spyOnPrepareRecords).toHaveBeenCalledTimes(1);
|
||||
expect(spyOnBatchOperation).not.toHaveBeenCalled();
|
||||
|
||||
const {database} = operator;
|
||||
|
||||
const attributeValueRecords = await database.get(PLAYBOOK_RUN_ATTRIBUTE_VALUE).query().fetch();
|
||||
expect(attributeValueRecords.length).toBe(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import {PLAYBOOK_TABLES} from '@playbooks/constants/database';
|
|||
import {logWarning} from '@utils/log';
|
||||
|
||||
import {shouldHandlePlaybookChecklistItemRecord, shouldHandlePlaybookChecklistRecord, shouldUpdatePlaybookRunRecord} from '../comparators';
|
||||
import {transformPlaybookChecklistItemRecord, transformPlaybookChecklistRecord, transformPlaybookRunRecord} from '../transformers';
|
||||
import {transformPlaybookChecklistItemRecord, transformPlaybookChecklistRecord, transformPlaybookRunRecord, transformPlaybookRunAttributeRecord, transformPlaybookRunAttributeValueRecord} from '../transformers';
|
||||
|
||||
import type ServerDataOperatorBase from '@database/operator/server_data_operator/handlers';
|
||||
import type PlaybookChecklistModel from '@playbooks/types/database/models/playbook_checklist';
|
||||
|
|
@ -34,12 +34,24 @@ type HandlePlaybookChecklistItemArgs = {
|
|||
items?: PartialChecklistItem[];
|
||||
}
|
||||
|
||||
const {PLAYBOOK_RUN, PLAYBOOK_CHECKLIST, PLAYBOOK_CHECKLIST_ITEM} = PLAYBOOK_TABLES;
|
||||
type HandlePlaybookRunAttributeArgs = {
|
||||
prepareRecordsOnly: boolean;
|
||||
attributes?: PartialPlaybookRunAttribute[];
|
||||
}
|
||||
|
||||
type HandlePlaybookRunAttributeValueArgs = {
|
||||
prepareRecordsOnly: boolean;
|
||||
attributeValues?: PartialPlaybookRunAttributeValue[];
|
||||
}
|
||||
|
||||
const {PLAYBOOK_RUN, PLAYBOOK_CHECKLIST, PLAYBOOK_CHECKLIST_ITEM, PLAYBOOK_RUN_ATTRIBUTE, PLAYBOOK_RUN_ATTRIBUTE_VALUE} = PLAYBOOK_TABLES;
|
||||
|
||||
export interface PlaybookHandlerMix {
|
||||
handlePlaybookRun: (args: HandlePlaybookRunArgs) => Promise<Model[]>;
|
||||
handlePlaybookChecklist: (args: HandlePlaybookChecklistArgs) => Promise<Model[]>;
|
||||
handlePlaybookChecklistItem: (args: HandlePlaybookChecklistItemArgs) => Promise<PlaybookChecklistItemModel[]>;
|
||||
handlePlaybookRunAttribute: (args: HandlePlaybookRunAttributeArgs) => Promise<Model[]>;
|
||||
handlePlaybookRunAttributeValue: (args: HandlePlaybookRunAttributeValueArgs) => Promise<Model[]>;
|
||||
}
|
||||
|
||||
const PlaybookHandler = <TBase extends Constructor<ServerDataOperatorBase>>(superclass: TBase) => class extends superclass {
|
||||
|
|
@ -274,6 +286,58 @@ const PlaybookHandler = <TBase extends Constructor<ServerDataOperatorBase>>(supe
|
|||
|
||||
return records;
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles the playbook run attribute records.
|
||||
* @param {HandlePlaybookRunAttributeArgs} args - The arguments for handling playbook run attribute records.
|
||||
* @param {boolean} args.prepareRecordsOnly - If true, only prepares the records without saving them.
|
||||
* @param {PlaybookRunAttribute[]} [args.attributes] - The playbook run attribute records to handle.
|
||||
* @returns {Promise<Model[]>} - A promise that resolves to an array of handled playbook run attribute records.
|
||||
*/
|
||||
handlePlaybookRunAttribute = async ({attributes, prepareRecordsOnly = true}: HandlePlaybookRunAttributeArgs): Promise<Model[]> => {
|
||||
if (!attributes?.length) {
|
||||
logWarning(
|
||||
'An empty or undefined "attributes" array has been passed to the handlePlaybookRunAttribute method',
|
||||
);
|
||||
return [];
|
||||
}
|
||||
|
||||
const createOrUpdateRawValues = getUniqueRawsBy({raws: attributes, key: 'id'});
|
||||
|
||||
return this.handleRecords({
|
||||
fieldName: 'id',
|
||||
transformer: transformPlaybookRunAttributeRecord,
|
||||
createOrUpdateRawValues,
|
||||
tableName: PLAYBOOK_RUN_ATTRIBUTE,
|
||||
prepareRecordsOnly,
|
||||
}, 'handlePlaybookRunAttribute');
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles the playbook run attribute value records.
|
||||
* @param {HandlePlaybookRunAttributeValueArgs} args - The arguments for handling playbook run attribute value records.
|
||||
* @param {boolean} args.prepareRecordsOnly - If true, only prepares the records without saving them.
|
||||
* @param {PlaybookRunAttributeValue[]} [args.attributeValues] - The playbook run attribute value records to handle.
|
||||
* @returns {Promise<Model[]>} - A promise that resolves to an array of handled playbook run attribute value records.
|
||||
*/
|
||||
handlePlaybookRunAttributeValue = async ({attributeValues, prepareRecordsOnly = true}: HandlePlaybookRunAttributeValueArgs): Promise<Model[]> => {
|
||||
if (!attributeValues?.length) {
|
||||
logWarning(
|
||||
'An empty or undefined "attributeValues" array has been passed to the handlePlaybookRunAttributeValue method',
|
||||
);
|
||||
return [];
|
||||
}
|
||||
|
||||
const createOrUpdateRawValues = getUniqueRawsBy({raws: attributeValues, key: 'id'});
|
||||
|
||||
return this.handleRecords({
|
||||
fieldName: 'id',
|
||||
transformer: transformPlaybookRunAttributeValueRecord,
|
||||
createOrUpdateRawValues,
|
||||
tableName: PLAYBOOK_RUN_ATTRIBUTE_VALUE,
|
||||
prepareRecordsOnly,
|
||||
}, 'handlePlaybookRunAttributeValue');
|
||||
};
|
||||
};
|
||||
|
||||
export default PlaybookHandler;
|
||||
|
|
|
|||
|
|
@ -8,12 +8,14 @@ import {createTestConnection} from '@database/operator/utils/create_test_connect
|
|||
import {PLAYBOOK_TABLES} from '@playbooks/constants/database';
|
||||
import {PlaybookRunModel} from '@playbooks/database/models';
|
||||
|
||||
import {transformPlaybookChecklistItemRecord, transformPlaybookChecklistRecord, transformPlaybookRunRecord} from '.';
|
||||
import {transformPlaybookChecklistItemRecord, transformPlaybookChecklistRecord, transformPlaybookRunRecord, transformPlaybookRunAttributeRecord, transformPlaybookRunAttributeValueRecord} from '.';
|
||||
|
||||
import type PlaybookChecklistModel from '@playbooks/types/database/models/playbook_checklist';
|
||||
import type PlaybookChecklistItemModel from '@playbooks/types/database/models/playbook_checklist_item';
|
||||
import type PlaybookRunAttributeModel from '@playbooks/types/database/models/playbook_run_attribute';
|
||||
import type PlaybookRunAttributeValueModel from '@playbooks/types/database/models/playbook_run_attribute_value';
|
||||
|
||||
const {PLAYBOOK_RUN} = PLAYBOOK_TABLES;
|
||||
const {PLAYBOOK_RUN, PLAYBOOK_RUN_ATTRIBUTE, PLAYBOOK_RUN_ATTRIBUTE_VALUE} = PLAYBOOK_TABLES;
|
||||
|
||||
describe('*** PLAYBOOK_RUN Prepare Records Test ***', () => {
|
||||
it('=> transformPlaybookRunRecord: should return a record of type PlaybookRun for CREATE action', async () => {
|
||||
|
|
@ -774,3 +776,287 @@ describe('*** PLAYBOOK_CHECKLIST_ITEM Prepare Records Test ***', () => {
|
|||
expect(preparedRecordDefault!.conditionReason).toBe('');
|
||||
});
|
||||
});
|
||||
|
||||
describe('*** PLAYBOOK_RUN_ATTRIBUTE Prepare Records Test ***', () => {
|
||||
it('=> transformPlaybookRunAttributeRecord: should return a record of type PlaybookRunAttribute for CREATE action', async () => {
|
||||
expect.assertions(3);
|
||||
|
||||
const database = await createTestConnection({databaseName: 'playbook_run_attribute_prepare_records', setActive: true});
|
||||
expect(database).toBeTruthy();
|
||||
|
||||
const preparedRecord = await transformPlaybookRunAttributeRecord({
|
||||
action: OperationType.CREATE,
|
||||
database: database!,
|
||||
value: {
|
||||
record: undefined,
|
||||
raw: {
|
||||
id: 'attribute_1',
|
||||
group_id: 'group_1',
|
||||
name: 'Test Attribute',
|
||||
type: 'text',
|
||||
target_id: 'target_1',
|
||||
target_type: 'playbook_run',
|
||||
create_at: 1620000000000,
|
||||
update_at: 1620000001000,
|
||||
delete_at: 0,
|
||||
attrs: '{"placeholder": "Enter value"}',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(preparedRecord).toBeTruthy();
|
||||
expect(preparedRecord!.collection.table).toBe(PLAYBOOK_RUN_ATTRIBUTE);
|
||||
});
|
||||
|
||||
it('=> transformPlaybookRunAttributeRecord: should return a record of type PlaybookRunAttribute for UPDATE action', async () => {
|
||||
expect.assertions(4);
|
||||
|
||||
const database = await createTestConnection({databaseName: 'playbook_run_attribute_prepare_records', setActive: true});
|
||||
expect(database).toBeTruthy();
|
||||
|
||||
let existingRecord: PlaybookRunAttributeModel | undefined;
|
||||
await database!.write(async () => {
|
||||
existingRecord = await database!.get<PlaybookRunAttributeModel>(PLAYBOOK_RUN_ATTRIBUTE).create((record) => {
|
||||
record._raw.id = 'attribute_2';
|
||||
record.groupId = 'group_2';
|
||||
record.name = 'Existing Attribute';
|
||||
record.type = 'text';
|
||||
record.targetId = 'target_2';
|
||||
record.targetType = 'playbook_run';
|
||||
record.createAt = 1620000000000;
|
||||
record.updateAt = 1620000001000;
|
||||
record.deleteAt = 0;
|
||||
record.attrs = '{"placeholder": "Original placeholder"}';
|
||||
});
|
||||
});
|
||||
|
||||
const preparedRecord = await transformPlaybookRunAttributeRecord({
|
||||
action: OperationType.UPDATE,
|
||||
database: database!,
|
||||
value: {
|
||||
record: existingRecord,
|
||||
raw: {
|
||||
id: 'attribute_2',
|
||||
group_id: 'group_2',
|
||||
name: 'Updated Attribute',
|
||||
type: 'text',
|
||||
target_id: 'target_2',
|
||||
target_type: 'playbook_run',
|
||||
create_at: 1620000000000,
|
||||
update_at: 1620000002000,
|
||||
delete_at: 0,
|
||||
attrs: '{"placeholder": "Updated placeholder"}',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await database?.write(async () => {
|
||||
await database?.batch(preparedRecord);
|
||||
});
|
||||
|
||||
expect(preparedRecord).toBeTruthy();
|
||||
expect(preparedRecord!.name).toBe('Updated Attribute');
|
||||
expect(preparedRecord!.collection.table).toBe(PLAYBOOK_RUN_ATTRIBUTE);
|
||||
});
|
||||
|
||||
it('=> transformPlaybookRunAttributeRecord: should throw an error for non-create action without an existing record', async () => {
|
||||
expect.assertions(2);
|
||||
|
||||
const database = await createTestConnection({databaseName: 'playbook_run_attribute_prepare_records', setActive: true});
|
||||
expect(database).toBeTruthy();
|
||||
|
||||
await expect(
|
||||
transformPlaybookRunAttributeRecord({
|
||||
action: OperationType.UPDATE,
|
||||
database: database!,
|
||||
value: {
|
||||
record: undefined,
|
||||
raw: {
|
||||
id: 'attribute_3',
|
||||
group_id: 'group_3',
|
||||
name: 'Invalid Attribute',
|
||||
type: 'text',
|
||||
target_id: 'target_3',
|
||||
target_type: 'playbook_run',
|
||||
create_at: 1620000000000,
|
||||
update_at: 1620000001000,
|
||||
delete_at: 0,
|
||||
},
|
||||
},
|
||||
}),
|
||||
).rejects.toThrow('Record not found for non create action');
|
||||
});
|
||||
|
||||
it('=> transformPlaybookRunAttributeRecord: should keep most of the data if the partial attribute is empty', async () => {
|
||||
const database = await createTestConnection({databaseName: 'playbook_run_attribute_prepare_records', setActive: true});
|
||||
expect(database).toBeTruthy();
|
||||
|
||||
let existingRecord: PlaybookRunAttributeModel | undefined;
|
||||
await database!.write(async () => {
|
||||
existingRecord = await database!.get<PlaybookRunAttributeModel>(PLAYBOOK_RUN_ATTRIBUTE).create((record) => {
|
||||
record._raw.id = 'attribute_2';
|
||||
record.groupId = 'group_2';
|
||||
record.name = 'Existing Attribute';
|
||||
record.type = 'text';
|
||||
record.targetId = 'target_2';
|
||||
record.targetType = 'playbook_run';
|
||||
record.createAt = 1620000000000;
|
||||
record.updateAt = 1620000001000;
|
||||
record.deleteAt = 0;
|
||||
record.attrs = '{"placeholder": "Original"}';
|
||||
});
|
||||
});
|
||||
|
||||
const preparedRecord = await transformPlaybookRunAttributeRecord({
|
||||
action: OperationType.UPDATE,
|
||||
database: database!,
|
||||
value: {
|
||||
record: existingRecord,
|
||||
raw: {
|
||||
id: 'attribute_2',
|
||||
update_at: 1620000004000,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await database?.write(async () => {
|
||||
await database?.batch(preparedRecord);
|
||||
});
|
||||
|
||||
expect(preparedRecord).toBeTruthy();
|
||||
expect(preparedRecord.groupId).toBe('group_2');
|
||||
expect(preparedRecord.name).toBe('Existing Attribute');
|
||||
expect(preparedRecord.type).toBe('text');
|
||||
expect(preparedRecord.targetId).toBe('target_2');
|
||||
expect(preparedRecord.targetType).toBe('playbook_run');
|
||||
expect(preparedRecord.createAt).toBe(1620000000000);
|
||||
expect(preparedRecord.deleteAt).toBe(0);
|
||||
expect(preparedRecord.attrs).toBe('{"placeholder": "Original"}');
|
||||
expect(preparedRecord.updateAt).toBe(1620000004000);
|
||||
});
|
||||
});
|
||||
|
||||
describe('*** PLAYBOOK_RUN_ATTRIBUTE_VALUE Prepare Records Test ***', () => {
|
||||
it('=> transformPlaybookRunAttributeValueRecord: should return a record of type PlaybookRunAttributeValue for CREATE action', async () => {
|
||||
expect.assertions(3);
|
||||
|
||||
const database = await createTestConnection({databaseName: 'playbook_run_attribute_value_prepare_records', setActive: true});
|
||||
expect(database).toBeTruthy();
|
||||
|
||||
const preparedRecord = await transformPlaybookRunAttributeValueRecord({
|
||||
action: OperationType.CREATE,
|
||||
database: database!,
|
||||
value: {
|
||||
record: undefined,
|
||||
raw: {
|
||||
id: 'attribute_value_1',
|
||||
attribute_id: 'attribute_1',
|
||||
run_id: 'playbook_run_1',
|
||||
value: 'Test Value',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(preparedRecord).toBeTruthy();
|
||||
expect(preparedRecord!.collection.table).toBe(PLAYBOOK_RUN_ATTRIBUTE_VALUE);
|
||||
});
|
||||
|
||||
it('=> transformPlaybookRunAttributeValueRecord: should return a record of type PlaybookRunAttributeValue for UPDATE action', async () => {
|
||||
expect.assertions(4);
|
||||
|
||||
const database = await createTestConnection({databaseName: 'playbook_run_attribute_value_prepare_records', setActive: true});
|
||||
expect(database).toBeTruthy();
|
||||
|
||||
let existingRecord: PlaybookRunAttributeValueModel | undefined;
|
||||
await database!.write(async () => {
|
||||
existingRecord = await database!.get<PlaybookRunAttributeValueModel>(PLAYBOOK_RUN_ATTRIBUTE_VALUE).create((record) => {
|
||||
record._raw.id = 'attribute_value_2';
|
||||
record.attributeId = 'attribute_2';
|
||||
record.runId = 'playbook_run_2';
|
||||
record.value = 'Existing Value';
|
||||
});
|
||||
});
|
||||
|
||||
const preparedRecord = await transformPlaybookRunAttributeValueRecord({
|
||||
action: OperationType.UPDATE,
|
||||
database: database!,
|
||||
value: {
|
||||
record: existingRecord,
|
||||
raw: {
|
||||
id: 'attribute_value_2',
|
||||
attribute_id: 'attribute_2',
|
||||
run_id: 'playbook_run_2',
|
||||
value: 'Updated Value',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await database?.write(async () => {
|
||||
await database?.batch(preparedRecord);
|
||||
});
|
||||
|
||||
expect(preparedRecord).toBeTruthy();
|
||||
expect(preparedRecord!.value).toBe('Updated Value');
|
||||
expect(preparedRecord!.collection.table).toBe(PLAYBOOK_RUN_ATTRIBUTE_VALUE);
|
||||
});
|
||||
|
||||
it('=> transformPlaybookRunAttributeValueRecord: should throw an error for non-create action without an existing record', async () => {
|
||||
expect.assertions(2);
|
||||
|
||||
const database = await createTestConnection({databaseName: 'playbook_run_attribute_value_prepare_records', setActive: true});
|
||||
expect(database).toBeTruthy();
|
||||
|
||||
await expect(
|
||||
transformPlaybookRunAttributeValueRecord({
|
||||
action: OperationType.UPDATE,
|
||||
database: database!,
|
||||
value: {
|
||||
record: undefined,
|
||||
raw: {
|
||||
id: 'attribute_value_3',
|
||||
attribute_id: 'attribute_3',
|
||||
run_id: 'playbook_run_3',
|
||||
value: 'Invalid Value',
|
||||
},
|
||||
},
|
||||
}),
|
||||
).rejects.toThrow('Record not found for non create action');
|
||||
});
|
||||
|
||||
it('=> transformPlaybookRunAttributeValueRecord: should keep most of the data if the partial attribute value is empty', async () => {
|
||||
const database = await createTestConnection({databaseName: 'playbook_run_attribute_value_prepare_records', setActive: true});
|
||||
expect(database).toBeTruthy();
|
||||
|
||||
let existingRecord: PlaybookRunAttributeValueModel | undefined;
|
||||
await database!.write(async () => {
|
||||
existingRecord = await database!.get<PlaybookRunAttributeValueModel>(PLAYBOOK_RUN_ATTRIBUTE_VALUE).create((record) => {
|
||||
record._raw.id = 'attribute_value_2';
|
||||
record.attributeId = 'attribute_2';
|
||||
record.runId = 'playbook_run_2';
|
||||
record.value = 'Existing Value';
|
||||
});
|
||||
});
|
||||
|
||||
const preparedRecord = await transformPlaybookRunAttributeValueRecord({
|
||||
action: OperationType.UPDATE,
|
||||
database: database!,
|
||||
value: {
|
||||
record: existingRecord,
|
||||
raw: {
|
||||
id: 'attribute_value_2',
|
||||
run_id: 'playbook_run_2',
|
||||
attribute_id: 'attribute_2',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await database?.write(async () => {
|
||||
await database?.batch(preparedRecord);
|
||||
});
|
||||
|
||||
expect(preparedRecord).toBeTruthy();
|
||||
expect(preparedRecord.attributeId).toBe('attribute_2');
|
||||
expect(preparedRecord.runId).toBe('playbook_run_2');
|
||||
expect(preparedRecord.value).toBe('Existing Value');
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -8,9 +8,11 @@ import {PLAYBOOK_TABLES} from '@playbooks/constants/database';
|
|||
import type PlaybookChecklistModel from '@playbooks/types/database/models/playbook_checklist';
|
||||
import type PlaybookChecklistItemModel from '@playbooks/types/database/models/playbook_checklist_item';
|
||||
import type PlaybookRunModel from '@playbooks/types/database/models/playbook_run';
|
||||
import type PlaybookRunAttributeModel from '@playbooks/types/database/models/playbook_run_attribute';
|
||||
import type PlaybookRunAttributeValueModel from '@playbooks/types/database/models/playbook_run_attribute_value';
|
||||
import type{TransformerArgs} from '@typings/database/database';
|
||||
|
||||
const {PLAYBOOK_RUN, PLAYBOOK_CHECKLIST, PLAYBOOK_CHECKLIST_ITEM} = PLAYBOOK_TABLES;
|
||||
const {PLAYBOOK_RUN, PLAYBOOK_CHECKLIST, PLAYBOOK_CHECKLIST_ITEM, PLAYBOOK_RUN_ATTRIBUTE, PLAYBOOK_RUN_ATTRIBUTE_VALUE} = PLAYBOOK_TABLES;
|
||||
|
||||
/**
|
||||
* transformPlaybookRunRecord: Prepares a record of the SERVER database 'PlaybookRun' table for update or create actions.
|
||||
|
|
@ -140,3 +142,71 @@ export const transformPlaybookChecklistItemRecord = ({action, database, value}:
|
|||
fieldsMapper,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* transformPlaybookRunAttributeRecord: Prepares a record of the SERVER database 'PlaybookRunAttribute' table for update or create actions.
|
||||
* @param {TransformerArgs} transformerArgs
|
||||
* @param {Database} transformerArgs.database
|
||||
* @param {RecordPair} transformerArgs.value
|
||||
* @returns {Promise<PlaybookRunAttributeModel>}
|
||||
*/
|
||||
export const transformPlaybookRunAttributeRecord = ({action, database, value}: TransformerArgs<PlaybookRunAttributeModel, PartialPlaybookRunAttribute>): Promise<PlaybookRunAttributeModel> => {
|
||||
const raw = value.raw;
|
||||
const record = value.record;
|
||||
const isCreateAction = action === OperationType.CREATE;
|
||||
if (!isCreateAction && !record) {
|
||||
return Promise.reject(new Error('Record not found for non create action'));
|
||||
}
|
||||
|
||||
const fieldsMapper = (attribute: PlaybookRunAttributeModel) => {
|
||||
attribute._raw.id = isCreateAction ? (raw?.id ?? attribute.id) : record!.id;
|
||||
attribute.groupId = raw.group_id ?? record?.groupId ?? '';
|
||||
attribute.name = raw.name ?? record?.name ?? '';
|
||||
attribute.type = raw.type ?? record?.type ?? '';
|
||||
attribute.targetId = raw.target_id ?? record?.targetId ?? '';
|
||||
attribute.targetType = raw.target_type ?? record?.targetType ?? '';
|
||||
attribute.createAt = raw.create_at ?? record?.createAt ?? 0;
|
||||
attribute.updateAt = raw.update_at ?? record?.updateAt ?? 0;
|
||||
attribute.deleteAt = raw.delete_at ?? record?.deleteAt ?? 0;
|
||||
attribute.attrs = raw.attrs ?? record?.attrs ?? '';
|
||||
};
|
||||
|
||||
return prepareBaseRecord({
|
||||
action,
|
||||
database,
|
||||
tableName: PLAYBOOK_RUN_ATTRIBUTE,
|
||||
value,
|
||||
fieldsMapper,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* transformPlaybookRunAttributeValueRecord: Prepares a record of the SERVER database 'PlaybookRunAttributeValue' table for update or create actions.
|
||||
* @param {TransformerArgs} transformerArgs
|
||||
* @param {Database} transformerArgs.database
|
||||
* @param {RecordPair} transformerArgs.value
|
||||
* @returns {Promise<PlaybookRunAttributeValueModel>}
|
||||
*/
|
||||
export const transformPlaybookRunAttributeValueRecord = ({action, database, value}: TransformerArgs<PlaybookRunAttributeValueModel, PartialPlaybookRunAttributeValue>): Promise<PlaybookRunAttributeValueModel> => {
|
||||
const raw = value.raw;
|
||||
const record = value.record;
|
||||
const isCreateAction = action === OperationType.CREATE;
|
||||
if (!isCreateAction && !record) {
|
||||
return Promise.reject(new Error('Record not found for non create action'));
|
||||
}
|
||||
|
||||
const fieldsMapper = (attribute: PlaybookRunAttributeValueModel) => {
|
||||
attribute._raw.id = isCreateAction ? (raw?.id ?? attribute.id) : record!.id;
|
||||
attribute.attributeId = raw.attribute_id ?? record?.attributeId ?? '';
|
||||
attribute.runId = raw.run_id ?? record?.runId ?? '';
|
||||
attribute.value = raw.value ?? record?.value ?? '';
|
||||
};
|
||||
|
||||
return prepareBaseRecord({
|
||||
action,
|
||||
database,
|
||||
tableName: PLAYBOOK_RUN_ATTRIBUTE_VALUE,
|
||||
value,
|
||||
fieldsMapper,
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -4,3 +4,5 @@
|
|||
export {default as PlaybookRunSchema} from './playbook_run';
|
||||
export {default as PlaybookChecklistSchema} from './playbook_checklist';
|
||||
export {default as PlaybookChecklistItemSchema} from './playbook_checklist_item';
|
||||
export {default as PlaybookRunAttributeSchema} from './playbook_run_attribute';
|
||||
export {default as PlaybookRunAttributeValueSchema} from './playbook_run_attribute_value';
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {tableSchema} from '@nozbe/watermelondb';
|
||||
|
||||
import {PLAYBOOK_TABLES} from '@playbooks/constants/database';
|
||||
|
||||
const {PLAYBOOK_RUN_ATTRIBUTE} = PLAYBOOK_TABLES;
|
||||
|
||||
/**
|
||||
* The schema for the PLAYBOOK_RUN_ATTRIBUTE table.
|
||||
* notice that this mimics closely the Custom Profile Attribute table schema. As there is a base element to both on properties.
|
||||
* After discussing, we decided to have a separate client schema for each feature based on System Attributes.
|
||||
* although we moved away from field/attribute to an attribute/attribute value which might have some initial confusion but
|
||||
* will eventually be more consistent.
|
||||
*/
|
||||
|
||||
export default tableSchema({
|
||||
name: PLAYBOOK_RUN_ATTRIBUTE,
|
||||
columns: [
|
||||
{name: 'group_id', type: 'string'},
|
||||
{name: 'name', type: 'string'},
|
||||
{name: 'type', type: 'string'},
|
||||
{name: 'target_id', type: 'string'},
|
||||
{name: 'target_type', type: 'string'},
|
||||
{name: 'create_at', type: 'number'},
|
||||
{name: 'update_at', type: 'number'},
|
||||
{name: 'delete_at', type: 'number'},
|
||||
{name: 'attrs', type: 'string', isOptional: true},
|
||||
],
|
||||
});
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {tableSchema} from '@nozbe/watermelondb';
|
||||
|
||||
import {PLAYBOOK_TABLES} from '@playbooks/constants/database';
|
||||
|
||||
const {PLAYBOOK_RUN_ATTRIBUTE_VALUE} = PLAYBOOK_TABLES;
|
||||
|
||||
/**
|
||||
* The schema for the PLAYBOOK_RUN_ATTRIBUTE_VALUE table.
|
||||
* notice that this mimics closely the Custom Profile Attribute table schema. As there is a base element to both on properties.
|
||||
* After discussing, we decided to have a separate client schema for each feature based on System Attributes.
|
||||
* although we moved away from field/attribute to an attribute/attribute value which might have some initial confusion but
|
||||
* will eventually be more consistent.
|
||||
*/
|
||||
|
||||
export default tableSchema({
|
||||
name: PLAYBOOK_RUN_ATTRIBUTE_VALUE,
|
||||
columns: [
|
||||
{name: 'attribute_id', type: 'string', isIndexed: true},
|
||||
{name: 'run_id', type: 'string', isIndexed: true},
|
||||
{name: 'value', type: 'string'},
|
||||
],
|
||||
});
|
||||
20
app/products/playbooks/types/api.d.ts
vendored
20
app/products/playbooks/types/api.d.ts
vendored
|
|
@ -71,6 +71,26 @@ type TimelineEvent = {
|
|||
|
||||
type PlaybookRunStatusType = typeof PlaybookRunStatus[keyof typeof PlaybookRunStatus];
|
||||
|
||||
type PlaybookRunAttribute = {
|
||||
id: string;
|
||||
group_id: string;
|
||||
name: string;
|
||||
type: string;
|
||||
target_id: string;
|
||||
target_type: string;
|
||||
create_at: number;
|
||||
update_at: number;
|
||||
delete_at: number;
|
||||
attrs?: string;
|
||||
}
|
||||
|
||||
type PlaybookRunAttributeValue = {
|
||||
id: string;
|
||||
attribute_id: string;
|
||||
run_id: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
type PlaybookRun = {
|
||||
id: string;
|
||||
name: string;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import type Model from '@nozbe/watermelondb/Model';
|
||||
|
||||
/**
|
||||
* The PlaybookRunAttribute interface, which will have all the fields from the PLAYBOOK_RUN_ATTRIBUTE table
|
||||
*/
|
||||
interface PlaybookRunAttributeModelInterface extends Model {
|
||||
|
||||
/** groupId : The group ID of the field */
|
||||
groupId: string;
|
||||
|
||||
/** name : The name of the field */
|
||||
name: string;
|
||||
|
||||
/** type : The type of the field */
|
||||
type: string;
|
||||
|
||||
/** targetId : The target ID of the field */
|
||||
targetId: string;
|
||||
|
||||
/** targetType : The target type of the field */
|
||||
targetType: string;
|
||||
|
||||
/** createAt : The timestamp of when the field was created */
|
||||
createAt: number;
|
||||
|
||||
/** updateAt : The timestamp of when the field was last updated */
|
||||
updateAt: number;
|
||||
|
||||
/** deleteAt : The timestamp of when the field was deleted */
|
||||
deleteAt: number;
|
||||
|
||||
/** attrs : Additional attributes for the field (JSON string) */
|
||||
attrs?: string;
|
||||
}
|
||||
|
||||
export type {PlaybookRunAttributeModelInterface as default};
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import type PlaybookRunModel from './playbook_run';
|
||||
import type PlaybookRunAttributeModel from './playbook_run_attribute';
|
||||
import type {Relation} from '@nozbe/watermelondb';
|
||||
import type Model from '@nozbe/watermelondb/Model';
|
||||
|
||||
/**
|
||||
* The PlaybookRunAttributeValue interface, which will have all the fields from the PLAYBOOK_RUN_ATTRIBUTE_VALUE table
|
||||
*/
|
||||
interface PlaybookRunAttributeValueModelInterface extends Model {
|
||||
|
||||
/** attributeId : The ID of the attribute this attribute value belongs to */
|
||||
attributeId: string;
|
||||
|
||||
/** runId : The ID of the playbook run this attribute belongs to */
|
||||
runId: string;
|
||||
|
||||
/** value : The value of the attribute */
|
||||
value: string;
|
||||
|
||||
/** attribute : The attribute this attribute value belongs to */
|
||||
attribute: Relation<PlaybookRunAttributeModel>;
|
||||
|
||||
/** run : The playbook run this attribute belongs to */
|
||||
run: Relation<PlaybookRunModel>;
|
||||
}
|
||||
|
||||
export type {PlaybookRunAttributeValueModelInterface as default};
|
||||
|
|
@ -7,8 +7,16 @@ type WithRunId = {
|
|||
type WithChecklistId = {
|
||||
checklist_id: string;
|
||||
}
|
||||
|
||||
type WithAttributeId = {
|
||||
attribute_id: string;
|
||||
}
|
||||
|
||||
type PartialWithId<T extends {id: string}> = Partial<T> & Pick<T, 'id'>;
|
||||
|
||||
type PartialPlaybookRun = PartialWithId<PlaybookRun>;
|
||||
type PartialChecklist = PartialWithId<PlaybookChecklist> & WithRunId;
|
||||
type PartialChecklistItem = PartialWithId<PlaybookChecklistItem> & WithChecklistId;
|
||||
|
||||
type PartialPlaybookRunAttribute = PartialWithId<PlaybookRunAttribute>;
|
||||
type PartialPlaybookRunAttributeValue = PartialWithId<PlaybookRunAttributeValue> & WithRunId & WithAttributeId;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# Server Database - Schema Version 13
|
||||
# Server Database - Schema Version 14
|
||||
# Please bump the version by 1, any time the schema changes.
|
||||
# Also, include the migration plan under app/database/migration/server,
|
||||
# update all models, relationships and types.
|
||||
|
|
@ -230,6 +230,26 @@ completed_at number
|
|||
synced string NULL INDEX # optional field for sync status
|
||||
last_sync_at number NULL # optional field for last sync timestamp
|
||||
|
||||
PlaybookRunAttribute
|
||||
-
|
||||
id PK string # server-generated
|
||||
group_id string
|
||||
name string
|
||||
type string
|
||||
target_id string
|
||||
target_type string
|
||||
create_at number
|
||||
update_at number
|
||||
delete_at number
|
||||
attrs string NULL # stringified JSON
|
||||
|
||||
PlaybookRunAttributeValue
|
||||
-
|
||||
id PK string # composition ID PlaybookRun.id-PlaybookRunAttribute.id
|
||||
attribute_id string INDEX FK >- PlaybookRunAttribute.id
|
||||
run_id string INDEX FK >- PlaybookRun.id
|
||||
value string
|
||||
|
||||
Post
|
||||
-
|
||||
id PK string # server generated
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ import type {Model, Query, Relation} from '@nozbe/watermelondb';
|
|||
import type PlaybookChecklistModel from '@playbooks/types/database/models/playbook_checklist';
|
||||
import type PlaybookChecklistItemModel from '@playbooks/types/database/models/playbook_checklist_item';
|
||||
import type PlaybookRunModel from '@playbooks/types/database/models/playbook_run';
|
||||
import type PlaybookRunAttributeModel from '@playbooks/types/database/models/playbook_run_attribute';
|
||||
import type PlaybookRunAttributeValueModel from '@playbooks/types/database/models/playbook_run_attribute_value';
|
||||
import type CategoryChannelModel from '@typings/database/models/servers/category_channel';
|
||||
import type ChannelModel from '@typings/database/models/servers/channel';
|
||||
import type ChannelBookmarkModel from '@typings/database/models/servers/channel_bookmark';
|
||||
|
|
@ -1067,7 +1069,7 @@ class TestHelperSingleton {
|
|||
};
|
||||
};
|
||||
|
||||
createPlaybookItem =(prefix: string, index: number): PlaybookChecklistItem => ({
|
||||
createPlaybookItem = (prefix: string, index: number): PlaybookChecklistItem => ({
|
||||
id: `${prefix}-item_${index}`,
|
||||
title: `Item ${index + 1} of Checklist ${prefix}`,
|
||||
description: 'Item description',
|
||||
|
|
@ -1085,6 +1087,26 @@ class TestHelperSingleton {
|
|||
update_at: 0,
|
||||
});
|
||||
|
||||
createPlaybookRunAttribute = (prefix: string, index: number): PlaybookRunAttribute => ({
|
||||
id: `${prefix}-attribute_${index}`,
|
||||
group_id: 'group_1',
|
||||
name: `Attribute ${index + 1}`,
|
||||
type: 'text',
|
||||
target_id: `${prefix}`,
|
||||
target_type: 'playbook_run',
|
||||
create_at: Date.now(),
|
||||
update_at: Date.now(),
|
||||
delete_at: 0,
|
||||
attrs: '',
|
||||
});
|
||||
|
||||
createPlaybookRunAttributeValue = (attributeId: string, runId: string, index: number): PlaybookRunAttributeValue => ({
|
||||
id: `${runId}-${attributeId}-value_${index}`,
|
||||
attribute_id: attributeId,
|
||||
run_id: runId,
|
||||
value: `Value ${index + 1}`,
|
||||
});
|
||||
|
||||
createPlaybookChecklist = (prefix: string, itemsCount: number, index: number): PlaybookChecklist => {
|
||||
const items: PlaybookChecklistItem[] = [];
|
||||
const id = `${prefix}-checklist_${index}`;
|
||||
|
|
@ -1263,6 +1285,60 @@ class TestHelperSingleton {
|
|||
};
|
||||
};
|
||||
|
||||
fakePlaybookRunAttribute = (overwrite: Partial<PlaybookRunAttribute> = {}): PlaybookRunAttribute => {
|
||||
return {
|
||||
id: this.generateId(),
|
||||
group_id: this.generateId(),
|
||||
name: 'Test Attribute',
|
||||
type: 'text',
|
||||
target_id: this.generateId(),
|
||||
target_type: 'playbook_run',
|
||||
create_at: Date.now(),
|
||||
update_at: Date.now(),
|
||||
delete_at: 0,
|
||||
attrs: '',
|
||||
...overwrite,
|
||||
};
|
||||
};
|
||||
|
||||
fakePlaybookRunAttributeValue = (attributeId: string, runId: string, overwrite: Partial<PlaybookRunAttributeValue> = {}): PlaybookRunAttributeValue => {
|
||||
return {
|
||||
id: this.generateId(),
|
||||
attribute_id: attributeId,
|
||||
run_id: runId,
|
||||
value: 'Test Value',
|
||||
...overwrite,
|
||||
};
|
||||
};
|
||||
|
||||
fakePlaybookRunAttributeModel = (overwrite: Partial<PlaybookRunAttributeModel> = {}): PlaybookRunAttributeModel => {
|
||||
return {
|
||||
...this.fakeModel(),
|
||||
groupId: this.generateId(),
|
||||
name: 'Test Attribute',
|
||||
type: 'text',
|
||||
targetId: this.generateId(),
|
||||
targetType: 'playbook_run',
|
||||
createAt: Date.now(),
|
||||
updateAt: Date.now(),
|
||||
deleteAt: 0,
|
||||
attrs: '',
|
||||
...overwrite,
|
||||
};
|
||||
};
|
||||
|
||||
fakePlaybookRunAttributeValueModel = (overwrite: Partial<PlaybookRunAttributeValueModel> = {}): PlaybookRunAttributeValueModel => {
|
||||
return {
|
||||
...this.fakeModel(),
|
||||
attributeId: this.generateId(),
|
||||
runId: this.generateId(),
|
||||
value: 'Test Value',
|
||||
attribute: this.fakeRelation(),
|
||||
run: this.fakeRelation(),
|
||||
...overwrite,
|
||||
};
|
||||
};
|
||||
|
||||
fakeWebsocketMessage = (overwrite: Partial<WebSocketMessage> = {}): WebSocketMessage => {
|
||||
return {
|
||||
event: 'test',
|
||||
|
|
|
|||
Loading…
Reference in a new issue