initial commit

This commit is contained in:
2025-07-13 01:46:42 +02:00
commit 867e5e2097
17 changed files with 553 additions and 0 deletions

38
.gitignore vendored Normal file
View File

@@ -0,0 +1,38 @@
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### IntelliJ IDEA ###
.idea/modules.xml
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
*.iws
*.iml
*.ipr
### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/
### Mac OS ###
.DS_Store

10
.idea/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,10 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Environment-dependent path to Maven home directory
/mavenHomeManager.xml
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

9
.idea/dictionaries/project.xml generated Normal file
View File

@@ -0,0 +1,9 @@
<component name="ProjectDictionaryState">
<dictionary name="project">
<words>
<w>nitrix</w>
<w>oxedos</w>
<w>yubilee</w>
</words>
</dictionary>
</component>

7
.idea/encodings.xml generated Normal file
View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
</component>
</project>

14
.idea/misc.xml generated Normal file
View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/pom.xml" />
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="corretto-24" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

17
pom.xml Normal file
View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>de.cccwi</groupId>
<artifactId>chaosdb</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>24</maven.compiler.source>
<maven.compiler.target>24</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>

View File

@@ -0,0 +1,19 @@
package de.cccwi;
public record Attribute(String name, Class<?> type) {
public Attribute rho(String newName) {
return new Attribute(newName, type);
}
@Override
public boolean equals(Object o) {
return o instanceof Attribute other && name.equals(other.name);
}
@Override
public int hashCode() {
return name.hashCode();
}
}

View File

@@ -0,0 +1,15 @@
package de.cccwi;
import java.util.Map;
public class Database {
private Map<String, Relation> tables;
public Database(Map<String, Relation> tables) {
this.tables = tables;
}
public Relation executeQuery(String query) {
return null;
}
}

View File

@@ -0,0 +1,79 @@
package de.cccwi;
import de.cccwi.conditions.AttributeEquals;
import de.cccwi.conditions.GreaterThan;
import de.cccwi.conditions.ValueEquals;
import java.util.List;
import java.util.UUID;
public class Main {
public static void main(String[] args) {
var idColumn = new Attribute("id", String.class);
var nameColumn = new Attribute("name", String.class);
var ageColumn = new Attribute("age", Integer.class);
var enabledColumn = new Attribute("enabled", Boolean.class);
var userTable = new Relation(
"Users",
List.of(idColumn, nameColumn, ageColumn, enabledColumn),
List.of(
List.of(UUID.randomUUID().toString(), "nitrix", 31, true),
List.of(UUID.randomUUID().toString(), "oxedos", 27, true),
List.of(UUID.randomUUID().toString(), "yubilee", 30, false)
)
);
System.out.println("Users");
System.out.println(userTable);
var userIdColumn = new Attribute("userId", String.class);
var typeColumn = new Attribute("type", String.class);
var descriptionColumn = new Attribute("description", String.class);
var eventTable = new Relation(
"Events",
List.of(idColumn, userIdColumn, typeColumn, descriptionColumn),
List.of(
List.of(UUID.randomUUID(), userTable.tuples().getFirst().getFirst(), "login", "user logged in"),
List.of(UUID.randomUUID(), userTable.tuples().getFirst().getFirst(), "logout", "user logged out")
)
);
System.out.println("Events");
System.out.println(eventTable);
System.out.println("SELECT name, id, age AS howOld FROM Users WHERE age > 30");
var resultTable = userTable
.sigma(new GreaterThan(ageColumn, 30))
.pi(List.of(nameColumn, idColumn, ageColumn))
.rho(ageColumn.name(), "howOld");
System.out.println(resultTable);
System.out.println("SELECT name AS enabledUsers FROM Users WHERE NOT enabled");
resultTable = userTable
.sigma(new ValueEquals(enabledColumn, false))
.pi(List.of(nameColumn))
.rho(nameColumn.name(), "enabledUsers");
System.out.println(resultTable);
System.out.println("SELECT * FROM Users u1 JOIN Users u2 ON u1.id = u2.id");
var u1 = userTable.rho("u1");
var u2 = userTable.rho("u2");
resultTable = u1.join(u2, new AttributeEquals(idColumn.rho("u1.id"), idColumn.rho("u2.id")));
System.out.println(resultTable);
System.out.println("SELECT * FROM Users u JOIN Events e ON u.id = e.userId");
resultTable = userTable.rho("u")
.join(eventTable.rho("e"), new AttributeEquals(idColumn.rho("u.id"), userIdColumn));
System.out.println(resultTable);
System.out.println("SELECT * FROM Users UNION Users");
resultTable = userTable.union(userTable);
System.out.println(resultTable);
System.out.println("SELECT * FROM Users UNION ALL Users");
resultTable = userTable.unionAll(userTable);
System.out.println(resultTable);
System.out.println("SELECT * FROM Users - Users");
resultTable = userTable.difference(userTable);
System.out.println(resultTable);
}
}

View File

@@ -0,0 +1,190 @@
package de.cccwi;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public record Relation(
String name,
List<Attribute> attributes,
List<List<Object>> tuples
) {
public Relation sigma(BiFunction<List<Attribute>, List<Object>, Boolean> condition) {
return new Relation(
name,
List.copyOf(attributes),
List.copyOf(tuples.stream().filter(t -> condition.apply(attributes, t)).toList())
);
}
public Relation pi(List<Attribute> newAttributes) {
// find out the required indices in the correct order
var indices = newAttributes.stream()
.map(attributes::indexOf)
.toList();
// filter and reorder the attributes of each row
var resultTuples = tuples.stream()
.map(t -> indices.stream().map(t::get).toList())
.toList();
return new Relation(
name,
List.copyOf(newAttributes),
List.copyOf(resultTuples)
);
}
public Relation rho(String newRelationName) {
return new Relation(newRelationName, List.copyOf(attributes), List.copyOf(tuples));
}
public Relation rho(String oldAttributeName, String newAttributeName) {
return new Relation(
name,
List.copyOf(attributes.stream()
.map(a -> a.name().equals(oldAttributeName) ? a.rho(newAttributeName) : a)
.toList()),
List.copyOf(tuples)
);
}
public Relation cross(Relation other) {
assert !this.name.equals(other.name);
var resultTuples = new ArrayList<List<Object>>();
for (var thisTuple : this.tuples) {
for (var otherTuple : other.tuples) {
resultTuples.add(Stream.concat(thisTuple.stream(), otherTuple.stream()).toList());
}
}
return new Relation(
"%sX%s".formatted(name, other.name),
List.copyOf(mergeAttributes(other)),
List.copyOf(resultTuples)
);
}
public Relation union(Relation other) {
assert attributes.size() == other.attributes.size();
for (int i = 0; i < attributes.size(); i++) {
assert attributes.get(i).equals(other.attributes.get(i));
}
return new Relation(
"%sU%s".formatted(name, other.name),
List.copyOf(attributes),
List.copyOf(Stream.concat(tuples.stream(), other.tuples.stream()).distinct().toList())
);
}
public Relation unionAll(Relation other) {
assert attributes.size() == other.attributes.size();
for (int i = 0; i < attributes.size(); i++) {
assert attributes.get(i).equals(other.attributes.get(i));
}
return new Relation(
"%sU%s".formatted(name, other.name),
List.copyOf(attributes),
List.copyOf(Stream.concat(tuples.stream(), other.tuples.stream()).toList())
);
}
public Relation difference(Relation other) {
assert attributes.size() == other.attributes.size();
for (int i = 0; i < attributes.size(); i++) {
assert attributes.get(i).equals(other.attributes.get(i));
}
return new Relation(
"%s-%s".formatted(name, other.name),
List.copyOf(attributes),
List.copyOf(tuples.stream()
.filter(t -> other.tuples().stream().noneMatch(tt -> tt.equals(t)))
.toList())
);
}
public Relation join(Relation other, BiFunction<List<Attribute>, List<Object>, Boolean> condition) {
return cross(other).sigma(condition);
}
@Override
public String toString() {
int colCount = attributes.size();
var columnWidths = new ArrayList<Integer>();
for (int col = 0; col < colCount; col++) {
int maxWidth = attributes.get(col).name().length();
for (var row : tuples) {
String cell = String.valueOf(row.get(col));
maxWidth = Math.max(maxWidth, cell.length());
}
columnWidths.add(maxWidth);
}
Function<List<Object>, String> formatRow = row -> {
StringBuilder line = new StringBuilder();
for (int col = 0; col < colCount; col++) {
String cell = String.valueOf(row.get(col));
line.append(String.format(" %-" + columnWidths.get(col) + "s ", cell));
if (col < colCount - 1) line.append("|");
}
return line.toString();
};
// Header
var sb = new StringBuilder();
sb.append(formatRow.apply(attributes.stream().map(Attribute::name).map(a -> (Object) a).toList()));
sb.append(System.lineSeparator());
// Trenner
for (int col = 0; col < colCount; col++) {
sb.append("".repeat(columnWidths.get(col) + 2));
if (col < colCount - 1) sb.append("");
}
sb.append(System.lineSeparator());
// Daten
for (var row : tuples) {
sb.append(formatRow.apply(row));
sb.append(System.lineSeparator());
}
return sb.toString();
}
private List<Attribute> mergeAttributes(Relation other) {
var thisAttributeName = this.attributes.stream()
.map(Attribute::name)
.collect(Collectors.toSet());
var otherAttributeNames = other.attributes.stream()
.map(Attribute::name)
.collect(Collectors.toSet());
var resultAttributes = new ArrayList<Attribute>();
for (var thisAttribute : this.attributes) {
if (otherAttributeNames.contains(thisAttribute.name())) {
resultAttributes.add(thisAttribute.rho("%s.%s".formatted(this.name, thisAttribute.name())));
} else {
resultAttributes.add(thisAttribute);
}
}
for (var otherAttribute : other.attributes) {
if (thisAttributeName.contains(otherAttribute.name())) {
resultAttributes.add(otherAttribute.rho("%s.%s".formatted(other.name, otherAttribute.name())));
} else {
resultAttributes.add(otherAttribute);
}
}
return resultAttributes;
}
}

View File

@@ -0,0 +1,22 @@
package de.cccwi.conditions;
import de.cccwi.Attribute;
import java.util.List;
import java.util.function.BiFunction;
public class AttributeEquals implements BiFunction<List<Attribute>, List<Object>, Boolean> {
private final Attribute lhs;
private final Attribute rhs;
public AttributeEquals(Attribute lhs, Attribute rhs) {
assert lhs.type().equals(rhs.type());
this.lhs = lhs;
this.rhs = rhs;
}
@Override
public Boolean apply(List<Attribute> attributes, List<Object> rows) {
return rows.get(attributes.indexOf(lhs)).equals(rows.get(attributes.indexOf(rhs)));
}
}

View File

@@ -0,0 +1,23 @@
package de.cccwi.conditions;
import de.cccwi.Attribute;
import java.util.List;
import java.util.function.BiFunction;
public class GreaterThan implements BiFunction<List<Attribute>, List<Object>, Boolean> {
private final Attribute attribute;
private final Integer value;
public GreaterThan(Attribute attribute, Integer value) {
this.attribute = attribute;
this.value = value;
}
@Override
public Boolean apply(List<Attribute> attributes, List<Object> rows) {
var columnIndex = attributes.indexOf(attribute);
assert attributes.get(columnIndex).type().equals(Integer.class);
return ((Integer) rows.get(columnIndex)) > value;
}
}

View File

@@ -0,0 +1,23 @@
package de.cccwi.conditions;
import de.cccwi.Attribute;
import java.util.List;
import java.util.function.BiFunction;
public class GreaterThanEquals implements BiFunction<List<Attribute>, List<Object>, Boolean> {
private final Attribute attribute;
private final Integer value;
public GreaterThanEquals(Attribute attribute, Integer value) {
this.attribute = attribute;
this.value = value;
}
@Override
public Boolean apply(List<Attribute> attributes, List<Object> rows) {
var columnIndex = attributes.indexOf(attribute);
assert attributes.get(columnIndex).type().equals(Integer.class);
return ((Integer) rows.get(columnIndex)) >= value;
}
}

View File

@@ -0,0 +1,23 @@
package de.cccwi.conditions;
import de.cccwi.Attribute;
import java.util.List;
import java.util.function.BiFunction;
public class LessThan implements BiFunction<List<Attribute>, List<Object>, Boolean> {
private final Attribute attribute;
private final Integer value;
public LessThan(Attribute attribute, Integer value) {
this.attribute = attribute;
this.value = value;
}
@Override
public Boolean apply(List<Attribute> attributes, List<Object> rows) {
var columnIndex = attributes.indexOf(attribute);
assert attributes.get(columnIndex).type().equals(Integer.class);
return ((Integer) rows.get(columnIndex)) < value;
}
}

View File

@@ -0,0 +1,23 @@
package de.cccwi.conditions;
import de.cccwi.Attribute;
import java.util.List;
import java.util.function.BiFunction;
public class LessThanEquals implements BiFunction<List<Attribute>, List<Object>, Boolean> {
private final Attribute attribute;
private final Integer value;
public LessThanEquals(Attribute attribute, Integer value) {
this.attribute = attribute;
this.value = value;
}
@Override
public Boolean apply(List<Attribute> attributes, List<Object> rows) {
var columnIndex = attributes.indexOf(attribute);
assert attributes.get(columnIndex).type().equals(Integer.class);
return ((Integer) rows.get(columnIndex)) <= value;
}
}

View File

@@ -0,0 +1,19 @@
package de.cccwi.conditions;
import de.cccwi.Attribute;
import java.util.List;
import java.util.function.BiFunction;
public class Not implements BiFunction<List<Attribute>, List<Object>, Boolean> {
private BiFunction<List<Attribute>, List<Object>, Boolean> condition;
public Not(BiFunction<List<Attribute>, List<Object>, Boolean> condition) {
this.condition = condition;
}
@Override
public Boolean apply(List<Attribute> attributes, List<Object> objects) {
return !condition.apply(attributes, objects);
}
}

View File

@@ -0,0 +1,22 @@
package de.cccwi.conditions;
import de.cccwi.Attribute;
import java.util.List;
import java.util.function.BiFunction;
public class ValueEquals implements BiFunction<List<Attribute>, List<Object>, Boolean> {
private final Attribute lhs;
private final Object rhs;
public ValueEquals(Attribute lhs, Object rhs) {
assert lhs.type().isInstance(rhs);
this.lhs = lhs;
this.rhs = rhs;
}
@Override
public Boolean apply(List<Attribute> attributes, List<Object> rows) {
return rows.get(attributes.indexOf(lhs)).equals(rhs);
}
}