Skip to main content

8.2 Data models

DataQL uses DataModel for runtime data and query results. Java callers obtain the model through QueryResult.getData() and ordinary Java data through unwrap().

Model types​

ModelType checkContent
ValueModelisValue()Strings, numbers, booleans and null
ListModelisList()Ordered lists
ObjectModelisObject()Fields in insertion order
UdfModelisUdf()Callable functions
BinaryModelisBinary()Files, bytes or input streams

Java conversion​

DomainHelper.convertTo(value) converts Java data into models, recursively converting fields and list elements.

Java inputModel
null, Boolean, NumberValueModel; numbers retain their Java type
Character, CharSequence, UUID, EnumString ValueModel; enums use name()
DateMillisecond timestamp ValueModel
Map, Java BeanObjectModel; Map keys become strings; Bean conversion reads readable properties except class
Collection, arraysListModel; char[] becomes character strings, byte[] becomes numbers
UdfUdfModel
DataModelThe original instance, including BinaryModel

Input must have no cyclic references. Map keys cannot be null; keys that become identical strings use the last value.

Read and modify​

ObjectModel.put and ListModel.add convert values automatically. get returns DataModel; getValue, getList, getObject and getUdf return typed models.

import java.util.Map;
import net.hasor.dataql.domain.DomainHelper;
import net.hasor.dataql.domain.ListModel;
import net.hasor.dataql.domain.ObjectModel;

ObjectModel user = (ObjectModel) DomainHelper.convertTo(Map.of("name", "Alice", "age", 18));
user.put("nickname", null);
String name = user.getValue("name").asString(); // Alice
int age = user.getValue("age").asInt(); // 18
boolean empty = user.getValue("nickname").isNull(); // true
boolean absent = user.get("unknown") == null; // true

ListModel users = new ListModel();
users.add(user);
String firstName = users.getObject(0).getValue("name").asString(); // Alice
  • Field names are case-sensitive. Missing fields return null and fail type checks; explicit null is stored as ValueModel.
  • Java list indexes start at 0; out-of-range access throws IndexOutOfBoundsException. The engine handles script negative indexes and INDEX_OVERFLOW.
  • Typed getters throw ClassCastException on a type mismatch. Check binary values with get(...).isBinary().

Value conversion​

ValueModel provides isString(), isNumber(), isBoolean() and isNull(). Conversions leave the stored value unchanged:

MethodBehavior
asString()Calls toString(); null returns null
asBoolean()Nonzero numbers are true; strings accept case-insensitive true/false and 1/0; null returns false
asNumber()Returns the original Number without parsing strings; null returns integer 0
asInt(), asLong(), asDouble(), etc.Converts numeric strings and booleans (1/0) to the target number type; null returns 0

Numeric checks include compatible types: Byte passes isInt(). For the exact Java type, check asOri().getClass() after excluding null. Narrowing can truncate or overflow; invalid conversions throw exceptions. Script functions are covered in Conversion functions.

Unwrap results​

ModelasOri()unwrap()
ValueModelOriginal valueOriginal value
ListModel / ObjectModelInternal mutable List / Map of modelsNew ordinary List / Map, recursively unwrapped with null preserved
UdfModelOriginal UdfOriginal Udf
BinaryModelThe model itselfThe model itself

Use put and add to modify models and unwrap() to obtain ordinary data. Unwrapping neither serializes JSON nor reads binary streams.

Binary resources​

Create binary values explicitly with BinaryValue; ordinary byte[] uses list semantics. Binary values retain their identity in parameters, variables and function calls.

import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import net.hasor.dataql.domain.BinaryValue;

try (BinaryValue content = new BinaryValue("Hello DataQL".getBytes(StandardCharsets.UTF_8));
InputStream input = content.openStream()) {
String text = new String(input.readAllBytes(), StandardCharsets.UTF_8);
System.out.println(text);
}
  • BinaryValue(byte[]): Streams can be reopened. The original array is retained; avoid modifying it after construction.
  • BinaryValue(InputStream): Opens only once. getSize() returns -1 for unknown size.
  • Extend BinaryModel: Implement openStream() and optionally override getSize().

Callers close the reading stream. A closed BinaryValue cannot be reopened. Binary values do not automatically participate in arithmetic or JSON encoding. See Result responses for HTTP output.

Function models​

UdfModel wraps Udf. Script lambdas and imported functions can be passed as values. In Java, create a model with DomainHelper.convertTo(udf); UdfModel.call(Hints, UdfParams) converts the function result into DataModel.

The call declares throws Throwable; Java callers must handle or declare it. Script calls receive parameters from the engine. See Custom functions for implementation and registration, and Application object imports for importing Java methods.