diff --git a/build.gradle b/build.gradle
index f65b98e..f21ef61 100644
--- a/build.gradle
+++ b/build.gradle
@@ -54,7 +54,7 @@ dependencies {
// json/yaml
implementation 'org.json:json:20240303'
implementation 'org.yaml:snakeyaml'
- // databases
+ // databases // todo: remove and add via plugin-system
runtimeOnly 'org.postgresql:postgresql'
runtimeOnly 'org.xerial:sqlite-jdbc'
// testing
diff --git a/src/main/java/org/dynapi/dynapi/core/database/impl/postgresql/PostgreSQLMetaQueryGenerator.java b/src/main/java/org/dynapi/dynapi/core/database/impl/postgresql/PostgreSQLMetaQueryGenerator.java
index 5b12710..04f285b 100644
--- a/src/main/java/org/dynapi/dynapi/core/database/impl/postgresql/PostgreSQLMetaQueryGenerator.java
+++ b/src/main/java/org/dynapi/dynapi/core/database/impl/postgresql/PostgreSQLMetaQueryGenerator.java
@@ -12,10 +12,10 @@ public String listSchemas() {
Table pgNamespace = new Schema("pg_catalog").table("pg_namespace");
Field schemaName = pgNamespace.field("nspname").as("schema_name");
return new PostgreSQLQuery()
- .from(pgNamespace)
- .select(schemaName)
- .where(schemaName.not_like("pg_%"))
- .getSql();
+ .from(pgNamespace)
+ .select(schemaName)
+ .where(schemaName.not_like("pg_%"))
+ .getSql();
}
@Override
diff --git a/src/main/java/org/dynapi/dynapi/core/database/impl/sqlite/SQLiteMetaQueryGenerator.java b/src/main/java/org/dynapi/dynapi/core/database/impl/sqlite/SQLiteMetaQueryGenerator.java
index 37c9654..42e3982 100644
--- a/src/main/java/org/dynapi/dynapi/core/database/impl/sqlite/SQLiteMetaQueryGenerator.java
+++ b/src/main/java/org/dynapi/dynapi/core/database/impl/sqlite/SQLiteMetaQueryGenerator.java
@@ -51,6 +51,7 @@ public String listTablesOfSchema(String schemaName) {
@Override
public String listColumnsOfTable(String schemaName, String tableName) {
+ // todo: $schema.pragme_table_info($tableName)
Selectable tableInfo = new TableValuedFunction("pragma_table_info", tableName);
return new SQLiteQuery()
.from(tableInfo)
diff --git a/src/main/java/org/dynapi/dynapi/core/database/interfaces/Database.java b/src/main/java/org/dynapi/dynapi/core/database/interfaces/Database.java
index 2c42eb7..23b137b 100644
--- a/src/main/java/org/dynapi/dynapi/core/database/interfaces/Database.java
+++ b/src/main/java/org/dynapi/dynapi/core/database/interfaces/Database.java
@@ -13,6 +13,7 @@ public interface Database {
/**
* note: it's recommended to use the getter instead
+ *
* @return a dialect appropriate {@link MetaQueryGenerator} used to fetch table-information
* @see #getSchemaNames()
* @see #getTableNamesOfSchema(String)
@@ -47,7 +48,7 @@ public interface Database {
/**
* @param schemaName schema of the table
- * @param tableName table
+ * @param tableName table
* @return column-information of the table
*/
List getColumnInformationOfTable(@NonNull String schemaName, @NonNull String tableName);
@@ -62,14 +63,14 @@ public interface Database {
/**
* @param schemaName name of the schema of the table
- * @param tableName name of the table
+ * @param tableName name of the table
* @return that the table exists
*/
boolean existsTable(@NonNull String schemaName, @NonNull String tableName);
/**
- * @param schemaName name of the schema of the table
- * @param tableName name of the table
+ * @param schemaName name of the schema of the table
+ * @param tableName name of the table
* @param columnNames columns to verify
* @return that all specified columns exist on the table
*/
@@ -78,8 +79,9 @@ public interface Database {
/**
* Utility-function used to validate that a table has all {@code columns}
* If {@code columns} contains {@code *} then it's directly marked as valid
- * @param schemaName schema-name
- * @param tableName table-name
+ *
+ * @param schemaName schema-name
+ * @param tableName table-name
* @param columnNames columns to check again
* @throws org.springframework.web.server.ResponseStatusException if one or more columns are not existing
*/
diff --git a/src/main/java/org/dynapi/dynapi/core/database/interfaces/MetaQueryGenerator.java b/src/main/java/org/dynapi/dynapi/core/database/interfaces/MetaQueryGenerator.java
index e97916b..e44a498 100644
--- a/src/main/java/org/dynapi/dynapi/core/database/interfaces/MetaQueryGenerator.java
+++ b/src/main/java/org/dynapi/dynapi/core/database/interfaces/MetaQueryGenerator.java
@@ -16,6 +16,7 @@ public interface MetaQueryGenerator {
/**
* returns an SQL-Query that returns the available tables of a specific schema
* format: {@code {'schema_name', 'table_name'}}
+ *
* @param schemaName database schema
*/
String listTablesOfSchema(String schemaName);
@@ -23,8 +24,9 @@ public interface MetaQueryGenerator {
/**
* returns an SQL-Query that returns the column-information of a specific table of a specific schema
* format: {@code {'column_name', 'type'}}
+ *
* @param schemaName database schema
- * @param tableName table of {@code schemaName}
+ * @param tableName table of {@code schemaName}
*/
String listColumnsOfTable(String schemaName, String tableName);
}
diff --git a/src/main/java/org/dynapi/dynapi/core/datatypes/DataType.java b/src/main/java/org/dynapi/dynapi/core/datatypes/DataType.java
new file mode 100644
index 0000000..4da88af
--- /dev/null
+++ b/src/main/java/org/dynapi/dynapi/core/datatypes/DataType.java
@@ -0,0 +1,23 @@
+package org.dynapi.dynapi.core.datatypes;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import org.dynapi.openapispec.core.schema.Schema;
+
+public interface DataType {
+ /**
+ * @return schema for /openapi
+ */
+ Schema, ?> getOpenApiSchema();
+
+ /**
+ * @param node node to parse
+ * @return parsed value
+ */
+ Object parseJsonNode(JsonNode node);
+
+ /**
+ * @param object saved or so object
+ * @return json-save object
+ */
+ Object formatObject(Object object);
+}
diff --git a/src/main/java/org/dynapi/dynapi/core/datatypes/impl/DataTypeArray.java b/src/main/java/org/dynapi/dynapi/core/datatypes/impl/DataTypeArray.java
new file mode 100644
index 0000000..5778913
--- /dev/null
+++ b/src/main/java/org/dynapi/dynapi/core/datatypes/impl/DataTypeArray.java
@@ -0,0 +1,52 @@
+package org.dynapi.dynapi.core.datatypes.impl;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import org.dynapi.dynapi.core.datatypes.DataType;
+import org.dynapi.openapispec.core.schema.Schema;
+import org.dynapi.openapispec.core.schema.TArray;
+
+public class DataTypeArray implements DataType {
+ private final DataType subType;
+
+ public DataTypeArray(DataType subType) {
+ this.subType = subType;
+ }
+
+ /**
+ * @return schema for /openapi
+ */
+ @Override
+ public Schema, ?> getOpenApiSchema() {
+ return new TArray(subType.getOpenApiSchema());
+ }
+
+ /**
+ * @param node node to parse
+ * @return parsed value
+ */
+ @Override
+ public Object[] parseJsonNode(JsonNode node) {
+ assert node.isArray();
+ Object[] array = new Object[node.size()];
+ for (int i = 0; i < node.size(); i++) {
+ JsonNode element = node.get(i);
+ array[i] = subType.parseJsonNode(element);
+ }
+ return array;
+ }
+
+ /**
+ * @param object saved or so object
+ * @return json-save object
+ */
+ @Override
+ public Object formatObject(Object object) {
+ if (object instanceof Object[] a) {
+ Object[] array = new Object[a.length];
+ for (int i = 0; i < a.length; i++)
+ array[i] = subType.formatObject(a[i]);
+ return array;
+ }
+ throw new IllegalArgumentException("Object is not an array");
+ }
+}
diff --git a/src/main/java/org/dynapi/dynapi/core/datatypes/impl/DataTypeBlob.java b/src/main/java/org/dynapi/dynapi/core/datatypes/impl/DataTypeBlob.java
new file mode 100644
index 0000000..63fa133
--- /dev/null
+++ b/src/main/java/org/dynapi/dynapi/core/datatypes/impl/DataTypeBlob.java
@@ -0,0 +1,41 @@
+package org.dynapi.dynapi.core.datatypes.impl;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import org.dynapi.dynapi.core.datatypes.DataType;
+import org.dynapi.openapispec.core.schema.Schema;
+import org.dynapi.openapispec.core.schema.TString;
+
+import java.util.Base64;
+
+public class DataTypeBlob implements DataType {
+ /**
+ * @return schema for /openapi
+ */
+ @Override
+ public Schema, ?> getOpenApiSchema() {
+ return new TString()
+ .format(TString.CommonFormats.BINARY);
+ }
+
+ /**
+ * @param node node to parse
+ * @return parsed value
+ */
+ @Override
+ public byte[] parseJsonNode(JsonNode node) {
+ assert node.isTextual();
+ String base64String = node.textValue();
+ return Base64.getDecoder().decode(base64String);
+ }
+
+ /**
+ * @param object saved or so object
+ * @return json-save object
+ */
+ @Override
+ public Object formatObject(Object object) {
+ if (object instanceof byte[] b)
+ return Base64.getEncoder().encodeToString(b);
+ throw new IllegalArgumentException("Object is not a blob");
+ }
+}
diff --git a/src/main/java/org/dynapi/dynapi/core/datatypes/impl/DataTypeBoolean.java b/src/main/java/org/dynapi/dynapi/core/datatypes/impl/DataTypeBoolean.java
new file mode 100644
index 0000000..4615683
--- /dev/null
+++ b/src/main/java/org/dynapi/dynapi/core/datatypes/impl/DataTypeBoolean.java
@@ -0,0 +1,37 @@
+package org.dynapi.dynapi.core.datatypes.impl;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import org.dynapi.dynapi.core.datatypes.DataType;
+import org.dynapi.openapispec.core.schema.Schema;
+import org.dynapi.openapispec.core.schema.TBoolean;
+
+public class DataTypeBoolean implements DataType {
+ /**
+ * @return schema for /openapi
+ */
+ @Override
+ public Schema, ?> getOpenApiSchema() {
+ return new TBoolean();
+ }
+
+ /**
+ * @param node node to parse
+ * @return parsed value
+ */
+ @Override
+ public Object parseJsonNode(JsonNode node) {
+ assert node.isBoolean();
+ return node.booleanValue();
+ }
+
+ /**
+ * @param object saved or so object
+ * @return json-save object
+ */
+ @Override
+ public Object formatObject(Object object) {
+ if (object instanceof Boolean b)
+ return b;
+ throw new IllegalArgumentException("Object is not a boolean");
+ }
+}
diff --git a/src/main/java/org/dynapi/dynapi/core/datatypes/impl/DataTypeDate.java b/src/main/java/org/dynapi/dynapi/core/datatypes/impl/DataTypeDate.java
new file mode 100644
index 0000000..90e4a0a
--- /dev/null
+++ b/src/main/java/org/dynapi/dynapi/core/datatypes/impl/DataTypeDate.java
@@ -0,0 +1,46 @@
+package org.dynapi.dynapi.core.datatypes.impl;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import org.dynapi.dynapi.core.datatypes.DataType;
+import org.dynapi.openapispec.core.schema.Schema;
+import org.dynapi.openapispec.core.schema.TString;
+
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.TemporalAccessor;
+
+public class DataTypeDate implements DataType {
+ private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ISO_LOCAL_DATE;
+
+ /**
+ * @return schema for /openapi
+ */
+ @Override
+ public Schema, ?> getOpenApiSchema() {
+ return new TString()
+ .format(TString.CommonFormats.DATE);
+ }
+
+ /**
+ * @param node node to parse
+ * @return parsed value
+ */
+ @Override
+ public LocalDate parseJsonNode(JsonNode node) {
+ assert node.isTextual();
+ return LocalDate.parse(node.textValue(), DATE_FORMATTER);
+ }
+
+ /**
+ * @param object saved or so object
+ * @return json-save object
+ */
+ @Override
+ public String formatObject(Object object) {
+ if (object instanceof LocalDateTime || object instanceof LocalDate || object instanceof Instant)
+ return DATE_FORMATTER.format((TemporalAccessor) object);
+ throw new IllegalArgumentException("Object is not a date");
+ }
+}
diff --git a/src/main/java/org/dynapi/dynapi/core/datatypes/impl/DataTypeDateTime.java b/src/main/java/org/dynapi/dynapi/core/datatypes/impl/DataTypeDateTime.java
new file mode 100644
index 0000000..9d05dde
--- /dev/null
+++ b/src/main/java/org/dynapi/dynapi/core/datatypes/impl/DataTypeDateTime.java
@@ -0,0 +1,46 @@
+package org.dynapi.dynapi.core.datatypes.impl;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import org.dynapi.dynapi.core.datatypes.DataType;
+import org.dynapi.openapispec.core.schema.Schema;
+import org.dynapi.openapispec.core.schema.TString;
+
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.TemporalAccessor;
+
+public class DataTypeDateTime implements DataType {
+ private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
+
+ /**
+ * @return schema for /openapi
+ */
+ @Override
+ public Schema, ?> getOpenApiSchema() {
+ return new TString()
+ .format(TString.CommonFormats.DATETIME);
+ }
+
+ /**
+ * @param node node to parse
+ * @return parsed value
+ */
+ @Override
+ public LocalDateTime parseJsonNode(JsonNode node) {
+ assert node.isTextual();
+ return LocalDateTime.parse(node.textValue(), DATE_FORMATTER);
+ }
+
+ /**
+ * @param object saved or so object
+ * @return json-save object
+ */
+ @Override
+ public String formatObject(Object object) {
+ if (object instanceof LocalDateTime || object instanceof LocalDate || object instanceof Instant)
+ return DATE_FORMATTER.format((TemporalAccessor) object);
+ throw new IllegalArgumentException("Object is not a date");
+ }
+}
diff --git a/src/main/java/org/dynapi/dynapi/core/datatypes/impl/DataTypeDecimal.java b/src/main/java/org/dynapi/dynapi/core/datatypes/impl/DataTypeDecimal.java
new file mode 100644
index 0000000..ebad9f6
--- /dev/null
+++ b/src/main/java/org/dynapi/dynapi/core/datatypes/impl/DataTypeDecimal.java
@@ -0,0 +1,39 @@
+package org.dynapi.dynapi.core.datatypes.impl;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import org.dynapi.dynapi.core.datatypes.DataType;
+import org.dynapi.openapispec.core.schema.Schema;
+import org.dynapi.openapispec.core.schema.TNumber;
+
+public class DataTypeDecimal implements DataType {
+ /**
+ * @return schema for /openapi
+ */
+ @Override
+ public Schema, ?> getOpenApiSchema() {
+ return new TNumber();
+ }
+
+ /**
+ * @param node node to parse
+ * @return parsed value
+ */
+ @Override
+ public Number parseJsonNode(JsonNode node) {
+ assert node.isFloatingPointNumber();
+ return node.isDouble() ? node.doubleValue() : node.floatValue();
+ }
+
+ /**
+ * @param object saved or so object
+ * @return json-save object
+ */
+ @Override
+ public Object formatObject(Object object) {
+ if (object instanceof Double d)
+ return d;
+ if (object instanceof Float f)
+ return f;
+ throw new IllegalArgumentException("Object is not a decimal");
+ }
+}
diff --git a/src/main/java/org/dynapi/dynapi/core/datatypes/impl/DataTypeInteger.java b/src/main/java/org/dynapi/dynapi/core/datatypes/impl/DataTypeInteger.java
new file mode 100644
index 0000000..59c897b
--- /dev/null
+++ b/src/main/java/org/dynapi/dynapi/core/datatypes/impl/DataTypeInteger.java
@@ -0,0 +1,39 @@
+package org.dynapi.dynapi.core.datatypes.impl;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import org.dynapi.dynapi.core.datatypes.DataType;
+import org.dynapi.openapispec.core.schema.Schema;
+import org.dynapi.openapispec.core.schema.TInteger;
+
+public class DataTypeInteger implements DataType {
+ /**
+ * @return schema for /openapi
+ */
+ @Override
+ public Schema, ?> getOpenApiSchema() {
+ return new TInteger();
+ }
+
+ /**
+ * @param node node to parse
+ * @return parsed value
+ */
+ @Override
+ public Number parseJsonNode(JsonNode node) {
+ assert node.isIntegralNumber();
+ return node.isLong() ? node.longValue() : node.intValue();
+ }
+
+ /**
+ * @param object saved or so object
+ * @return json-save object
+ */
+ @Override
+ public Object formatObject(Object object) {
+ if (object instanceof Long l)
+ return l;
+ if (object instanceof Integer i)
+ return i;
+ throw new IllegalArgumentException("Object is not an integer");
+ }
+}
diff --git a/src/main/java/org/dynapi/dynapi/core/datatypes/impl/DataTypeJson.java b/src/main/java/org/dynapi/dynapi/core/datatypes/impl/DataTypeJson.java
new file mode 100644
index 0000000..38966b7
--- /dev/null
+++ b/src/main/java/org/dynapi/dynapi/core/datatypes/impl/DataTypeJson.java
@@ -0,0 +1,36 @@
+package org.dynapi.dynapi.core.datatypes.impl;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import org.dynapi.dynapi.core.datatypes.DataType;
+import org.dynapi.openapispec.core.schema.Schema;
+import org.dynapi.openapispec.core.schema.TObject;
+
+public class DataTypeJson implements DataType {
+ /**
+ * @return schema for /openapi
+ */
+ @Override
+ public Schema, ?> getOpenApiSchema() {
+ return new TObject();
+ }
+
+ /**
+ * @param node node to parse
+ * @return parsed value
+ */
+ @Override
+ public JsonNode parseJsonNode(JsonNode node) {
+ return node;
+ }
+
+ /**
+ * @param object saved or so object
+ * @return json-save object
+ */
+ @Override
+ public JsonNode formatObject(Object object) {
+ if (object instanceof JsonNode j)
+ return j;
+ throw new IllegalArgumentException("Object is not a JSON object");
+ }
+}
diff --git a/src/main/java/org/dynapi/dynapi/core/datatypes/impl/DataTypeString.java b/src/main/java/org/dynapi/dynapi/core/datatypes/impl/DataTypeString.java
new file mode 100644
index 0000000..1bbd6bb
--- /dev/null
+++ b/src/main/java/org/dynapi/dynapi/core/datatypes/impl/DataTypeString.java
@@ -0,0 +1,37 @@
+package org.dynapi.dynapi.core.datatypes.impl;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import org.dynapi.dynapi.core.datatypes.DataType;
+import org.dynapi.openapispec.core.schema.Schema;
+import org.dynapi.openapispec.core.schema.TString;
+
+public class DataTypeString implements DataType {
+ /**
+ * @return schema for /openapi
+ */
+ @Override
+ public Schema, ?> getOpenApiSchema() {
+ return new TString();
+ }
+
+ /**
+ * @param node node to parse
+ * @return parsed value
+ */
+ @Override
+ public String parseJsonNode(JsonNode node) {
+ assert node.isTextual();
+ return node.textValue();
+ }
+
+ /**
+ * @param object saved or so object
+ * @return json-save object
+ */
+ @Override
+ public String formatObject(Object object) {
+ if (object instanceof String s)
+ return s;
+ throw new IllegalArgumentException("Object is not a string");
+ }
+}
diff --git a/src/main/java/org/dynapi/dynapi/core/datatypes/impl/DataTypeUUID.java b/src/main/java/org/dynapi/dynapi/core/datatypes/impl/DataTypeUUID.java
new file mode 100644
index 0000000..ccee057
--- /dev/null
+++ b/src/main/java/org/dynapi/dynapi/core/datatypes/impl/DataTypeUUID.java
@@ -0,0 +1,41 @@
+package org.dynapi.dynapi.core.datatypes.impl;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import org.dynapi.dynapi.core.datatypes.DataType;
+import org.dynapi.openapispec.core.schema.Schema;
+import org.dynapi.openapispec.core.schema.TString;
+
+import java.util.UUID;
+
+public class DataTypeUUID implements DataType {
+ /**
+ * @return schema for /openapi
+ */
+ @Override
+ public Schema, ?> getOpenApiSchema() {
+ return new TString()
+ .format(TString.CommonFormats.UUID);
+ }
+
+ /**
+ * @param node node to parse
+ * @return parsed value
+ */
+ @Override
+ public Object parseJsonNode(JsonNode node) {
+ assert node.isTextual();
+ String uuidString = node.asText();
+ return UUID.fromString(uuidString);
+ }
+
+ /**
+ * @param object saved or so object
+ * @return json-save object
+ */
+ @Override
+ public String formatObject(Object object) {
+ if (object instanceof UUID u)
+ return u.toString();
+ throw new IllegalArgumentException("Object is not a UUID");
+ }
+}