Repository navigation
Expand file tree
/
Copy pathGeneratedExactDecimalProbe.java
More file actions
122 lines (112 loc) · 6.35 KB
/
Copy pathGeneratedExactDecimalProbe.java
File metadata and controls
122 lines (112 loc) · 6.35 KB
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
package com.example.exactdecimalservice;
import com.example.exactdecimalservice.decimalentry.DecimalEntry;
import com.example.exactdecimalservice.platform.Platform;
import io.teaql.core.meta.SimpleEntityMetaFactory;
import io.teaql.core.sql.portable.IdSpaceIdGenerator;
import io.teaql.core.sqlite.SqliteDataServiceExecutor;
import io.teaql.provider.jdbc.JdbcSqlExecutor;
import io.teaql.runtime.TeaQLRuntime;
import java.math.BigDecimal;
import java.nio.file.Files;
import java.nio.file.Path;
import org.sqlite.SQLiteDataSource;
/** Application-owned exact Decimal check against a freshly generated domain library. */
public final class GeneratedExactDecimalProbe {
private GeneratedExactDecimalProbe() {}
private static TeaQLRuntime runtime(SQLiteDataSource dataSource, JdbcSqlExecutor sql) {
return TeaQLRuntime.builder()
.metadata(new SimpleEntityMetaFactory())
.dataService("default", new SqliteDataServiceExecutor("default", sql, dataSource))
.idGenerationService(new IdSpaceIdGenerator(new WorkspaceTeaQLDatabase(sql, dataSource)))
.executionLogging(false)
.build()
.install(GeneratedRuntimeModule.module());
}
public static void main(String[] args) throws Exception {
Path directory = Files.createTempDirectory("teaql-java-generated-exact-decimal-");
SQLiteDataSource sourceData = new SQLiteDataSource();
sourceData.setUrl("jdbc:sqlite:" + directory.resolve("source.sqlite"));
JdbcSqlExecutor sourceSql = new JdbcSqlExecutor(sourceData);
var source = new CustomUserContext(runtime(sourceData, sourceSql));
source.ensureSchema();
Platform platform = Q.platforms().withIdIs(1L)
.comment("Locate the exact Decimal platform")
.purpose("Attach ledger entries to their generated root")
.executeForOne(source);
if (platform == null) throw new AssertionError("seeded platform is missing");
save(source, platform, "first", new BigDecimal("0.1"));
save(source, platform, "second", new BigDecimal("0.2"));
var loaded = Q.decimalEntriesWithMinimalFields()
.selectLabel().selectAmount()
.withAmountIs(new BigDecimal("0.1"))
.orderByIdAscending().limit(10)
.comment("Read a generated exact Decimal row")
.purpose("Verify Q filtering and E hydration")
.executeForList(source);
if (loaded.size() != 1 || !"first".equals(E.decimalEntry(loaded.get(0)).getLabel().eval())
|| E.decimalEntry(loaded.get(0)).getAmount().eval().compareTo(new BigDecimal("0.1")) != 0) {
throw new AssertionError("generated Decimal Q/E round-trip failed");
}
if (sum(source).compareTo(new BigDecimal("0.3")) != 0) {
throw new AssertionError("generated Decimal SUM is not exact");
}
DecimalEntry preciseEntry = save(source, platform, "precise", new BigDecimal("3.50"));
BigDecimal scale = reloadAmount(source, preciseEntry.getId());
if (!new BigDecimal("3.50").equals(scale)) {
throw new AssertionError("generated Decimal scale was not preserved: " + scale);
}
BigDecimal preciseInput = new BigDecimal("123456789012.3456789");
preciseEntry.updateAmount(preciseInput);
preciseEntry.auditAs("Update exact Decimal precision for generated integration gate").save(source);
BigDecimal precision = reloadAmount(source, preciseEntry.getId());
if (!preciseInput.equals(precision)) {
throw new AssertionError("generated Decimal precision was not preserved: " + precision);
}
for (String exponent : new String[] {"1E-7", "1E+8"}) {
BigDecimal input = new BigDecimal(exponent);
DecimalEntry entry = save(source, platform, "exponent " + exponent, input);
BigDecimal reloaded = reloadAmount(source, entry.getId());
var filtered = Q.decimalEntriesWithMinimalFields().selectAmount()
.withIdIs(entry.getId()).withAmountIs(input).limit(1)
.comment("Find generated exact Decimal exponent value")
.purpose("Verify canonical SQLite binding in generated Q and mutation APIs")
.executeForOne(source);
if (input.compareTo(reloaded) != 0 || filtered == null
|| input.compareTo(E.decimalEntry(filtered).getAmount().eval()) != 0) {
throw new AssertionError("generated Decimal exponent round-trip failed: " + exponent);
}
}
System.out.println("GENERATED_EXACT_DECIMAL_PASS q=1 e=1 save=5 update=1 sum=0.3 scale=3.50 precision=19 exponent=2");
}
private static DecimalEntry save(CustomUserContext context, Platform platform,
String label, BigDecimal amount) {
DecimalEntry entry = Q.decimalEntries()
.comment("Initialize generated Decimal entry")
.purpose("Record an auditable ledger value")
.newEntity(context);
entry.updatePlatform(platform);
entry.updateLabel(label);
entry.updateAmount(amount);
entry.auditAs("Create exact Decimal entry for generated integration gate").save(context);
return entry;
}
private static BigDecimal sum(CustomUserContext context) {
var rows = Q.decimalEntriesWithMinimalFields().sumAmountAs("total")
.comment("Sum generated exact Decimal entries")
.purpose("Verify financial aggregation without binary floating point")
.aggregation(context).toList();
if (rows.size() != 1 || !(rows.get(0).get("total") instanceof BigDecimal total)) {
throw new AssertionError("generated Decimal aggregate has the wrong shape");
}
return total;
}
private static BigDecimal reloadAmount(CustomUserContext context, Long id) {
var entry = Q.decimalEntriesWithMinimalFields().selectAmount()
.withIdIs(id).limit(1)
.comment("Reload generated exact Decimal value")
.purpose("Verify scale and precision after audited save")
.executeForOne(context);
if (entry == null) throw new AssertionError("generated Decimal entry is missing: " + id);
return E.decimalEntry(entry).getAmount().eval();
}
}