jhannes / fluent-jdbc Goto Github PK
View Code? Open in Web Editor NEWJava database code without ORM in a pleasant and fluent style
License: Apache License 2.0
Java database code without ORM in a pleasant and fluent style
License: Apache License 2.0
Given this code:
public boolean foo(int projectId) {
return table
.where("project_id", projectId)
.whereExpression("entry_id is not null or entry_comment_id is not null")
.getCount() > 0;
}
The or
in the whereExpression
can match rows with a different project_id
than the one given as an argument.
I was expecting the whereExpression
to get wrapped in parenthesis and not interfere with the call to where
.
Thoughts?
Add @CheckReturnValue
annotations to all methods that should have it to help users get relevant warnings in their IDE
It would be nice to have support for standard statement "FETCH FIRST x ROWS ONLY":
according to SQL:2008. That would make the statement below easier to both read and write:
I tried to use this library with micronaut, however, after adding the dependency, project doesn't start due to slf4j-api incompatibility.
"Class path contains SLF4J bindings targeting slf4j-api versions prior to 1.8 "
I've tried to exclude slf4j-api from with gradle exclude, but without any success.
Currently only Long is supported:
Often in the face of a combinatory key, I would like the ability to do the following
table a col b_x, b_y
table b col x, y
JOIN a on a.b_x = b.x and a.b_y = b.y
This applies to both inner join and possible future left/right joins
A lot of situastions requires you to get a result with an optional hit in another table
Motivating example
table.syncBuilder(collection)
.unique("keyOne", it -> it.getKeyOne())
.unique("keyTwo", it -> it.getKeyTwo())
.field("value1", it -> it.getValueOne())
.field("value2", it -> it.getValueTwo())
.cacheExisting()
.deleteExtras()
.insertMissing()
.updateDiffering()
.execute();
It's useful to be able to add parameters using named fields instead of "?" markers. This reduces confusion around what goes where, better supports duplicated references to same parameter, and avoids having to track posistions or generate lists of "?" for IN clauses etc.
E.g.
return new DbStatement("Select a.* from MyTable a where a.someField=:someField and a.status IN (:status)")
.setField("name", "some value")
.setField("status", List.of("status1", "status2", "status3")
.executeQuery();
Sample code:
`
package org.fluentjdbc;
import java.util.;
import java.util.regex.;
import java.util.stream.*;
public class DbStatement {
static class Field {
String name;
int start;
int end;
Field(String name, int start, int end) {
this.name = name;
this.start = start;
this.end = end;
}
@Override
public String toString() {
return getClass().getSimpleName() + "<" + name + "," + start + "," + end + ">";
}
}
private static final Pattern FIELD_REGEXP = Pattern.compile("(?:'[^']+')|:([a-zA-Z0-9_]+)");
private final String statement;
/** order of fields in statement. */
private final List<Field> fieldOrder = new ArrayList<>();
private final Map<String, List<?>> fieldParams = new LinkedHashMap<>();
public DbStatement(String stmt) {
this.statement = Objects.requireNonNull(stmt);
Matcher m = FIELD_REGEXP.matcher(stmt);
while (m.find()) {
if (m.group(1) != null) {
fieldOrder.add(new Field(m.group(1), m.start(), m.end()));
}
}
}
void executeQuery() {
Set<String> fields = fieldOrder.stream().map(f -> f.name).collect(Collectors.toSet());
if (!fieldParams.keySet().equals(fields)) {
throw new IllegalStateException("Forventet : " + fields + ", men har " + fieldParams.keySet());
}
StringBuilder sql = new StringBuilder();
int last = 0;
for (Field f : fieldOrder) {
sql.append(statement.subSequence(last, f.start));
String[] args = new String[fieldParams.get(f.name).size()];
Arrays.fill(args, "?");
String qs = String.join(",", Arrays.asList(args));
sql = sql.append(qs);
last = f.end;
}
sql.append(statement.substring(last));
int i = 1;
for (Field f : fieldOrder) {
for (Object v : fieldParams.get(f.name)) {
// TODO: populate statement
System.out.println(i++ + ": " + f.name + " =" + v);
}
}
// TODO: execute
System.out.println(sql);
}
public void setField(String fieldName, Object val) {
this.fieldParams.put(fieldName, List.of(val));
}
public void setField(String fieldName, List<Object> vals) {
fieldParams.put(fieldName, vals);
}
List<Field> getFieldOrder() {
return Collections.unmodifiableList(fieldOrder);
}
Map<String, List<?>> getFieldParams() {
return Collections.unmodifiableMap(fieldParams);
}
}
class TestDbStatement {
public static void main(String[] args) {
DbStatement stmt = new DbStatement(
"select * from hello where id=:myField1 and name=':notincluded' and id2 IN(:myField_2) and id3= :myField1");
System.out.println(stmt.getFieldOrder());
stmt.setField("myField1", 999);
stmt.setField("myField_2", List.of("A", "B", "C"));
stmt.executeQuery();
}
}
`
I see that Oracle currently is not supported: https://github.com/jhannes/fluent-jdbc/tree/master/src/test/java/org/fluentjdbc
https://github.com/jhannes/fluent-jdbc/blob/main/src/main/java/org/fluentjdbc/opt/junit/DbContextRule.java needs to be converted to something like this:
public class DbContextExtension extends DbContext
implements BeforeEachCallback, AfterEachCallback {
val DbContextConnection ignoredConnection
// Constructors is bad most likley, need to check how to provide constructor argument to an Extension class.
// Maybe allow to set datasource and databaseStatementFactory via setters in a @BeforeClass/@Before when using the extension?
public DbContextExtension(DataSource dataSource) {
this(dataSource, new DatabaseStatementFactory(DatabaseReporter.LOGGING_REPORTER));
}
public DbContextExtension(DataSource dataSource, DatabaseStatementFactory factory) {
super(factory);
this.dataSource = dataSource;
}
@Override
public void beforeEach(ExtensionContext context) throws Exception {
ignoredConnection = startConnection(dataSource)
}
@Override
public void afterEach(ExtensionContext context) throws Exception {
if (ignoredConnection != null) ignoredConnection.close()
}
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.