Skip to content

Commit

Permalink
Merge branch 'release-4.1.1' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
usfalami committed Aug 27, 2024
2 parents 6a9d65e + 60c8499 commit 625a503
Show file tree
Hide file tree
Showing 26 changed files with 255 additions and 312 deletions.
2 changes: 1 addition & 1 deletion src/main/java/org/usf/jquery/core/AggregateFunction.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@
@FunctionalInterface
public interface AggregateFunction extends FunctionOperator {

}
}
2 changes: 1 addition & 1 deletion src/main/java/org/usf/jquery/core/ArgTypeRef.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ interface ArgTypeRef extends Function<Object[], JDBCType> {

static ArgTypeRef firstArgJdbcType() {
return arr-> typeOf(requireAtLeastNArgs(1, arr,
()-> "ArgTypeRef function")[0]).orElse(null); // not sure
ArgTypeRef.class::getSimpleName)[0]).orElse(null); // not sure
}
}
2 changes: 1 addition & 1 deletion src/main/java/org/usf/jquery/core/ArithmeticOperator.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ interface ArithmeticOperator extends Operator {

@Override
default String sql(QueryParameterBuilder builder, Object[] args) {
requireNArgs(2, args, ArithmeticOperator.class::getSimpleName);
requireNArgs(2, args, ArithmeticException.class::getSimpleName);
return "(" + builder.appendLiteral(args[0]) + id() + builder.appendLiteral(args[1]) + ")";
}
}
2 changes: 1 addition & 1 deletion src/main/java/org/usf/jquery/core/CastFunction.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ default String id() {

@Override
default String sql(QueryParameterBuilder builder, Object[] args) {
requireAtLeastNArgs(1, args, ()-> id() + "_AS_" + asType());
requireAtLeastNArgs(1, args, CastFunction.class::getSimpleName);
var sb = new SqlStringBuilder(id())
.append("(")
.append(builder.appendLiteral(args[0])).append(" AS ").append(asType());
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/org/usf/jquery/core/Comparator.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import static org.usf.jquery.core.JDBCType.VARCHAR;
import static org.usf.jquery.core.Parameter.required;
import static org.usf.jquery.core.Parameter.varargs;
import static org.usf.jquery.core.DBProcessor.lookup;

import java.util.Objects;
import java.util.Optional;
Expand Down Expand Up @@ -164,6 +165,6 @@ static InCompartor inComparator(final String name) {
}

static Optional<TypedComparator> lookupComparator(String op) {
return DBProcessor.lookup(Comparator.class, TypedComparator.class, op);
return lookup(Comparator.class, TypedComparator.class, op);
}
}
2 changes: 1 addition & 1 deletion src/main/java/org/usf/jquery/core/ExtractFunction.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ default String id() {

@Override
default String sql(QueryParameterBuilder builder, Object[] args) {
requireNArgs(1, args, this::id);
requireNArgs(1, args, ExtractFunction.class::getSimpleName);
return id() + "(" + field() + " FROM " + builder.appendLiteral(args[0]) + ")";
}
}
6 changes: 6 additions & 0 deletions src/main/java/org/usf/jquery/core/JoinType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.usf.jquery.core;

public enum JoinType {

INNER, LEFT, RIGHT, FULL;
}
3 changes: 2 additions & 1 deletion src/main/java/org/usf/jquery/core/Operator.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.usf.jquery.core;

import static org.usf.jquery.core.ArgTypeRef.firstArgJdbcType;
import static org.usf.jquery.core.DBProcessor.lookup;
import static org.usf.jquery.core.Database.TERADATA;
import static org.usf.jquery.core.Database.currentDatabase;
import static org.usf.jquery.core.JDBCType.BIGINT;
Expand Down Expand Up @@ -334,6 +335,6 @@ static ConstantOperator constant(String name) {
}

static Optional<TypedOperator> lookupOperator(String op) {
return DBProcessor.lookup(Operator.class, TypedOperator.class, op);
return lookup(Operator.class, TypedOperator.class, op);
}
}
2 changes: 1 addition & 1 deletion src/main/java/org/usf/jquery/core/PipeFunction.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public interface PipeFunction extends FunctionOperator {

@Override
default String sql(QueryParameterBuilder builder, Object[] args) {
requireAtLeastNArgs(1, args, ()-> "Pipe function");
requireAtLeastNArgs(1, args, PipeFunction.class::getSimpleName);
return builder.appendLiteral(args[0]) + SPACE
+ FunctionOperator.super.sql(builder, copyOfRange(args, 1, args.length));
}
Expand Down
9 changes: 7 additions & 2 deletions src/main/java/org/usf/jquery/core/QueryColumn.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,21 @@
import lombok.Getter;
import lombok.RequiredArgsConstructor;

/**
*
* @author u$f
*
*/
@RequiredArgsConstructor(access = AccessLevel.PACKAGE)
public class QueryColumn implements DBColumn {
public final class QueryColumn implements DBColumn {

private final QueryView query;
@Getter
private final JDBCType type;

@Override
public String sql(QueryParameterBuilder builder) {
requireNArgs(1, query.getBuilder().getColumns().toArray(), ()-> ""); //TODO
requireNArgs(1, query.getBuilder().getColumns().toArray(), ()-> "require only one column: " + query);
return query.sql(builder);
}

Expand Down
38 changes: 6 additions & 32 deletions src/main/java/org/usf/jquery/core/Validation.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package org.usf.jquery.core;

import static java.lang.String.format;
import static java.util.Objects.isNull;
import static java.util.Objects.nonNull;

import java.util.Collection;
import java.util.function.Supplier;
import java.util.function.UnaryOperator;

import lombok.AccessLevel;
import lombok.NoArgsConstructor;
Expand All @@ -21,59 +21,33 @@ public final class Validation {
public static final String VAR_PATTERN = "[a-zA-Z]\\w*";

public static String requireLegalVariable(String s) {
return requireLegalVariable(s, v-> "illegal variable name : " + v);
}

public static String requireLegalVariable(String s, UnaryOperator<String> msg) {
illegalArgumentIf(isNull(s) || !s.matches(VAR_PATTERN), ()-> msg.apply(s));
return s;
}

public static String requireNonBlank(String s) {
illegalArgumentIf(isNull(s) || s.isBlank(), "empty string");
illegalArgumentIf(isNull(s) || !s.matches(VAR_PATTERN), ()-> "illegal variable name: " + s);
return s;
}

public static <T> T[] requireNonEmpty(T[] arr){
illegalArgumentIf(isNull(arr) || arr.length == 0, "empty array");
return arr;
}

public static <T> Collection<T> requireNonEmpty(Collection<T> c, String name){
illegalArgumentIf(isNull(c) || c.isEmpty(), name + " is empty");
illegalArgumentIf(isNull(c) || c.isEmpty(), ()-> name + " is empty");
return c;
}

public static <T> T[] requireNoArgs(T[] args, Supplier<String> name) {
illegalArgumentIf(nonNull(args) && args.length > 0, ()-> name.get() + " takes no parameters");
illegalArgumentIf(nonNull(args) && args.length > 0, ()-> format("'%s' takes no arguments", name.get()));
return args;
}

public static <T> T[] requireNArgs(int n, T[] args, Supplier<String> name) {
illegalArgumentIf(isNull(args) || args.length != n, ()-> name.get() + " takes " + n + " parameters");
illegalArgumentIf(isNull(args) || args.length != n, ()-> format("'%s' takes %d arguments", name.get(), n));
return args;
}

public static <T> T[] requireAtLeastNArgs(int n, T[] args, Supplier<String> name) {
illegalArgumentIf(isNull(args) || args.length < n, ()-> name.get() + " takes at least " + n + " parameters");
illegalArgumentIf(isNull(args) || args.length < n, ()-> format("'%s' takes at least %d arguments", name.get(), n));
return args;
}

public static <T> T[] requireAtMostNArgs(int n, T[] args, Supplier<String> name) {
illegalArgumentIf(nonNull(args) && args.length > n, ()-> name.get() + " takes at most" + n + " parameters");
return args;
}

public static void illegalArgumentIf(boolean test, String msg) {
if(test) {
throw new IllegalArgumentException(msg);
}
}

public static void illegalArgumentIf(boolean test, Supplier<String> supplier) {
if(test) {
throw new IllegalArgumentException(supplier.get());
}
}

}
20 changes: 4 additions & 16 deletions src/main/java/org/usf/jquery/core/ViewJoin.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package org.usf.jquery.core;

import static java.util.stream.Collectors.joining;
import static org.usf.jquery.core.JoinType.FULL;
import static org.usf.jquery.core.JoinType.INNER;
import static org.usf.jquery.core.JoinType.LEFT;
import static org.usf.jquery.core.JoinType.RIGHT;
import static org.usf.jquery.core.LogicalOperator.AND;
import static org.usf.jquery.core.Validation.requireNoArgs;
import static org.usf.jquery.core.ViewJoin.JoinType.FULL;
import static org.usf.jquery.core.ViewJoin.JoinType.INNER;
import static org.usf.jquery.core.ViewJoin.JoinType.LEFT;
import static org.usf.jquery.core.ViewJoin.JoinType.RIGHT;

import java.util.stream.Stream;

Expand Down Expand Up @@ -57,16 +57,4 @@ public static ViewJoin fullJoin(DBView view, DBFilter... filters) {
public static ViewJoin join(JoinType jt, DBView view, DBFilter... filters) {
return new ViewJoin(jt, view, filters);
}

public enum JoinType {

INNER, LEFT, RIGHT, FULL;

public static String pattern() {
return Stream.of(values())
.map(JoinType::name)
.map(String::toLowerCase)
.collect(joining("|"));
}
}
}
16 changes: 8 additions & 8 deletions src/main/java/org/usf/jquery/web/ColumnMetadata.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ public final class ColumnMetadata {
private int precision;
private final boolean overConfigured;

public void update(int type, int size, int precision) {
if(!overConfigured) {
this.type = fromDataType(type).orElse(OTHER);
this.dataSize = size;
this.precision = precision;
}
}

ColumnMetadata reset() {
if(!overConfigured) {
this.type = null;
Expand All @@ -45,14 +53,6 @@ ColumnMetadata reset() {
return this;
}

public void update(int type, int size, int precision) {
if(!overConfigured) {
this.type = fromDataType(type).orElse(OTHER);
this.dataSize = size;
this.precision = precision;
}
}

public String toJavaType(){
var t = type.typeClass().getSimpleName();
return overConfigured ? t+"!" : t;
Expand Down
44 changes: 30 additions & 14 deletions src/main/java/org/usf/jquery/web/ContextEnvironment.java
Original file line number Diff line number Diff line change
@@ -1,49 +1,56 @@
package org.usf.jquery.web;

import static java.lang.reflect.Modifier.isStatic;
import static java.util.Collections.unmodifiableMap;
import static java.util.Objects.isNull;
import static java.util.Objects.nonNull;
import static java.util.Objects.requireNonNull;
import static java.util.Optional.ofNullable;
import static java.util.function.Function.identity;
import static java.util.stream.Collectors.toMap;
import static java.util.stream.Collectors.toSet;
import static org.usf.jquery.core.Validation.requireLegalVariable;
import static org.usf.jquery.core.Validation.requireNonEmpty;
import static org.usf.jquery.web.ResourceAccessException.resourceAlreadyExistsException;

import java.lang.reflect.Field;
import java.sql.SQLException;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collector;
import java.util.stream.Stream;

import javax.sql.DataSource;

import org.usf.jquery.core.DBView;
import org.usf.jquery.core.JQueryException;
import org.usf.jquery.core.QueryView;
import org.usf.jquery.core.TaggableColumn;
import org.usf.jquery.core.Validation;

import lombok.AccessLevel;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
*
* @author u$f
*
*/
@Slf4j
@Getter
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public final class ContextEnvironment {

private static final Set<String> RESERVED_WORDS = Stream.of(Parameters.class.getDeclaredFields())
.filter(f-> isStatic(f.getModifiers()))
.map(Field::getName)
.collect(toSet());

private final DatabaseDecorator database;
private final Map<String, ViewDecorator> views;
private final Map<String, ColumnDecorator> columns;
Expand Down Expand Up @@ -105,18 +112,20 @@ ViewMetadata computeTableMetadata(ViewDecorator vd, Function<Collection<ColumnDe
}

ContextEnvironment bind() {
if(nonNull(dataSource)) { //outer fetch
for(var v : views.values()) {
var meta = requireNonNull(v.metadata(), v.identity() + ".metadata");
synchronized(meta) {
try(var cnx = dataSource.getConnection()) {
meta.fetch(cnx.getMetaData(), schema);
}
catch(SQLException | JQueryException e) {
log.error("error while scanning '{}' metadata", v.identity(), e);
if(nonNull(dataSource)) {
try(var cnx = dataSource.getConnection()) {
var cm = cnx.getMetaData();
metadata.fetch(cm);
for(var v : views.values()) {
var meta = requireNonNull(v.metadata(), v.identity() + ".metadata");
synchronized(meta) {
meta.fetch(cm, schema);
}
}
}
catch (SQLException e) {
throw new JQueryException(e);
}
}
return this;
}
Expand All @@ -133,7 +142,7 @@ public static ContextEnvironment of(DatabaseDecorator database,

public static ContextEnvironment of(DatabaseDecorator database,
Collection<ViewDecorator> views, Collection<ColumnDecorator> columns, DataSource ds, String schema) {
requireLegalVariable(requireNonNull(database, "configuration.database").identity());
assertIdentity(requireNonNull(database, "configuration.database").identity());
return new ContextEnvironment(database,
unmodifiableIdentityMap(views, ViewDecorator::identity, database.identity() + ".views"), //preserve views order
unmodifiableIdentityMap(columns, ColumnDecorator::identity, database.identity() + ".columns"),
Expand All @@ -142,7 +151,7 @@ public static ContextEnvironment of(DatabaseDecorator database,

static <T> Map<String, T> unmodifiableIdentityMap(Collection<T> c, Function<T, String> fn, String msg){
return unmodifiableMap(requireNonEmpty(c, msg).stream()
.collect(toLinkedMap(fn.andThen(Validation::requireLegalVariable), identity())));
.collect(toLinkedMap(fn.andThen(ContextEnvironment::assertIdentity), identity())));
}

static <T, K, U> Collector<T, ?, Map<K,U>> toLinkedMap(
Expand All @@ -152,4 +161,11 @@ static <T> Map<String, T> unmodifiableIdentityMap(Collection<T> c, Function<T, S
(v1, v2) -> {throw new IllegalStateException("!parallel");},
LinkedHashMap::new);
}

static String assertIdentity(String id) {
if(!RESERVED_WORDS.contains(requireLegalVariable(id))){
return id;
}
throw new IllegalArgumentException("reserved word cannot be used as an identifier: " + id);
}
}
2 changes: 1 addition & 1 deletion src/main/java/org/usf/jquery/web/ContextManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

import static java.util.Objects.isNull;
import static java.util.Objects.nonNull;
import static org.usf.jquery.web.Constants.DATABASE;
import static org.usf.jquery.web.NoSuchResourceException.noSuchResourceException;
import static org.usf.jquery.web.Parameters.DATABASE;
import static org.usf.jquery.web.ResourceAccessException.resourceAlreadyExistsException;

import java.util.HashMap;
Expand Down
Loading

0 comments on commit 625a503

Please sign in to comment.