Msg.java
/*
* SPDX-FileCopyrightText: 2025 kaumei.io
* SPDX-License-Identifier: Apache-2.0
*/
package io.kaumei.jdbc.anno.msg;
import org.jspecify.annotations.Nullable;
import java.util.Collections;
import java.util.TreeSet;
import java.util.function.Supplier;
public interface Msg {
static Msg.Builder builder() {
return new MsgBuilderImpl();
}
static Msg.Message of(String text) {
return new MessageImpl(text);
}
static Messages empty() {
return MessagesEmptyImpl.EMPTY_LIST;
}
static <T> Msg.Result<T> result(T value) {
return new MessageResultImpl<>(value);
}
static <T> Msg.Result<T> result(Messages messages) {
return new MessageResultImpl<>(messages);
}
static <T> Msg.NullableResult<T> nullableResult(@Nullable T value) {
return new MessageResultNullableImpl<T>(value);
}
static <T> Msg.NullableResult<T> nullableResult(Messages messages) {
return new MessageResultNullableImpl<>(messages);
}
// ------------------------------------------------------------------------
static Messages merge(Msg.Message msg1, Msg.Message msg2) {
var s = new TreeSet<Msg.Message>();
s.add(msg1);
s.add(msg2);
return new MessagesImpl(s);
}
static Messages merge(Msg.Message... messages) {
var s = new TreeSet<Msg.Message>();
Collections.addAll(s, messages);
return new MessagesImpl(s);
}
static Messages merge(Messages msgSet1, Messages msgSet2, Msg.Message msg) {
var s = new TreeSet<Msg.Message>();
for (var item : msgSet1) {
s.add(item);
}
for (var item : msgSet2) {
s.add(item);
}
s.add(msg);
return new MessagesImpl(s);
}
static Messages merge(Messages msgSet1, Messages msgSet2) {
var s = new TreeSet<Msg.Message>();
for (var item : msgSet1) {
s.add(item);
}
for (var item : msgSet2) {
s.add(item);
}
return s.isEmpty() ? Msg.empty() : new MessagesImpl(s);
}
// ------------------------------------------------------------------------
sealed interface Builder permits MsgBuilderImpl {
boolean hasMessages();
boolean hasNoMessages();
String join(String sep);
void requireEmpty();
Messages build();
/**
* Will fail if the value is null, regardless of whether messages are
* present or not.
* For a lazy null check, use build(Supplier<T> func).
*/
<T> Result<T> build(T value);
<T> Result<T> build(Supplier<T> func);
<T> NullableResult<T> buildOpt(@Nullable T value);
Builder add(Message msg);
Builder add(boolean test, Message msg);
Builder add(Supplier<Boolean> test, Message msg);
Builder add(Messages msg);
Builder add(@Nullable HasMessages value);
}
sealed interface Messages extends Iterable<Msg.Message> permits MessagesEmptyImpl, MessagesImpl, Message {
boolean hasMessages();
boolean hasNoMessages();
String join(String sep);
void join(StringBuilder sb, String sep);
void requireEmpty();
Messages requireNoneEmpty();
/**
* Will fail if the value is null, regardless of whether messages are
* present or not.
* For a lazy null check, use build(Supplier<T> func).
*/
<T> Result<T> build(T value);
<T> Result<T> build(Supplier<T> func);
<T> NullableResult<T> buildOpt(@Nullable T value);
}
sealed interface Message extends Messages, Comparable<Msg.Message> permits MessageImpl {
String text();
}
interface HasMessages {
boolean hasMessages();
Messages messages();
}
sealed interface Result<T> extends HasMessages permits MessageResultImpl {
T value();
/**
* @return the value or in case the result has messages null
*/
@Nullable T valueOrNull();
}
sealed interface NullableResult<T> extends HasMessages permits MessageResultNullableImpl {
/**
* @return if value is null and no messages
*/
boolean isNull();
/**
* @return the value and ensures to be always not null
* @throws IllegalStateException if the result has messages or the value is null
*/
T value();
@Nullable T valueOpt();
}
}