Automation + Expression WIP
This commit is contained in:
parent
850d23f293
commit
ded17239b6
24
src/main/angular/src/app/api/Automation/Automation.ts
Normal file
24
src/main/angular/src/app/api/Automation/Automation.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import {Expression, expressionFromJson} from '../Expression/Expression';
|
||||||
|
import {validateBoolean, validateString} from '../common/validators';
|
||||||
|
|
||||||
|
export class Automation {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
readonly uuid: string,
|
||||||
|
readonly name: string,
|
||||||
|
readonly enabled: boolean,
|
||||||
|
readonly condition: Expression,
|
||||||
|
) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
static fromJson(json: any): Automation {
|
||||||
|
return new Automation(
|
||||||
|
validateString(json.uuid),
|
||||||
|
validateString(json.name),
|
||||||
|
validateBoolean(json.enabled),
|
||||||
|
expressionFromJson(json.condition),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
35
src/main/angular/src/app/api/Expression/Expression.ts
Normal file
35
src/main/angular/src/app/api/Expression/Expression.ts
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import {validateString} from '../common/validators';
|
||||||
|
import {ExpressionLiteralBoolean} from './ExpressionLiteralBoolean';
|
||||||
|
import {ExpressionLiteralNumber} from './ExpressionLiteralNumber';
|
||||||
|
import {ExpressionProperty} from './ExpressionProperty';
|
||||||
|
import {ExpressionUnary} from './ExpressionUnary';
|
||||||
|
import {ExpressionNary} from './ExpressionNary';
|
||||||
|
|
||||||
|
export abstract class Expression {
|
||||||
|
|
||||||
|
protected constructor(
|
||||||
|
readonly _type_: string,
|
||||||
|
readonly uuid: string,
|
||||||
|
readonly name: string,
|
||||||
|
) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export function expressionFromJson(json: any): Expression {
|
||||||
|
const _type_ = validateString(json._type_);
|
||||||
|
switch (_type_) {
|
||||||
|
case 'ExpressionLiteralBoolean':
|
||||||
|
return ExpressionLiteralBoolean.fromJson(json);
|
||||||
|
case 'ExpressionLiteralNumber':
|
||||||
|
return ExpressionLiteralNumber.fromJson(json);
|
||||||
|
case 'ExpressionProperty':
|
||||||
|
return ExpressionProperty.fromJson(json);
|
||||||
|
case 'ExpressionUnary':
|
||||||
|
return ExpressionUnary.fromJson(json);
|
||||||
|
case 'ExpressionNary':
|
||||||
|
return ExpressionNary.fromJson(json);
|
||||||
|
}
|
||||||
|
throw Error("expression type not implemented: " + _type_);
|
||||||
|
}
|
||||||
14
src/main/angular/src/app/api/Expression/ExpressionLiteral.ts
Normal file
14
src/main/angular/src/app/api/Expression/ExpressionLiteral.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import {Expression} from "./Expression";
|
||||||
|
|
||||||
|
export abstract class ExpressionLiteral<T> extends Expression {
|
||||||
|
|
||||||
|
protected constructor(
|
||||||
|
_type_: string,
|
||||||
|
uuid: string,
|
||||||
|
name: string,
|
||||||
|
readonly literal: T | null,
|
||||||
|
) {
|
||||||
|
super(_type_, uuid, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
import {validateBooleanOrNull, validateString} from "../common/validators";
|
||||||
|
|
||||||
|
import {ExpressionLiteral} from './ExpressionLiteral';
|
||||||
|
|
||||||
|
export class ExpressionLiteralBoolean extends ExpressionLiteral<boolean> {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
_type_: string,
|
||||||
|
uuid: string,
|
||||||
|
name: string,
|
||||||
|
readonly value: boolean | null,
|
||||||
|
) {
|
||||||
|
super(_type_, uuid, name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static fromJson(json: any): ExpressionLiteralBoolean {
|
||||||
|
return new ExpressionLiteralBoolean(
|
||||||
|
validateString(json._type_),
|
||||||
|
validateString(json.uuid),
|
||||||
|
validateString(json.name),
|
||||||
|
validateBooleanOrNull(json.value),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
import {validateNumberOrNull, validateString} from "../common/validators";
|
||||||
|
|
||||||
|
import {ExpressionLiteral} from './ExpressionLiteral';
|
||||||
|
|
||||||
|
export class ExpressionLiteralNumber extends ExpressionLiteral<number> {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
_type_: string,
|
||||||
|
uuid: string,
|
||||||
|
name: string,
|
||||||
|
readonly value: number | null,
|
||||||
|
) {
|
||||||
|
super(_type_, uuid, name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static fromJson(json: any): ExpressionLiteralNumber {
|
||||||
|
return new ExpressionLiteralNumber(
|
||||||
|
validateString(json._type_),
|
||||||
|
validateString(json.uuid),
|
||||||
|
validateString(json.name),
|
||||||
|
validateNumberOrNull(json.value),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
29
src/main/angular/src/app/api/Expression/ExpressionNary.ts
Normal file
29
src/main/angular/src/app/api/Expression/ExpressionNary.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import {orNull, validateString} from "../common/validators";
|
||||||
|
import {Expression, expressionFromJson} from './Expression';
|
||||||
|
import {ExpressionNaryOperator} from './ExpressionNaryOperator';
|
||||||
|
|
||||||
|
export class ExpressionNary extends Expression {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
_type_: string,
|
||||||
|
uuid: string,
|
||||||
|
name: string,
|
||||||
|
readonly operator: ExpressionNaryOperator,
|
||||||
|
readonly expression0: Expression | null,
|
||||||
|
readonly expression1: Expression | null,
|
||||||
|
) {
|
||||||
|
super(_type_, uuid, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static fromJson(json: any): ExpressionNary {
|
||||||
|
return new ExpressionNary(
|
||||||
|
validateString(json._type_),
|
||||||
|
validateString(json.uuid),
|
||||||
|
validateString(json.name),
|
||||||
|
validateString(json.operator) as ExpressionNaryOperator,
|
||||||
|
orNull(json.expression0, j => expressionFromJson(j)),
|
||||||
|
orNull(json.expression1, j => expressionFromJson(j)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
export enum ExpressionNaryOperator {
|
||||||
|
OR = 'OR',
|
||||||
|
AND = 'AND',
|
||||||
|
XOR = 'XOR',
|
||||||
|
ADD = 'ADD',
|
||||||
|
SUB = 'SUB',
|
||||||
|
MUL = 'MUL',
|
||||||
|
DIV = 'DIV',
|
||||||
|
MOD = 'MOD',
|
||||||
|
POW = 'POW',
|
||||||
|
HYPOT = 'HYPOT',
|
||||||
|
ATAN2 = 'ATAN2',
|
||||||
|
MIN = 'MIN',
|
||||||
|
MAX = 'MAX',
|
||||||
|
}
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
import {validateString} from "../common/validators";
|
||||||
|
import {Expression} from './Expression';
|
||||||
|
|
||||||
|
export class ExpressionProperty extends Expression {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
_type_: string,
|
||||||
|
uuid: string,
|
||||||
|
name: string,
|
||||||
|
readonly propertyId: string,
|
||||||
|
) {
|
||||||
|
super(_type_, uuid, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static fromJson(json: any): ExpressionProperty {
|
||||||
|
return new ExpressionProperty(
|
||||||
|
validateString(json._type_),
|
||||||
|
validateString(json.uuid),
|
||||||
|
validateString(json.name),
|
||||||
|
validateString(json.propertyId),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
27
src/main/angular/src/app/api/Expression/ExpressionUnary.ts
Normal file
27
src/main/angular/src/app/api/Expression/ExpressionUnary.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import {orNull, validateString} from "../common/validators";
|
||||||
|
import {Expression, expressionFromJson} from './Expression';
|
||||||
|
import {ExpressionUnaryOperator} from './ExpressionUnaryOperator';
|
||||||
|
|
||||||
|
export class ExpressionUnary extends Expression {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
_type_: string,
|
||||||
|
uuid: string,
|
||||||
|
name: string,
|
||||||
|
readonly operator: ExpressionUnaryOperator,
|
||||||
|
readonly expression: Expression | null,
|
||||||
|
) {
|
||||||
|
super(_type_, uuid, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static fromJson(json: any): ExpressionUnary {
|
||||||
|
return new ExpressionUnary(
|
||||||
|
validateString(json._type_),
|
||||||
|
validateString(json.uuid),
|
||||||
|
validateString(json.name),
|
||||||
|
validateString(json.operator) as ExpressionUnaryOperator,
|
||||||
|
orNull(json.expression, j => expressionFromJson(j)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
export enum ExpressionUnaryOperator {
|
||||||
|
NOT = 'NOT',
|
||||||
|
NEG = 'NEG',
|
||||||
|
POS = 'POS',
|
||||||
|
FLOOR = 'FLOOR',
|
||||||
|
CEIL = 'CEIL',
|
||||||
|
ROUND = 'ROUND',
|
||||||
|
SQRT = 'SQRT',
|
||||||
|
ABS = 'ABS',
|
||||||
|
COS = 'COS',
|
||||||
|
SIN = 'SIN',
|
||||||
|
TAN = 'TAN',
|
||||||
|
ACOS = 'ACOS',
|
||||||
|
ASIN = 'ASIN',
|
||||||
|
ATAN = 'ATAN',
|
||||||
|
COSH = 'COSH',
|
||||||
|
SINH = 'SINH',
|
||||||
|
TANH = 'TANH',
|
||||||
|
EXP = 'EXP',
|
||||||
|
EXPM1 = 'EXPM1',
|
||||||
|
}
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
import {Injectable} from '@angular/core';
|
||||||
|
import {ExpressionLiteralBoolean} from './ExpressionLiteralBoolean';
|
||||||
|
import {ApiService} from '../common/api.service';
|
||||||
|
import {CrudService} from '../common/CrudService';
|
||||||
|
import {Next} from '../common/types';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class ExpressionLiteralBooleanService extends CrudService<ExpressionLiteralBoolean> {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
apiService: ApiService,
|
||||||
|
) {
|
||||||
|
super(apiService, ['ExpressionLiteralBoolean'], ExpressionLiteralBoolean.fromJson);
|
||||||
|
}
|
||||||
|
|
||||||
|
setValue(expression: ExpressionLiteralBoolean, value: boolean, next?: Next<ExpressionLiteralBoolean>) {
|
||||||
|
this.postSingle([expression.uuid, 'setValue'], value, next);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
import {Injectable} from '@angular/core';
|
||||||
|
import {ExpressionLiteralNumber} from './ExpressionLiteralNumber';
|
||||||
|
import {ApiService} from '../common/api.service';
|
||||||
|
import {CrudService} from '../common/CrudService';
|
||||||
|
import {Next} from '../common/types';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class ExpressionLiteralNumberService extends CrudService<ExpressionLiteralNumber> {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
apiService: ApiService,
|
||||||
|
) {
|
||||||
|
super(apiService, ['ExpressionLiteralNumber'], ExpressionLiteralNumber.fromJson);
|
||||||
|
}
|
||||||
|
|
||||||
|
setValue(expression: ExpressionLiteralNumber, value: number, next?: Next<ExpressionLiteralNumber>) {
|
||||||
|
this.postSingle([expression.uuid, 'setValue'], value, next);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1 @@
|
|||||||
|
<input type="checkbox" [ngModel]="expression.value" (ngModelChange)="expressionService.setValue(expression, $event)">
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
import {Component, Input} from '@angular/core';
|
||||||
|
import {FormsModule} from '@angular/forms';
|
||||||
|
import {ExpressionLiteralBoolean} from '../../../api/Expression/ExpressionLiteralBoolean';
|
||||||
|
import {ExpressionLiteralBooleanService} from '../../../api/Expression/expression-literal-boolean.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-expression-literal-boolean',
|
||||||
|
standalone: true,
|
||||||
|
imports: [
|
||||||
|
FormsModule
|
||||||
|
],
|
||||||
|
templateUrl: './expression-literal-boolean.component.html',
|
||||||
|
styleUrl: './expression-literal-boolean.component.less'
|
||||||
|
})
|
||||||
|
export class ExpressionLiteralBooleanComponent {
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
expression!: ExpressionLiteralBoolean;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
readonly expressionService: ExpressionLiteralBooleanService,
|
||||||
|
) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1 @@
|
|||||||
|
<input type="number" [ngModel]="expression.value" (ngModelChange)="expressionService.setValue(expression, $event)">
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
import {Component, Input} from '@angular/core';
|
||||||
|
import {FormsModule} from '@angular/forms';
|
||||||
|
import {ExpressionLiteralNumber} from '../../../api/Expression/ExpressionLiteralNumber';
|
||||||
|
import {ExpressionLiteralNumberService} from '../../../api/Expression/expression-literal-number.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-expression-literal-number',
|
||||||
|
standalone: true,
|
||||||
|
imports: [
|
||||||
|
FormsModule
|
||||||
|
],
|
||||||
|
templateUrl: './expression-literal-number.component.html',
|
||||||
|
styleUrl: './expression-literal-number.component.less'
|
||||||
|
})
|
||||||
|
export class ExpressionLiteralNumberComponent {
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
expression!: ExpressionLiteralNumber;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
readonly expressionService: ExpressionLiteralNumberService,
|
||||||
|
) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
<ng-container [ngSwitch]="expression._type_">
|
||||||
|
<ng-container *ngSwitchCase="'ExpressionLiteralDouble'">
|
||||||
|
<app-expression-literal-boolean [expression]="asExpressionLiteralBoolean()"></app-expression-literal-boolean>
|
||||||
|
</ng-container>
|
||||||
|
<ng-container *ngSwitchCase="'ExpressionLiteralDouble'">
|
||||||
|
<app-expression-literal-number [expression]="asExpressionLiteralNumber()"></app-expression-literal-number>
|
||||||
|
</ng-container>
|
||||||
|
</ng-container>
|
||||||
@ -0,0 +1,49 @@
|
|||||||
|
import {Component, Input} from '@angular/core';
|
||||||
|
import {Expression} from '../../api/Expression/Expression';
|
||||||
|
import {ExpressionLiteralBoolean} from '../../api/Expression/ExpressionLiteralBoolean';
|
||||||
|
import {NgSwitch, NgSwitchCase} from '@angular/common';
|
||||||
|
import {ExpressionLiteralNumber} from '../../api/Expression/ExpressionLiteralNumber';
|
||||||
|
import {ExpressionProperty} from '../../api/Expression/ExpressionProperty';
|
||||||
|
import {ExpressionUnary} from '../../api/Expression/ExpressionUnary';
|
||||||
|
import {ExpressionNary} from '../../api/Expression/ExpressionNary';
|
||||||
|
import {ExpressionLiteralBooleanComponent} from './expression-literal-boolean/expression-literal-boolean.component';
|
||||||
|
import {ExpressionLiteralNumberComponent} from './expression-literal-number/expression-literal-number.component';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-expression',
|
||||||
|
standalone: true,
|
||||||
|
imports: [
|
||||||
|
NgSwitch,
|
||||||
|
NgSwitchCase,
|
||||||
|
ExpressionLiteralBooleanComponent,
|
||||||
|
ExpressionLiteralNumberComponent
|
||||||
|
],
|
||||||
|
templateUrl: './expression.component.html',
|
||||||
|
styleUrl: './expression.component.less'
|
||||||
|
})
|
||||||
|
export class ExpressionComponent {
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
expression!: Expression;
|
||||||
|
|
||||||
|
asExpressionLiteralBoolean(): ExpressionLiteralBoolean {
|
||||||
|
return this.expression as ExpressionLiteralBoolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
asExpressionLiteralNumber(): ExpressionLiteralNumber {
|
||||||
|
return this.expression as ExpressionLiteralNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
asExpressionProperty(): ExpressionProperty {
|
||||||
|
return this.expression as ExpressionProperty;
|
||||||
|
}
|
||||||
|
|
||||||
|
asExpressionUnary(): ExpressionUnary {
|
||||||
|
return this.expression as ExpressionUnary;
|
||||||
|
}
|
||||||
|
|
||||||
|
asExpressionNary(): ExpressionNary {
|
||||||
|
return this.expression as ExpressionNary;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
48
src/main/java/de/ph87/home/automation/Automation.java
Normal file
48
src/main/java/de/ph87/home/automation/Automation.java
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
package de.ph87.home.automation;
|
||||||
|
|
||||||
|
import de.ph87.home.expression.AbstractExpression;
|
||||||
|
import de.ph87.home.expression.Runtime;
|
||||||
|
import jakarta.annotation.Nullable;
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.ManyToOne;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Getter
|
||||||
|
@ToString
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class Automation {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@NonNull
|
||||||
|
private String uuid = UUID.randomUUID().toString();
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Column(nullable = false)
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
private boolean enabled = false;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@ManyToOne
|
||||||
|
private AbstractExpression condition;
|
||||||
|
|
||||||
|
public Automation(@NonNull final String name, final boolean enabled, @NonNull final AbstractExpression condition) {
|
||||||
|
this.name = name;
|
||||||
|
this.enabled = enabled;
|
||||||
|
this.condition = condition;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean evaluateCondition(@NonNull final Runtime runtime) {
|
||||||
|
return AbstractExpression.mapOrElseNotNull(condition, c -> c.evaluate(runtime), AbstractExpression::convertToBoolean, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
package de.ph87.home.automation;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@RequestMapping("Automation")
|
||||||
|
public class AutomationController {
|
||||||
|
|
||||||
|
private final AutomationService automationService;
|
||||||
|
|
||||||
|
@GetMapping("list")
|
||||||
|
public List<AutomationDto> list() {
|
||||||
|
return automationService.listDto();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
31
src/main/java/de/ph87/home/automation/AutomationDto.java
Normal file
31
src/main/java/de/ph87/home/automation/AutomationDto.java
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package de.ph87.home.automation;
|
||||||
|
|
||||||
|
import de.ph87.home.expression.AbstractExpressionDto;
|
||||||
|
import jakarta.annotation.Nullable;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ToString
|
||||||
|
public class AutomationDto {
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private final String uuid;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
private final boolean enabled;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private final AbstractExpressionDto condition;
|
||||||
|
|
||||||
|
public AutomationDto(@NonNull final Automation automation, @Nullable final AbstractExpressionDto condition) {
|
||||||
|
this.uuid = automation.getUuid();
|
||||||
|
this.name = automation.getName();
|
||||||
|
this.enabled = automation.isEnabled();
|
||||||
|
this.condition = condition;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
package de.ph87.home.automation;
|
||||||
|
|
||||||
|
import org.springframework.data.repository.ListCrudRepository;
|
||||||
|
|
||||||
|
public interface AutomationRepository extends ListCrudRepository<Automation, String> {
|
||||||
|
|
||||||
|
}
|
||||||
36
src/main/java/de/ph87/home/automation/AutomationService.java
Normal file
36
src/main/java/de/ph87/home/automation/AutomationService.java
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
package de.ph87.home.automation;
|
||||||
|
|
||||||
|
import de.ph87.home.expression.AbstractExpressionDto;
|
||||||
|
import de.ph87.home.expression.expression.ExpressionService;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static de.ph87.home.expression.AbstractExpression.mapOrElse;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@Transactional
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class AutomationService {
|
||||||
|
|
||||||
|
private final AutomationRepository automationRepository;
|
||||||
|
|
||||||
|
private final ExpressionService expressionService;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public List<AutomationDto> listDto() {
|
||||||
|
return automationRepository.findAll().stream().map(this::toDto).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private AutomationDto toDto(@NonNull final Automation automation) {
|
||||||
|
final AbstractExpressionDto condition = mapOrElse(automation.getCondition(), expressionService::toDto, null);
|
||||||
|
return new AutomationDto(automation, condition);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,6 +1,10 @@
|
|||||||
package de.ph87.home.demo;
|
package de.ph87.home.demo;
|
||||||
|
|
||||||
|
import de.ph87.home.automation.Automation;
|
||||||
|
import de.ph87.home.automation.AutomationRepository;
|
||||||
import de.ph87.home.device.DeviceService;
|
import de.ph87.home.device.DeviceService;
|
||||||
|
import de.ph87.home.expression.expression.ExpressionRepository;
|
||||||
|
import de.ph87.home.expression.expression.literal.bool.ExpressionLiteralBoolean;
|
||||||
import de.ph87.home.knx.property.KnxPropertyService;
|
import de.ph87.home.knx.property.KnxPropertyService;
|
||||||
import de.ph87.home.knx.property.KnxPropertyType;
|
import de.ph87.home.knx.property.KnxPropertyType;
|
||||||
import de.ph87.home.shutter.ShutterService;
|
import de.ph87.home.shutter.ShutterService;
|
||||||
@ -24,6 +28,10 @@ public class DemoService {
|
|||||||
|
|
||||||
private final ShutterService shutterService;
|
private final ShutterService shutterService;
|
||||||
|
|
||||||
|
private final ExpressionRepository expressionRepository;
|
||||||
|
|
||||||
|
private final AutomationRepository automationRepository;
|
||||||
|
|
||||||
@EventListener(ApplicationStartedEvent.class)
|
@EventListener(ApplicationStartedEvent.class)
|
||||||
public void startup() {
|
public void startup() {
|
||||||
knxPropertyService.create("eg_ambiente", KnxPropertyType.BOOLEAN, adr(849), adr(848));
|
knxPropertyService.create("eg_ambiente", KnxPropertyType.BOOLEAN, adr(849), adr(848));
|
||||||
@ -58,6 +66,9 @@ public class DemoService {
|
|||||||
|
|
||||||
knxPropertyService.create("kueche_tuer", KnxPropertyType.DOUBLE, adr(2324), adr(2324));
|
knxPropertyService.create("kueche_tuer", KnxPropertyType.DOUBLE, adr(2324), adr(2324));
|
||||||
shutterService.create("Küche Tür", "kueche_tuer", "kueche_tuer");
|
shutterService.create("Küche Tür", "kueche_tuer", "kueche_tuer");
|
||||||
|
|
||||||
|
final ExpressionLiteralBoolean exp = expressionRepository.save(new ExpressionLiteralBoolean(true));
|
||||||
|
automationRepository.save(new Automation("test", true, exp));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static GroupAddress adr(final int rawGroupAddress) {
|
private static GroupAddress adr(final int rawGroupAddress) {
|
||||||
|
|||||||
168
src/main/java/de/ph87/home/expression/AbstractExpression.java
Normal file
168
src/main/java/de/ph87/home/expression/AbstractExpression.java
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
package de.ph87.home.expression;
|
||||||
|
|
||||||
|
import jakarta.annotation.Nullable;
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ToString
|
||||||
|
@NoArgsConstructor
|
||||||
|
@Entity(name = "expression")
|
||||||
|
@DiscriminatorColumn(name = "_type_")
|
||||||
|
@Inheritance(strategy = InheritanceType.JOINED)
|
||||||
|
public abstract class AbstractExpression {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@NonNull
|
||||||
|
private String uuid = UUID.randomUUID().toString();
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Column(nullable = false)
|
||||||
|
private String name = "";
|
||||||
|
|
||||||
|
public abstract Object evaluate(@NonNull final Runtime runtime);
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public static <T, R> Object applyFallback(final Object v0, final Object v1, @NonNull final Function<Object, T> convert, @NonNull final T fallback, @NonNull final BiFunction<T, T, R> function) {
|
||||||
|
final T c0 = orElseNotNull(convert.apply(v0), fallback);
|
||||||
|
final T c1 = orElseNotNull(convert.apply(v1), fallback);
|
||||||
|
return function.apply(c0, c1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static <T, R> Object applyNullToNull(final Object value, @NonNull final Function<Object, T> convert, @NonNull final Function<T, R> function) {
|
||||||
|
final T converted = convert.apply(value);
|
||||||
|
if (converted == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return function.apply(converted);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static <T, R> Object applyNullToNull(final Object v0, final Object v1, @NonNull final Function<Object, T> convert, @NonNull final BiFunction<T, T, R> function) {
|
||||||
|
final T c0 = convert.apply(v0);
|
||||||
|
final T c1 = convert.apply(v1);
|
||||||
|
if (c0 == null || c1 == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return function.apply(c0, c1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static Object evalOrNull(@NonNull final Runtime runtime, @Nullable final AbstractExpression expression) {
|
||||||
|
if (expression == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return expression.evaluate(runtime);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static Boolean convertToBoolean(@Nullable final Object value) {
|
||||||
|
if (value == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (value instanceof Boolean) {
|
||||||
|
return (boolean) value;
|
||||||
|
}
|
||||||
|
final Double number = convertToNumber(value);
|
||||||
|
if (number == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return number > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static Double convertToNumber(@Nullable final Object value) {
|
||||||
|
if (value == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (value instanceof Number) {
|
||||||
|
return (double) value;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return Double.parseDouble((String) value);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public static <T> T orElseNotNull(@Nullable final T t, @NonNull final T orElse) {
|
||||||
|
if (t == null) {
|
||||||
|
return orElse;
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public static <T, R> R mapOrElseNotNull(@Nullable final T t, @NonNull final Function<T, R> tr, @NonNull final R orElse) {
|
||||||
|
if (t == null) {
|
||||||
|
return orElse;
|
||||||
|
}
|
||||||
|
final R r = tr.apply(t);
|
||||||
|
if (r == null) {
|
||||||
|
return orElse;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public static <T, U, R> R mapOrElseNotNull(@Nullable final T t, @NonNull final Function<T, U> tu, @NonNull final Function<U, R> ur, @NonNull final R orElse) {
|
||||||
|
if (t == null) {
|
||||||
|
return orElse;
|
||||||
|
}
|
||||||
|
final U u = tu.apply(t);
|
||||||
|
if (u == null) {
|
||||||
|
return orElse;
|
||||||
|
}
|
||||||
|
final R r = ur.apply(u);
|
||||||
|
if (r == null) {
|
||||||
|
return orElse;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static <T> T orElse(@Nullable final T t, @Nullable final T orElse) {
|
||||||
|
if (t == null) {
|
||||||
|
return orElse;
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static <T, R> R mapOrElse(@Nullable final T t, @NonNull final Function<T, R> tr, @Nullable final R orElse) {
|
||||||
|
if (t == null) {
|
||||||
|
return orElse;
|
||||||
|
}
|
||||||
|
final R r = tr.apply(t);
|
||||||
|
if (r == null) {
|
||||||
|
return orElse;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static <T, U, R> R mapOrElse(@Nullable final T t, @NonNull final Function<T, U> tu, @NonNull final Function<U, R> ur, @Nullable final R orElse) {
|
||||||
|
if (t == null) {
|
||||||
|
return orElse;
|
||||||
|
}
|
||||||
|
final U u = tu.apply(t);
|
||||||
|
if (u == null) {
|
||||||
|
return orElse;
|
||||||
|
}
|
||||||
|
final R r = ur.apply(u);
|
||||||
|
if (r == null) {
|
||||||
|
return orElse;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
package de.ph87.home.expression;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public abstract class AbstractExpressionController<E extends AbstractExpression, D extends AbstractExpressionDto> {
|
||||||
|
|
||||||
|
protected final AbstractExpressionService<E, D> expressionService;
|
||||||
|
|
||||||
|
@GetMapping("{uuid}")
|
||||||
|
public D byUuid(@PathVariable("uuid") String uuid) {
|
||||||
|
return expressionService.getDtoByUuid(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,27 @@
|
|||||||
|
package de.ph87.home.expression;
|
||||||
|
|
||||||
|
import jakarta.annotation.Nullable;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ToString
|
||||||
|
public abstract class AbstractExpressionDto {
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private final String uuid;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private final Object value;
|
||||||
|
|
||||||
|
protected AbstractExpressionDto(@NonNull final AbstractExpression expression, @Nullable final Object value) {
|
||||||
|
this.uuid = expression.getUuid();
|
||||||
|
this.name = expression.getName();
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
package de.ph87.home.expression;
|
||||||
|
|
||||||
|
import org.springframework.data.repository.ListCrudRepository;
|
||||||
|
import org.springframework.data.repository.NoRepositoryBean;
|
||||||
|
|
||||||
|
@NoRepositoryBean
|
||||||
|
public interface AbstractExpressionRepository<E extends AbstractExpression> extends ListCrudRepository<E, String> {
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,48 @@
|
|||||||
|
package de.ph87.home.expression;
|
||||||
|
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@Transactional
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public abstract class AbstractExpressionService<E extends AbstractExpression, D extends AbstractExpressionDto> {
|
||||||
|
|
||||||
|
protected final AbstractExpressionRepository<E> repository;
|
||||||
|
|
||||||
|
protected final ApplicationEventPublisher applicationEventPublisher;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public D set(@NonNull final String uuid, @NonNull final Consumer<E> setter) {
|
||||||
|
final E expression = getByUuid(uuid);
|
||||||
|
setter.accept(expression);
|
||||||
|
return publish(expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private E getByUuid(@NonNull final String uuid) {
|
||||||
|
return repository.findById(uuid).orElseThrow();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public D getDtoByUuid(@NonNull final String uuid) {
|
||||||
|
return toDto(getByUuid(uuid));
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private D publish(@NonNull final E expression) {
|
||||||
|
final D dto = toDto(expression);
|
||||||
|
applicationEventPublisher.publishEvent(dto);
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract D toDto(final E expression);
|
||||||
|
|
||||||
|
}
|
||||||
26
src/main/java/de/ph87/home/expression/Runtime.java
Normal file
26
src/main/java/de/ph87/home/expression/Runtime.java
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package de.ph87.home.expression;
|
||||||
|
|
||||||
|
import de.ph87.home.property.PropertyService;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ToString
|
||||||
|
public class Runtime {
|
||||||
|
|
||||||
|
public final ZonedDateTime now = ZonedDateTime.now();
|
||||||
|
|
||||||
|
public final Map<String, Object> write = new HashMap<>();
|
||||||
|
|
||||||
|
public final PropertyService propertyService;
|
||||||
|
|
||||||
|
public Runtime(@NonNull final PropertyService propertyService) {
|
||||||
|
this.propertyService = propertyService;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
package de.ph87.home.expression.expression;
|
||||||
|
|
||||||
|
import de.ph87.home.expression.AbstractExpression;
|
||||||
|
import de.ph87.home.expression.AbstractExpressionController;
|
||||||
|
import de.ph87.home.expression.AbstractExpressionDto;
|
||||||
|
import de.ph87.home.expression.AbstractExpressionService;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("Expression")
|
||||||
|
public class ExpressionController extends AbstractExpressionController<AbstractExpression, AbstractExpressionDto> {
|
||||||
|
|
||||||
|
public ExpressionController(final AbstractExpressionService<AbstractExpression, AbstractExpressionDto> expressionService) {
|
||||||
|
super(expressionService);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,60 @@
|
|||||||
|
package de.ph87.home.expression.expression;
|
||||||
|
|
||||||
|
import de.ph87.home.expression.AbstractExpression;
|
||||||
|
import de.ph87.home.expression.AbstractExpressionDto;
|
||||||
|
import de.ph87.home.expression.AbstractExpressionRepository;
|
||||||
|
import de.ph87.home.expression.AbstractExpressionService;
|
||||||
|
import de.ph87.home.expression.expression.literal.bool.ExpressionLiteralBoolean;
|
||||||
|
import de.ph87.home.expression.expression.literal.bool.ExpressionLiteralBooleanService;
|
||||||
|
import de.ph87.home.expression.expression.literal.number.ExpressionLiteralDouble;
|
||||||
|
import de.ph87.home.expression.expression.literal.number.ExpressionLiteralDoubleService;
|
||||||
|
import de.ph87.home.expression.expression.list.ExpressionList;
|
||||||
|
import de.ph87.home.expression.expression.list.ExpressionListService;
|
||||||
|
import de.ph87.home.expression.expression.property.ExpressionProperty;
|
||||||
|
import de.ph87.home.expression.expression.property.ExpressionPropertyService;
|
||||||
|
import de.ph87.home.expression.expression.unary.ExpressionUnary;
|
||||||
|
import de.ph87.home.expression.expression.unary.ExpressionUnaryService;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@Transactional
|
||||||
|
public class ExpressionMapper extends AbstractExpressionService<AbstractExpression, AbstractExpressionDto> {
|
||||||
|
|
||||||
|
private final ExpressionLiteralBooleanService expressionLiteralBooleanService;
|
||||||
|
|
||||||
|
private final ExpressionLiteralDoubleService expressionLiteralDoubleService;
|
||||||
|
|
||||||
|
private final ExpressionUnaryService expressionUnaryService;
|
||||||
|
|
||||||
|
private final ExpressionListService expressionNaryService;
|
||||||
|
|
||||||
|
private final ExpressionPropertyService expressionPropertyService;
|
||||||
|
|
||||||
|
public ExpressionMapper(final AbstractExpressionRepository<AbstractExpression> repository, final ApplicationEventPublisher applicationEventPublisher, final ExpressionLiteralBooleanService expressionLiteralBooleanService, final ExpressionLiteralDoubleService expressionLiteralDoubleService, final ExpressionUnaryService expressionUnaryService, final ExpressionListService expressionNaryService, final ExpressionPropertyService expressionPropertyService) {
|
||||||
|
super(repository, applicationEventPublisher);
|
||||||
|
this.expressionLiteralBooleanService = expressionLiteralBooleanService;
|
||||||
|
this.expressionLiteralDoubleService = expressionLiteralDoubleService;
|
||||||
|
this.expressionUnaryService = expressionUnaryService;
|
||||||
|
this.expressionNaryService = expressionNaryService;
|
||||||
|
this.expressionPropertyService = expressionPropertyService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public AbstractExpressionDto toDto(@NonNull final AbstractExpression expression) {
|
||||||
|
return switch (expression) {
|
||||||
|
case final ExpressionLiteralBoolean expressionLiteralBoolean -> expressionLiteralBooleanService.toDto(expressionLiteralBoolean);
|
||||||
|
case final ExpressionLiteralDouble expressionLiteralDouble -> expressionLiteralDoubleService.toDto(expressionLiteralDouble);
|
||||||
|
case final ExpressionProperty expressionProperty -> expressionPropertyService.toDto(expressionProperty);
|
||||||
|
case final ExpressionUnary expressionUnary -> expressionUnaryService.toDto(expressionUnary);
|
||||||
|
case final ExpressionList expressionNary -> expressionNaryService.toDto(expressionNary);
|
||||||
|
default -> throw new RuntimeException("Expression type not implemented: " + expression.getClass().getSimpleName());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
package de.ph87.home.expression.expression;
|
||||||
|
|
||||||
|
import de.ph87.home.expression.AbstractExpression;
|
||||||
|
import de.ph87.home.expression.AbstractExpressionRepository;
|
||||||
|
|
||||||
|
public interface ExpressionRepository extends AbstractExpressionRepository<AbstractExpression> {
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,60 @@
|
|||||||
|
package de.ph87.home.expression.expression;
|
||||||
|
|
||||||
|
import de.ph87.home.expression.AbstractExpression;
|
||||||
|
import de.ph87.home.expression.AbstractExpressionDto;
|
||||||
|
import de.ph87.home.expression.AbstractExpressionRepository;
|
||||||
|
import de.ph87.home.expression.AbstractExpressionService;
|
||||||
|
import de.ph87.home.expression.expression.literal.bool.ExpressionLiteralBoolean;
|
||||||
|
import de.ph87.home.expression.expression.literal.bool.ExpressionLiteralBooleanService;
|
||||||
|
import de.ph87.home.expression.expression.literal.number.ExpressionLiteralDouble;
|
||||||
|
import de.ph87.home.expression.expression.literal.number.ExpressionLiteralDoubleService;
|
||||||
|
import de.ph87.home.expression.expression.list.ExpressionList;
|
||||||
|
import de.ph87.home.expression.expression.list.ExpressionListService;
|
||||||
|
import de.ph87.home.expression.expression.property.ExpressionProperty;
|
||||||
|
import de.ph87.home.expression.expression.property.ExpressionPropertyService;
|
||||||
|
import de.ph87.home.expression.expression.unary.ExpressionUnary;
|
||||||
|
import de.ph87.home.expression.expression.unary.ExpressionUnaryService;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@Transactional
|
||||||
|
public class ExpressionService extends AbstractExpressionService<AbstractExpression, AbstractExpressionDto> {
|
||||||
|
|
||||||
|
private final ExpressionLiteralBooleanService expressionLiteralBooleanService;
|
||||||
|
|
||||||
|
private final ExpressionLiteralDoubleService expressionLiteralDoubleService;
|
||||||
|
|
||||||
|
private final ExpressionUnaryService expressionUnaryService;
|
||||||
|
|
||||||
|
private final ExpressionListService expressionNaryService;
|
||||||
|
|
||||||
|
private final ExpressionPropertyService expressionPropertyService;
|
||||||
|
|
||||||
|
public ExpressionService(final AbstractExpressionRepository<AbstractExpression> repository, final ApplicationEventPublisher applicationEventPublisher, final ExpressionLiteralBooleanService expressionLiteralBooleanService, final ExpressionLiteralDoubleService expressionLiteralDoubleService, final ExpressionUnaryService expressionUnaryService, final ExpressionListService expressionNaryService, final ExpressionPropertyService expressionPropertyService) {
|
||||||
|
super(repository, applicationEventPublisher);
|
||||||
|
this.expressionLiteralBooleanService = expressionLiteralBooleanService;
|
||||||
|
this.expressionLiteralDoubleService = expressionLiteralDoubleService;
|
||||||
|
this.expressionUnaryService = expressionUnaryService;
|
||||||
|
this.expressionNaryService = expressionNaryService;
|
||||||
|
this.expressionPropertyService = expressionPropertyService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public AbstractExpressionDto toDto(@NonNull final AbstractExpression expression) {
|
||||||
|
return switch (expression) {
|
||||||
|
case final ExpressionLiteralBoolean expressionLiteralBoolean -> expressionLiteralBooleanService.toDto(expressionLiteralBoolean);
|
||||||
|
case final ExpressionLiteralDouble expressionLiteralDouble -> expressionLiteralDoubleService.toDto(expressionLiteralDouble);
|
||||||
|
case final ExpressionProperty expressionProperty -> expressionPropertyService.toDto(expressionProperty);
|
||||||
|
case final ExpressionUnary expressionUnary -> expressionUnaryService.toDto(expressionUnary);
|
||||||
|
case final ExpressionList expressionNary -> expressionNaryService.toDto(expressionNary);
|
||||||
|
default -> throw new RuntimeException("Expression type not implemented: " + expression.getClass().getSimpleName());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,42 @@
|
|||||||
|
package de.ph87.home.expression.expression.list;
|
||||||
|
|
||||||
|
import de.ph87.home.expression.AbstractExpression;
|
||||||
|
import de.ph87.home.expression.Runtime;
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
|
@Entity
|
||||||
|
@NoArgsConstructor
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class ExpressionList extends AbstractExpression {
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Enumerated(EnumType.STRING)
|
||||||
|
private ExpressionListOperator operator = ExpressionListOperator.OR;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@ManyToMany
|
||||||
|
@OrderColumn
|
||||||
|
private List<AbstractExpression> list = new ArrayList<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object evaluate(@NonNull final Runtime runtime) {
|
||||||
|
if (list.size() < 2) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
final List<Object> valueList = list.stream().map(e -> evalOrNull(runtime, e)).toList();
|
||||||
|
Object vLast = valueList.removeFirst();
|
||||||
|
while (!valueList.isEmpty()) {
|
||||||
|
final Object vNext = evalOrNull(runtime, list.removeFirst());
|
||||||
|
vLast = operator.apply(vLast, vNext);
|
||||||
|
}
|
||||||
|
return vLast;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
package de.ph87.home.expression.expression.list;
|
||||||
|
|
||||||
|
import de.ph87.home.expression.AbstractExpression;
|
||||||
|
import de.ph87.home.expression.AbstractExpressionDto;
|
||||||
|
import jakarta.annotation.Nullable;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class ExpressionListDto extends AbstractExpressionDto {
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private final ExpressionListOperator operator;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private final List<String> expressionUuidList;
|
||||||
|
|
||||||
|
public ExpressionListDto(@NonNull final ExpressionList expression, @Nullable final Object value) {
|
||||||
|
super(expression, value);
|
||||||
|
this.operator = expression.getOperator();
|
||||||
|
this.expressionUuidList = expression.getList().stream().map(AbstractExpression::getUuid).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,39 @@
|
|||||||
|
package de.ph87.home.expression.expression.list;
|
||||||
|
|
||||||
|
import de.ph87.home.expression.AbstractExpression;
|
||||||
|
import jakarta.annotation.Nullable;
|
||||||
|
import lombok.NonNull;
|
||||||
|
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
|
import static de.ph87.home.expression.AbstractExpression.applyFallback;
|
||||||
|
import static de.ph87.home.expression.AbstractExpression.applyNullToNull;
|
||||||
|
|
||||||
|
public enum ExpressionListOperator {
|
||||||
|
OR((v0, v1) -> applyFallback(v0, v1, AbstractExpression::convertToBoolean, false, (c0, c1) -> c0 || c1)),
|
||||||
|
AND((v0, v1) -> applyNullToNull(v0, v1, AbstractExpression::convertToBoolean, (c0, c1) -> c0 && c1)),
|
||||||
|
XOR((v0, v1) -> applyNullToNull(v0, v1, AbstractExpression::convertToBoolean, (c0, c1) -> c0 ^ c1)),
|
||||||
|
ADD((v0, v1) -> applyNullToNull(v0, v1, AbstractExpression::convertToNumber, Double::sum)),
|
||||||
|
SUB((v0, v1) -> applyNullToNull(v0, v1, AbstractExpression::convertToNumber, (c0, c1) -> c0 - c1)),
|
||||||
|
MUL((v0, v1) -> applyNullToNull(v0, v1, AbstractExpression::convertToNumber, (c0, c1) -> c0 * c1)),
|
||||||
|
DIV((v0, v1) -> applyNullToNull(v0, v1, AbstractExpression::convertToNumber, (c0, c1) -> c0 / c1)),
|
||||||
|
MOD((v0, v1) -> applyNullToNull(v0, v1, AbstractExpression::convertToNumber, (c0, c1) -> c0 % c1)),
|
||||||
|
POW((v0, v1) -> applyNullToNull(v0, v1, AbstractExpression::convertToNumber, Math::pow)),
|
||||||
|
HYPOT((v0, v1) -> applyNullToNull(v0, v1, AbstractExpression::convertToNumber, Math::hypot)),
|
||||||
|
ATAN2((v0, v1) -> applyNullToNull(v0, v1, AbstractExpression::convertToNumber, Math::atan2)),
|
||||||
|
MIN((v0, v1) -> applyNullToNull(v0, v1, AbstractExpression::convertToNumber, Math::min)),
|
||||||
|
MAX((v0, v1) -> applyNullToNull(v0, v1, AbstractExpression::convertToNumber, Math::max)),
|
||||||
|
;
|
||||||
|
|
||||||
|
private final BiFunction<Object, Object, Object> function;
|
||||||
|
|
||||||
|
ExpressionListOperator(@NonNull final BiFunction<Object, Object, Object> function) {
|
||||||
|
this.function = function;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public Object apply(@Nullable final Object v0, @Nullable final Object v1) {
|
||||||
|
return function.apply(v0, v1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
package de.ph87.home.expression.expression.list;
|
||||||
|
|
||||||
|
import de.ph87.home.expression.AbstractExpressionRepository;
|
||||||
|
|
||||||
|
public interface ExpressionListRepository extends AbstractExpressionRepository<ExpressionList> {
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
package de.ph87.home.expression.expression.list;
|
||||||
|
|
||||||
|
import de.ph87.home.expression.AbstractExpressionService;
|
||||||
|
import de.ph87.home.expression.Runtime;
|
||||||
|
import de.ph87.home.property.PropertyService;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@Transactional
|
||||||
|
public class ExpressionListService extends AbstractExpressionService<ExpressionList, ExpressionListDto> {
|
||||||
|
|
||||||
|
private final PropertyService propertyService;
|
||||||
|
|
||||||
|
public ExpressionListService(final ExpressionListRepository repository, final ApplicationEventPublisher applicationEventPublisher, final PropertyService propertyService) {
|
||||||
|
super(repository, applicationEventPublisher);
|
||||||
|
this.propertyService = propertyService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ExpressionListDto toDto(final ExpressionList expression) {
|
||||||
|
return new ExpressionListDto(expression, expression.evaluate(new Runtime(propertyService)));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
package de.ph87.home.expression.expression.literal;
|
||||||
|
|
||||||
|
import de.ph87.home.expression.AbstractExpression;
|
||||||
|
import de.ph87.home.expression.Runtime;
|
||||||
|
import jakarta.annotation.Nullable;
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.MappedSuperclass;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
|
@MappedSuperclass
|
||||||
|
@NoArgsConstructor
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public abstract class ExpressionLiteral<T> extends AbstractExpression {
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Column(name = "`value`")
|
||||||
|
private T value = null;
|
||||||
|
|
||||||
|
public ExpressionLiteral(final T value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public Object evaluate(@NonNull final Runtime runtime) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
package de.ph87.home.expression.expression.literal;
|
||||||
|
|
||||||
|
import de.ph87.home.expression.AbstractExpressionController;
|
||||||
|
import de.ph87.home.expression.AbstractExpressionDto;
|
||||||
|
import jakarta.annotation.Nullable;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
|
||||||
|
public abstract class ExpressionLiteralController<T, E extends ExpressionLiteral<T>, D extends AbstractExpressionDto> extends AbstractExpressionController<E, D> {
|
||||||
|
|
||||||
|
public ExpressionLiteralController(final ExpressionLiteralService<T, E, D> expressionService) {
|
||||||
|
super(expressionService);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@PostMapping("{uuid}/setValue")
|
||||||
|
public D setValue(@PathVariable final String uuid, @RequestBody(required = false) @Nullable final T value) {
|
||||||
|
return expressionService.set(uuid, e -> e.setValue(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
package de.ph87.home.expression.expression.literal;
|
||||||
|
|
||||||
|
import de.ph87.home.expression.AbstractExpressionDto;
|
||||||
|
import de.ph87.home.expression.AbstractExpressionRepository;
|
||||||
|
import de.ph87.home.expression.AbstractExpressionService;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@Transactional
|
||||||
|
public abstract class ExpressionLiteralService<T, E extends ExpressionLiteral<T>, D extends AbstractExpressionDto> extends AbstractExpressionService<E, D> {
|
||||||
|
|
||||||
|
public ExpressionLiteralService(final AbstractExpressionRepository<E> repository, final ApplicationEventPublisher applicationEventPublisher) {
|
||||||
|
super(repository, applicationEventPublisher);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
package de.ph87.home.expression.expression.literal.bool;
|
||||||
|
|
||||||
|
import de.ph87.home.expression.expression.literal.ExpressionLiteral;
|
||||||
|
import jakarta.annotation.Nullable;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
|
@Entity
|
||||||
|
@NoArgsConstructor
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class ExpressionLiteralBoolean extends ExpressionLiteral<Boolean> {
|
||||||
|
|
||||||
|
public ExpressionLiteralBoolean(@Nullable final Boolean value) {
|
||||||
|
super(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
package de.ph87.home.expression.expression.literal.bool;
|
||||||
|
|
||||||
|
import de.ph87.home.expression.expression.literal.ExpressionLiteralController;
|
||||||
|
import de.ph87.home.expression.expression.literal.ExpressionLiteralService;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("ExpressionLiteralBoolean")
|
||||||
|
public class ExpressionLiteralBooleanController extends ExpressionLiteralController<Boolean, ExpressionLiteralBoolean, ExpressionLiteralBooleanDto> {
|
||||||
|
|
||||||
|
public ExpressionLiteralBooleanController(final ExpressionLiteralService<Boolean, ExpressionLiteralBoolean, ExpressionLiteralBooleanDto> expressionLiteralService) {
|
||||||
|
super(expressionLiteralService);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
package de.ph87.home.expression.expression.literal.bool;
|
||||||
|
|
||||||
|
import de.ph87.home.expression.AbstractExpressionDto;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class ExpressionLiteralBooleanDto extends AbstractExpressionDto {
|
||||||
|
|
||||||
|
protected ExpressionLiteralBooleanDto(@NonNull final ExpressionLiteralBoolean expression) {
|
||||||
|
super(expression, expression.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
package de.ph87.home.expression.expression.literal.bool;
|
||||||
|
|
||||||
|
import de.ph87.home.expression.AbstractExpressionRepository;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface ExpressionLiteralBooleanRepository extends AbstractExpressionRepository<ExpressionLiteralBoolean> {
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
package de.ph87.home.expression.expression.literal.bool;
|
||||||
|
|
||||||
|
import de.ph87.home.expression.expression.literal.ExpressionLiteralService;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@Transactional
|
||||||
|
public class ExpressionLiteralBooleanService extends ExpressionLiteralService<Boolean, ExpressionLiteralBoolean, ExpressionLiteralBooleanDto> {
|
||||||
|
|
||||||
|
public ExpressionLiteralBooleanService(final ExpressionLiteralBooleanRepository repository, final ApplicationEventPublisher applicationEventPublisher) {
|
||||||
|
super(repository, applicationEventPublisher);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ExpressionLiteralBooleanDto toDto(final ExpressionLiteralBoolean expression) {
|
||||||
|
return new ExpressionLiteralBooleanDto(expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
package de.ph87.home.expression.expression.literal.number;
|
||||||
|
|
||||||
|
import de.ph87.home.expression.expression.literal.ExpressionLiteral;
|
||||||
|
import jakarta.annotation.Nullable;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
|
@Entity
|
||||||
|
@NoArgsConstructor
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class ExpressionLiteralDouble extends ExpressionLiteral<Double> {
|
||||||
|
|
||||||
|
public ExpressionLiteralDouble(@Nullable final Double value) {
|
||||||
|
super(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
package de.ph87.home.expression.expression.literal.number;
|
||||||
|
|
||||||
|
import de.ph87.home.expression.expression.literal.ExpressionLiteralController;
|
||||||
|
import de.ph87.home.expression.expression.literal.ExpressionLiteralService;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("ExpressionLiteralDouble")
|
||||||
|
public class ExpressionLiteralDoubleController extends ExpressionLiteralController<Double, ExpressionLiteralDouble, ExpressionLiteralDoubleDto> {
|
||||||
|
|
||||||
|
public ExpressionLiteralDoubleController(final ExpressionLiteralService<Double, ExpressionLiteralDouble, ExpressionLiteralDoubleDto> expressionLiteralService) {
|
||||||
|
super(expressionLiteralService);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
package de.ph87.home.expression.expression.literal.number;
|
||||||
|
|
||||||
|
import de.ph87.home.expression.AbstractExpressionDto;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class ExpressionLiteralDoubleDto extends AbstractExpressionDto {
|
||||||
|
|
||||||
|
protected ExpressionLiteralDoubleDto(@NonNull final ExpressionLiteralDouble expression) {
|
||||||
|
super(expression, expression.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
package de.ph87.home.expression.expression.literal.number;
|
||||||
|
|
||||||
|
import de.ph87.home.expression.AbstractExpressionRepository;
|
||||||
|
|
||||||
|
public interface ExpressionLiteralDoubleRepository extends AbstractExpressionRepository<ExpressionLiteralDouble> {
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
package de.ph87.home.expression.expression.literal.number;
|
||||||
|
|
||||||
|
import de.ph87.home.expression.expression.literal.ExpressionLiteralService;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@Transactional
|
||||||
|
public class ExpressionLiteralDoubleService extends ExpressionLiteralService<Double, ExpressionLiteralDouble, ExpressionLiteralDoubleDto> {
|
||||||
|
|
||||||
|
public ExpressionLiteralDoubleService(final ExpressionLiteralDoubleRepository repository, final ApplicationEventPublisher applicationEventPublisher) {
|
||||||
|
super(repository, applicationEventPublisher);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ExpressionLiteralDoubleDto toDto(final ExpressionLiteralDouble expression) {
|
||||||
|
return new ExpressionLiteralDoubleDto(expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
package de.ph87.home.expression.expression.property;
|
||||||
|
|
||||||
|
import de.ph87.home.expression.AbstractExpression;
|
||||||
|
import de.ph87.home.expression.Runtime;
|
||||||
|
import de.ph87.home.property.Property;
|
||||||
|
import de.ph87.home.property.State;
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
|
@Entity
|
||||||
|
@NoArgsConstructor
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class ExpressionProperty extends AbstractExpression {
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Column(nullable = false)
|
||||||
|
private String propertyId;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object evaluate(@NonNull final Runtime runtime) {
|
||||||
|
return runtime.propertyService.findById(propertyId).map(Property::getState).map(State::getValue).orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
package de.ph87.home.expression.expression.property;
|
||||||
|
|
||||||
|
import de.ph87.home.expression.AbstractExpressionDto;
|
||||||
|
import de.ph87.home.property.IProperty;
|
||||||
|
import de.ph87.home.property.PropertyDto;
|
||||||
|
import jakarta.annotation.Nullable;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
import static de.ph87.home.expression.AbstractExpression.mapOrElse;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class ExpressionPropertyDto extends AbstractExpressionDto {
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private final String propertyId;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private final PropertyDto<?> property;
|
||||||
|
|
||||||
|
public ExpressionPropertyDto(@NonNull final ExpressionProperty expressionProperty, @Nullable final PropertyDto<?> property) {
|
||||||
|
super(expressionProperty, mapOrElse(property, IProperty::getStateValue, null));
|
||||||
|
this.propertyId = expressionProperty.getPropertyId();
|
||||||
|
this.property = property;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
package de.ph87.home.expression.expression.property;
|
||||||
|
|
||||||
|
import de.ph87.home.expression.AbstractExpressionRepository;
|
||||||
|
|
||||||
|
public interface ExpressionPropertyRepository extends AbstractExpressionRepository<ExpressionProperty> {
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
package de.ph87.home.expression.expression.property;
|
||||||
|
|
||||||
|
import de.ph87.home.expression.AbstractExpressionService;
|
||||||
|
import de.ph87.home.property.PropertyDto;
|
||||||
|
import de.ph87.home.property.PropertyService;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@Transactional
|
||||||
|
public class ExpressionPropertyService extends AbstractExpressionService<ExpressionProperty, ExpressionPropertyDto> {
|
||||||
|
|
||||||
|
private final PropertyService propertyService;
|
||||||
|
|
||||||
|
public ExpressionPropertyService(final ExpressionPropertyRepository repository, final ApplicationEventPublisher applicationEventPublisher, final PropertyService propertyService) {
|
||||||
|
super(repository, applicationEventPublisher);
|
||||||
|
this.propertyService = propertyService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ExpressionPropertyDto toDto(final ExpressionProperty expressionProperty) {
|
||||||
|
final PropertyDto<?> property = propertyService.dtoByIdOrNull(expressionProperty.getPropertyId());
|
||||||
|
return new ExpressionPropertyDto(expressionProperty, property);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
package de.ph87.home.expression.expression.unary;
|
||||||
|
|
||||||
|
import de.ph87.home.expression.AbstractExpression;
|
||||||
|
import de.ph87.home.expression.Runtime;
|
||||||
|
import jakarta.annotation.Nullable;
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
|
@Entity
|
||||||
|
@NoArgsConstructor
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class ExpressionUnary extends AbstractExpression {
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Enumerated(EnumType.STRING)
|
||||||
|
private ExpressionUnaryOperator operator = ExpressionUnaryOperator.NOT;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
private AbstractExpression expression;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object evaluate(@NonNull final Runtime runtime) {
|
||||||
|
final Object value = evalOrNull(runtime, expression);
|
||||||
|
return operator.apply(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
package de.ph87.home.expression.expression.unary;
|
||||||
|
|
||||||
|
import de.ph87.home.expression.AbstractExpression;
|
||||||
|
import de.ph87.home.expression.AbstractExpressionDto;
|
||||||
|
import jakarta.annotation.Nullable;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
import static de.ph87.home.expression.AbstractExpression.mapOrElse;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class ExpressionUnaryDto extends AbstractExpressionDto {
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private final ExpressionUnaryOperator operator;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private final String expressionUuid;
|
||||||
|
|
||||||
|
public ExpressionUnaryDto(@NonNull final ExpressionUnary expressionUnary, @Nullable final Object value) {
|
||||||
|
super(expressionUnary, value);
|
||||||
|
this.operator = expressionUnary.getOperator();
|
||||||
|
this.expressionUuid = mapOrElse(expressionUnary.getExpression(), AbstractExpression::getUuid, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,42 @@
|
|||||||
|
package de.ph87.home.expression.expression.unary;
|
||||||
|
|
||||||
|
import de.ph87.home.expression.AbstractExpression;
|
||||||
|
import jakarta.annotation.Nullable;
|
||||||
|
import lombok.NonNull;
|
||||||
|
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public enum ExpressionUnaryOperator {
|
||||||
|
NOT(v -> AbstractExpression.applyNullToNull(v, AbstractExpression::convertToBoolean, c -> !c)),
|
||||||
|
NEG(v -> AbstractExpression.applyNullToNull(v, AbstractExpression::convertToNumber, c -> -c)),
|
||||||
|
POS(v -> AbstractExpression.applyNullToNull(v, AbstractExpression::convertToNumber, c -> +c)),
|
||||||
|
FLOOR(v -> AbstractExpression.applyNullToNull(v, AbstractExpression::convertToNumber, Math::floor)),
|
||||||
|
CEIL(v -> AbstractExpression.applyNullToNull(v, AbstractExpression::convertToNumber, Math::ceil)),
|
||||||
|
ROUND(v -> AbstractExpression.applyNullToNull(v, AbstractExpression::convertToNumber, Math::round)),
|
||||||
|
SQRT(v -> AbstractExpression.applyNullToNull(v, AbstractExpression::convertToNumber, Math::sqrt)),
|
||||||
|
ABS(v -> AbstractExpression.applyNullToNull(v, AbstractExpression::convertToNumber, Math::abs)),
|
||||||
|
COS(v -> AbstractExpression.applyNullToNull(v, AbstractExpression::convertToNumber, Math::cos)),
|
||||||
|
SIN(v -> AbstractExpression.applyNullToNull(v, AbstractExpression::convertToNumber, Math::sin)),
|
||||||
|
TAN(v -> AbstractExpression.applyNullToNull(v, AbstractExpression::convertToNumber, Math::tan)),
|
||||||
|
ACOS(v -> AbstractExpression.applyNullToNull(v, AbstractExpression::convertToNumber, Math::acos)),
|
||||||
|
ASIN(v -> AbstractExpression.applyNullToNull(v, AbstractExpression::convertToNumber, Math::asin)),
|
||||||
|
ATAN(v -> AbstractExpression.applyNullToNull(v, AbstractExpression::convertToNumber, Math::atan)),
|
||||||
|
COSH(v -> AbstractExpression.applyNullToNull(v, AbstractExpression::convertToNumber, Math::cosh)),
|
||||||
|
SINH(v -> AbstractExpression.applyNullToNull(v, AbstractExpression::convertToNumber, Math::sinh)),
|
||||||
|
TANH(v -> AbstractExpression.applyNullToNull(v, AbstractExpression::convertToNumber, Math::tanh)),
|
||||||
|
EXP(v -> AbstractExpression.applyNullToNull(v, AbstractExpression::convertToNumber, Math::exp)),
|
||||||
|
EXPM1(v -> AbstractExpression.applyNullToNull(v, AbstractExpression::convertToNumber, Math::expm1)),
|
||||||
|
;
|
||||||
|
|
||||||
|
private final Function<Object, Object> function;
|
||||||
|
|
||||||
|
ExpressionUnaryOperator(@NonNull final Function<Object, Object> function) {
|
||||||
|
this.function = function;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public Object apply(@Nullable final Object value) {
|
||||||
|
return function.apply(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
package de.ph87.home.expression.expression.unary;
|
||||||
|
|
||||||
|
import de.ph87.home.expression.AbstractExpressionRepository;
|
||||||
|
|
||||||
|
public interface ExpressionUnaryRepository extends AbstractExpressionRepository<ExpressionUnary> {
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
package de.ph87.home.expression.expression.unary;
|
||||||
|
|
||||||
|
import de.ph87.home.expression.AbstractExpressionService;
|
||||||
|
import de.ph87.home.expression.Runtime;
|
||||||
|
import de.ph87.home.property.PropertyService;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@Transactional
|
||||||
|
public class ExpressionUnaryService extends AbstractExpressionService<ExpressionUnary, ExpressionUnaryDto> {
|
||||||
|
|
||||||
|
private final PropertyService propertyService;
|
||||||
|
|
||||||
|
public ExpressionUnaryService(final ExpressionUnaryRepository repository, final ApplicationEventPublisher applicationEventPublisher, final PropertyService propertyService) {
|
||||||
|
super(repository, applicationEventPublisher);
|
||||||
|
this.propertyService = propertyService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ExpressionUnaryDto toDto(final ExpressionUnary expression) {
|
||||||
|
return new ExpressionUnaryDto(expression, expression.evaluate(new Runtime(propertyService)));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -89,7 +89,7 @@ public class PropertyService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private Optional<Property<?>> findById(final String id) {
|
public Optional<Property<?>> findById(final String id) {
|
||||||
return propertyList.stream().filter(p -> p.getId().equals(id)).findFirst();
|
return propertyList.stream().filter(p -> p.getId().equals(id)).findFirst();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,4 +120,9 @@ public class PropertyService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public PropertyDto<?> dtoByIdOrNull(@NonNull final String propertyId) {
|
||||||
|
return findById(propertyId).map(this::toDto).orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user