Skip to content

Commit

Permalink
first partially working poc
Browse files Browse the repository at this point in the history
  • Loading branch information
rainbowdashlabs committed May 25, 2024
1 parent 6b62e50 commit 7e60670
Show file tree
Hide file tree
Showing 24 changed files with 560 additions and 59 deletions.
14 changes: 14 additions & 0 deletions sadu-jackson-mapper/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,4 +1,18 @@
dependencies {
api(project(":sadu-mapper"))
api("com.fasterxml.jackson.core", "jackson-databind", "2.17.1")

testImplementation(project(":sadu-queries"))
testImplementation(project(":sadu-postgresql"))
testImplementation(project(":sadu-mariadb"))
testImplementation(project(":sadu-mysql"))
testImplementation(project(":sadu-sqlite"))
testImplementation(project(":sadu-datasource"))
testImplementation(testlibs.bundles.database.postgres)
testImplementation(testlibs.bundles.database.mariadb)
testImplementation(testlibs.bundles.database.mysql)
testImplementation(testlibs.driver.sqlite)
testImplementation(testlibs.slf4j.noop)
testImplementation(testlibs.bundles.junit)
testImplementation(libs.jackson.jsr310)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* SPDX-License-Identifier: LGPL-3.0-or-later
*
* Copyright (C) RainbowDashLabs and Contributor
*/

package de.chojo.sadu.jackson;

import com.fasterxml.jackson.databind.ObjectMapper;
import de.chojo.sadu.core.types.SqlType;
import de.chojo.sadu.jackson.exception.UnknownTypeException;
import de.chojo.sadu.mapper.IRowMapperRegistry;
import de.chojo.sadu.mapper.MapperConfig;
import de.chojo.sadu.mapper.rowmapper.IRowMapper;
import de.chojo.sadu.mapper.wrapper.Row;

import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class JacksonRowMapper<T> implements IRowMapper<T> {
private final Class<T> clazz;
private final ObjectMapper objectMapper;
private final IRowMapperRegistry registry;

public JacksonRowMapper(Class<T> clazz, ObjectMapper objectMapper, IRowMapperRegistry registry) {
this.clazz = clazz;
this.objectMapper = objectMapper;
this.registry = registry;
}

@Override
public T map(Row row) throws SQLException {
ResultSetMetaData meta = row.getMetaData();
Map<String, Object> map = new HashMap<>();
for (int index = 1; index < meta.getColumnCount() + 1; index++) {
// Maybe this works already
//map.put(meta.getColumnName(index), row.getObject(index));
var type = meta.getColumnTypeName(index);
var forType = registry.findForType(type);
var mapper = forType.orElseThrow(() -> new UnknownTypeException(type));
map.put(meta.getColumnName(index), mapper.map(row, index));
}

return objectMapper.convertValue(map, clazz);
}

@Override
public T map(Row row, int index) throws SQLException {
throw new UnsupportedOperationException("A Jackson row Mapper can not map by index.");
}

@Override
public boolean isWildcard() {
return false;
}

@Override
public int applicable(ResultSet resultSet) throws SQLException {
return applicable(resultSet.getMetaData());
}

@Override
public int applicable(ResultSet resultSet, MapperConfig config) throws SQLException {
return applicable(resultSet.getMetaData(), config);
}

@Override
public int applicable(ResultSetMetaData meta) throws SQLException {
return meta.getColumnCount();
}

@Override
public int applicable(ResultSetMetaData meta, MapperConfig config) throws SQLException {
return applicable(meta);
}

@Override
public List<SqlType> types() {
return List.of();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* SPDX-License-Identifier: LGPL-3.0-or-later
*
* Copyright (C) RainbowDashLabs and Contributor
*/

package de.chojo.sadu.jackson;

import com.fasterxml.jackson.databind.ObjectMapper;
import de.chojo.sadu.jackson.exception.UnknownTypeException;
import de.chojo.sadu.mapper.IRowMapperRegistry;
import de.chojo.sadu.mapper.rowmapper.IRowMapper;
import de.chojo.sadu.mapper.rowmapper.RowMapper;
import de.chojo.sadu.mapper.wrapper.Row;

import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

public class JacksonRowMapperFactory {
private final IRowMapperRegistry registry;
private final ObjectMapper objectMapper;
private final Map<Class<?>, IRowMapper<?>> mapper = new HashMap<>();

public JacksonRowMapperFactory(ObjectMapper objectMapper, IRowMapperRegistry registry) {
this.objectMapper = objectMapper;
this.registry = registry;
}

@SuppressWarnings("unchecked")
public <T, V extends IRowMapper<T>> V forClass(Class<T> clazz) {
return (V) mapper.computeIfAbsent(clazz, key -> new JacksonRowMapper<>(key, objectMapper, registry));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* SPDX-License-Identifier: LGPL-3.0-or-later
*
* Copyright (C) RainbowDashLabs and Contributor
*/

package de.chojo.sadu.jackson;

import com.fasterxml.jackson.databind.ObjectMapper;
import de.chojo.sadu.mapper.IRowMapperRegistry;
import de.chojo.sadu.mapper.MapperConfig;
import de.chojo.sadu.mapper.exceptions.MappingException;
import de.chojo.sadu.mapper.rowmapper.IRowMapper;
import de.chojo.sadu.mapper.rowmapper.RowMapper;

import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.List;
import java.util.Optional;

public class JacksonRowMapperRegistry implements IRowMapperRegistry {
private final JacksonRowMapperFactory factory;
private final IRowMapperRegistry registry;

public JacksonRowMapperRegistry(ObjectMapper objectMapper, IRowMapperRegistry registry) {
this.registry = registry;
this.factory = new JacksonRowMapperFactory(objectMapper, registry);
}

@Override
public List<RowMapper<?>> mapper(Class<?> clazz) {
return List.of();
}

@Override
public <T> Optional<IRowMapper<T>> wildcard(Class<T> clazz) {
return Optional.ofNullable(registry.wildcard(clazz).orElseGet(() -> factory.forClass(clazz)));
}

@Override
public <T> Optional<IRowMapper<T>> find(Class<T> clazz, ResultSetMetaData meta, MapperConfig config) {
return wildcard(clazz);
}

@Override
public <T, V extends IRowMapper<T>> V findOrWildcard(Class<T> clazz, ResultSetMetaData meta, MapperConfig config) throws MappingException, SQLException {
return (V) wildcard(clazz).get();
}

@Override
public Optional<IRowMapper<?>> findForType(String name) {
return Optional.empty();
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

import static org.junit.jupiter.api.Assertions.*;

class ResultSetMapperTest {
class JacksonRowMapperFactoryTest {

@Test
void convertRow() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* SPDX-License-Identifier: LGPL-3.0-or-later
*
* Copyright (C) RainbowDashLabs and Contributor
*/

package de.chojo.sadu.jackson;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;

import java.time.Instant;
import java.util.UUID;

public record TestObj(int first, long second, String third, Instant fourth, UUID fifth) {
@JsonCreator
public TestObj(@JsonProperty("first") int first,
@JsonProperty("second") long second,
@JsonProperty("third") String third,
@JsonProperty("fourth") Instant fourth,
@JsonProperty("fifth") UUID fifth) {
this.first = first;
this.second = second;
this.third = third;
this.fourth = fourth;
this.fifth = fifth;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* SPDX-License-Identifier: LGPL-3.0-or-later
*
* Copyright (C) RainbowDashLabs and Contributor
*/

package de.chojo.sadu.jackson.databases;

import de.chojo.sadu.jackson.TestObj;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;

import java.time.Instant;
import java.util.UUID;
import java.util.stream.Stream;

import static de.chojo.sadu.jackson.setup.PostgresDatabase.createContainer;
import static de.chojo.sadu.queries.api.call.Call.call;
import static de.chojo.sadu.queries.api.query.Query.query;
import static de.chojo.sadu.queries.converter.StandardValueConverter.INSTANT_MILLIS;
import static de.chojo.sadu.queries.converter.StandardValueConverter.INSTANT_TIMESTAMP;
import static de.chojo.sadu.queries.converter.StandardValueConverter.UUID_STRING;

public class TestPostgreSQL {
@BeforeEach
void setup() throws Exception {
createContainer();
}

public static Stream<TestObj> objects() {
return Stream.of(
new TestObj(1324, 78644877545455L, "test", Instant.now(), UUID.randomUUID())
);
}

@ParameterizedTest
@MethodSource("objects")
public void testRead(TestObj obj) {
query("INSERT INTO test(first, second, third, fourth, fifth) VALUES (?,?,?,?,?::UUID)")
.single(call().bind(obj.first()).bind(obj.second()).bind(obj.third()).bind(obj.fourth(), INSTANT_TIMESTAMP).bind(obj.fifth(), UUID_STRING))
.insert();

var result = query("SELECT * FROM test")
.single()
.mapAs(TestObj.class)
.first()
.get();

Assertions.assertEquals(obj, result);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* SPDX-License-Identifier: LGPL-3.0-or-later
*
* Copyright (C) RainbowDashLabs and Contributor
*/

package de.chojo.sadu.jackson.setup;

import de.chojo.sadu.datasource.DataSourceCreator;
import de.chojo.sadu.mariadb.databases.MariaDb;
import de.chojo.sadu.postgresql.databases.PostgreSql;
import de.chojo.sadu.updater.SqlUpdater;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.utility.DockerImageName;

import javax.sql.DataSource;
import java.io.IOException;
import java.sql.SQLException;

public class MariaDBDatabase {
public static Database createContainer() throws IOException, SQLException {
GenericContainer<?> self = new GenericContainer<>(DockerImageName.parse("mariadb:latest"))
.withExposedPorts(3306)
.withEnv("MARIADB_ROOT_PASSWORD", "root")
.waitingFor(Wait.forLogMessage(".*mariadbd: ready for connections.*", 2));
self.start();

DataSource dc = DataSourceCreator.create(MariaDb.get())
.configure(c -> c.host(self.getHost()).port(self.getFirstMappedPort())).create()
.usingPassword("root")
.usingUsername("root")
.build();

SqlUpdater.builder(dc, MariaDb.get())
.execute();

return new Database(self, dc);
}

public static record Database(GenericContainer<?> container, DataSource dataSource) {
public void close() {
container.close();
}
}
}
Loading

0 comments on commit 7e60670

Please sign in to comment.