All files / src/operation change-field.ts

100% Statements 60/60
100% Branches 8/8
100% Functions 13/13
100% Lines 60/60

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181  3x 3x 3x 3x 3x   3x                         37x   32x       37x 37x 37x   37x   37x   37x                 32x   32x   7x   7x   7x   7x   3x   1x         7x 7x   7x                 7x 7x   7x                 7x 7x   7x                 7x 7x   7x                 3x 3x   3x                 37x 37x 37x 37x 37x 37x 37x 37x 37x 37x 37x   37x                                 37x   37x       37x   37x       37x   37x 23x     14x       69x   69x       3x  
import Node from 'type/node';
import SystemId from 'system/enum/id';
import ChangeType from 'enum/change-type';
import ChangeStatus from 'enum/change-status';
import KeyGenerator from 'utility/key-generator';
import BadRequestError from 'http/error/bad-request';
import { PrimitiveValue } from 'type/field-value';
import Operation, { OperationInput } from 'operation';
 
interface Input extends OperationInput {
	readonly id: string;
	readonly type_id: string;
	readonly change_type: ChangeType;
	readonly field: string;
	readonly value: PrimitiveValue;
	readonly previous_value?: PrimitiveValue;
}
 
class ChangeFieldOperation extends Operation<Input, Node> {
	protected async performInternal(): Promise<Node> {
		await this.addChangeNode();
 
		return this.performFieldChange();
	}
 
	private async addChangeNode(): Promise<void> {
		const input = this.getInput();
		const change_node = this.buildChangeNode();
		const repository = this.getRepository();
 
		await repository.storeNode(change_node);
 
		const change_url = repository.buildNodeUrl(change_node);
 
		await repository.addValueToList(
			input.type_id,
			input.id,
			'changes',
			change_url
		);
	}
 
	private performFieldChange(): Promise<Node> {
		const change_type = this.getInputChangeType();
 
		switch (change_type) {
			case ChangeType.SET_FIELD_VALUE:
				return this.performSetFieldValueOperation();
			case ChangeType.ADD_LIST_VALUE:
				return this.performAddListValueOperation();
			case ChangeType.REMOVE_LIST_VALUE:
				return this.performRemoveListValueOperation();
			case ChangeType.ADD_SET_VALUE:
				return this.performAddSetValueOperation();
			case ChangeType.REMOVE_SET_VALUE:
				return this.performRemoveSetValueOperation();
			default:
				throw new BadRequestError();
		}
	}
 
	private performSetFieldValueOperation(): Promise<Node> {
		const input = this.getInput();
		const repository = this.getRepository();
 
		return repository.setField(
			input.type_id,
			input.id,
			input.field,
			input.value
		);
	}
 
	private performAddListValueOperation(): Promise<Node> {
		const input = this.getInput();
		const repository = this.getRepository();
 
		return repository.addValueToList(
			input.type_id,
			input.id,
			input.field,
			input.value
		);
	}
 
	private performRemoveListValueOperation(): Promise<Node> {
		const input = this.getInput();
		const repository = this.getRepository();
 
		return repository.removeValueFromList(
			input.type_id,
			input.id,
			input.field,
			input.value
		);
	}
 
	private performAddSetValueOperation(): Promise<Node> {
		const input = this.getInput();
		const repository = this.getRepository();
 
		return repository.addValueToSet(
			input.type_id,
			input.id,
			input.field,
			input.value
		);
	}
 
	private performRemoveSetValueOperation(): Promise<Node> {
		const input = this.getInput();
		const repository = this.getRepository();
 
		return repository.removeValueFromSet(
			input.type_id,
			input.id,
			input.field,
			input.value
		);
	}
 
	private buildChangeNode(): Node {
		const id = KeyGenerator.id();
		const type_id = SystemId.CHANGE_TYPE;
		const status = ChangeStatus.APPROVED;
		const change_type = this.getInputChangeType();
		const field = this.getInputField();
		const value = this.getInputValue();
		const previous_value = this.getInputPreviousValue();
		const creator = 'https://9db.org/account/anonymous';
		const approver = 'https://9db.org/account/system';
		const created_at = Date.now();
		const updated_at = created_at;
 
		return {
			id,
			type_id,
			status,
			change_type,
			field,
			value,
			previous_value,
			approver,
			creator,
			created_at,
			updated_at,
			changes: []
		};
	}
 
	private getInputField(): string {
		const input = this.getInput();
 
		return input.field;
	}
 
	private getInputValue(): PrimitiveValue {
		const input = this.getInput();
 
		return input.value;
	}
 
	private getInputPreviousValue(): PrimitiveValue {
		const input = this.getInput();
 
		if (input.previous_value === undefined) {
			return null;
		}
 
		return input.previous_value;
	}
 
	private getInputChangeType(): ChangeType {
		const input = this.getInput();
 
		return input.change_type;
	}
}
 
export default ChangeFieldOperation;