dbo CRUD first iter
This commit is contained in:
@@ -13,6 +13,12 @@
|
|||||||
<attribute name="test" value="true"/>
|
<attribute name="test" value="true"/>
|
||||||
</attributes>
|
</attributes>
|
||||||
</classpathentry>
|
</classpathentry>
|
||||||
|
<classpathentry kind="src" output="build/classes/java/main" path="src/main/resources">
|
||||||
|
<attributes>
|
||||||
|
<attribute name="gradle_scope" value="main"/>
|
||||||
|
<attribute name="gradle_used_by_scope" value="main,test"/>
|
||||||
|
</attributes>
|
||||||
|
</classpathentry>
|
||||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8/"/>
|
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8/"/>
|
||||||
<classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer"/>
|
<classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer"/>
|
||||||
<classpathentry kind="output" path="build-default"/>
|
<classpathentry kind="output" path="build-default"/>
|
||||||
|
|||||||
Vendored
+4
-4
@@ -1,6 +1,9 @@
|
|||||||
.vscode/
|
.vscode/
|
||||||
!.vscode/launch.json
|
!.vscode/launch.json
|
||||||
|
build/
|
||||||
|
dist/
|
||||||
|
target/
|
||||||
|
var/
|
||||||
### Java ###
|
### Java ###
|
||||||
*.class
|
*.class
|
||||||
|
|
||||||
@@ -21,9 +24,6 @@ hs_err_pid*
|
|||||||
|
|
||||||
### Gradle ###
|
### Gradle ###
|
||||||
.gradle
|
.gradle
|
||||||
build/
|
|
||||||
dist/
|
|
||||||
target/
|
|
||||||
|
|
||||||
# Ignore Gradle GUI config
|
# Ignore Gradle GUI config
|
||||||
gradle-app.setting
|
gradle-app.setting
|
||||||
|
|||||||
+43
-23
@@ -1,7 +1,23 @@
|
|||||||
|
/**
|
||||||
|
Local repostories:
|
||||||
|
Unix - ~/.m2
|
||||||
|
Windows - C:\Users\<username>\.m2
|
||||||
|
For example - /Users/alex/.m2/repository/<library_path>/<version>/<name>.<extension>
|
||||||
|
*/
|
||||||
|
|
||||||
apply plugin: 'java'
|
apply plugin: 'java'
|
||||||
apply plugin: 'eclipse'
|
apply plugin: 'eclipse'
|
||||||
apply plugin: 'application'
|
apply plugin: 'application'
|
||||||
mainClassName = 'com.reliancy.jabba.Router'
|
apply plugin: 'maven-publish'
|
||||||
|
|
||||||
|
group='com.reliancy'
|
||||||
|
version = '0.1'
|
||||||
|
mainClassName = group+'.'+name+'.Router'
|
||||||
|
System.out.println("group:"+group);
|
||||||
|
System.out.println("name:"+name);
|
||||||
|
System.out.println("version:"+version);
|
||||||
|
System.out.println("entry:"+mainClassName);
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenLocal()
|
mavenLocal()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
@@ -12,8 +28,8 @@ targetCompatibility = 1.8
|
|||||||
dependencies {
|
dependencies {
|
||||||
implementation "org.eclipse.jetty:jetty-server:11.0.1"
|
implementation "org.eclipse.jetty:jetty-server:11.0.1"
|
||||||
implementation "org.slf4j:slf4j-simple:2.0.0-alpha0"
|
implementation "org.slf4j:slf4j-simple:2.0.0-alpha0"
|
||||||
implementation 'com.hubspot.jinjava:jinjava:2.5.10'
|
//implementation 'com.hubspot.jinjava:jinjava:2.5.10'
|
||||||
implementation 'com.hubspot.jinjava:jinjava:2.5.10'
|
implementation 'com.github.jknack:handlebars:4.2.1'
|
||||||
implementation 'com.h2database:h2:1.4.200'
|
implementation 'com.h2database:h2:1.4.200'
|
||||||
// https://mvnrepository.com/artifact/org.postgresql/postgresql
|
// https://mvnrepository.com/artifact/org.postgresql/postgresql
|
||||||
implementation 'org.postgresql:postgresql:42.3.1'
|
implementation 'org.postgresql:postgresql:42.3.1'
|
||||||
@@ -43,20 +59,21 @@ test {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
jar {
|
jar {
|
||||||
archiveBaseName = 'jabba'
|
archiveBaseName = project.name
|
||||||
archiveVersion = '0.1'
|
archiveVersion = project.version
|
||||||
manifest {
|
manifest {
|
||||||
attributes "Main-Class": mainClassName
|
attributes "Main-Class": mainClassName
|
||||||
attributes "Class-Path": configurations.runtimeClasspath.collect { it.getName() }.join(' ')
|
attributes "Class-Path": configurations.runtimeClasspath.collect { it.getName() }.join(' ')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
task copyToLib(type: Copy) {
|
task copyToLib(type: Copy) {
|
||||||
into "${buildDir}/libs" from configurations.runtimeClasspath
|
//into "${buildDir}/libs" from configurations.runtimeClasspath
|
||||||
|
into layout.buildDirectory.dir("libs") from configurations.runtimeClasspath
|
||||||
}
|
}
|
||||||
build.dependsOn(copyToLib)
|
build.finalizedBy(copyToLib)
|
||||||
task fat_jar(type: Jar) {
|
task fat_jar(type: Jar) {
|
||||||
archiveBaseName = 'fat-jabba'
|
archiveBaseName = 'fat-'+project.name
|
||||||
archiveVersion = '0.1'
|
archiveVersion = project.version
|
||||||
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||||
/*
|
/*
|
||||||
manifest {
|
manifest {
|
||||||
@@ -86,7 +103,7 @@ class Server implements Runnable{
|
|||||||
}
|
}
|
||||||
return singleton;
|
return singleton;
|
||||||
}
|
}
|
||||||
org.slf4j.Logger log=org.slf4j.LoggerFactory.getLogger("server.driver");
|
//org.slf4j.Logger log=org.slf4j.LoggerFactory.getLogger("server.driver");
|
||||||
Thread driver=null;
|
Thread driver=null;
|
||||||
Runnable task=null;
|
Runnable task=null;
|
||||||
protected Server(){}
|
protected Server(){}
|
||||||
@@ -107,10 +124,8 @@ class Server implements Runnable{
|
|||||||
info("running task");
|
info("running task");
|
||||||
try{
|
try{
|
||||||
task.run();
|
task.run();
|
||||||
}catch(java.lang.InterruptedException ex){
|
}catch(java.lang.Exception ex){
|
||||||
info("running task:interrupted");
|
info("running task:interrupted");
|
||||||
}catch(org.gradle.internal.UncheckedException ex2){
|
|
||||||
info("running task:interrupted2");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public Server start(Runnable c){
|
public Server start(Runnable c){
|
||||||
@@ -165,16 +180,21 @@ task runServer{
|
|||||||
//args "arg1", "arg2"
|
//args "arg1", "arg2"
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
// build.gradle
|
publishing {
|
||||||
eclipse.classpath {
|
publications {
|
||||||
defaultOutputDir = file("build") ///default
|
mavenJava(MavenPublication) {
|
||||||
file.whenMerged { cp ->
|
from components.java
|
||||||
cp.entries.forEach { cpe ->
|
}
|
||||||
if (cpe instanceof org.gradle.plugins.ide.eclipse.model.SourceFolder) {
|
}
|
||||||
cpe.output = cpe.output.replace "bin/", "build/classes/java/"
|
}
|
||||||
}
|
eclipse{
|
||||||
if (cpe instanceof org.gradle.plugins.ide.eclipse.model.Output) {
|
classpath {
|
||||||
cpe.path = cpe.path.replace "bin/", "build/"
|
defaultOutputDir = file("build") ///default
|
||||||
|
file.whenMerged { cp ->
|
||||||
|
cp.entries.forEach { cpe ->
|
||||||
|
if (cpe.kind == 'src' && cpe.hasProperty('output')) {
|
||||||
|
cpe.output = cpe.output.replace('bin/', "build/classes/java/")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,35 +1,47 @@
|
|||||||
package com.reliancy.dbo;
|
package com.reliancy.dbo;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
import com.reliancy.util.CloseableIterator;
|
|
||||||
|
|
||||||
/** Description of a terminal operation with a slice of dbo objects as input or output.
|
/** Description of a terminal operation with a slice of dbo objects as input or output.
|
||||||
* This object is not just for reading but also bulk updating.
|
* This object is not just for reading but also bulk updating.
|
||||||
* It will be used to describe a multi DBO read or write and to then also track results.
|
* It will be used to describe a multi DBO read or write and to then also track results.
|
||||||
|
* At its core are action traits which are classes that define either loading,saving or deleting.
|
||||||
|
* The items field is a consumable object when consumed the action is done.
|
||||||
|
* So for loading we iterate once done it cannot be done again. Also when items are provided for saving
|
||||||
|
* once iterated over and saved they we done.
|
||||||
*/
|
*/
|
||||||
public class Action implements Iterable<DBO>,CloseableIterator<DBO>{
|
public class Action implements Iterable<DBO>,SiphonIterator<DBO>{
|
||||||
public static enum Type{
|
public static class Trait{
|
||||||
NONE,LOAD,SAVE,DELETE
|
public String toString(){return getClass().getSimpleName();}
|
||||||
}
|
}
|
||||||
|
public static class Load extends Trait{
|
||||||
|
int limit,offset;
|
||||||
|
Check filter;
|
||||||
|
}
|
||||||
|
public static class Save extends Trait{
|
||||||
|
|
||||||
|
}
|
||||||
|
public static class Delete extends Trait{
|
||||||
|
Check filter;
|
||||||
|
}
|
||||||
|
|
||||||
Terminal terminal;
|
Terminal terminal;
|
||||||
Type type;
|
Trait trait;
|
||||||
Entity entity;
|
Entity entity;
|
||||||
Object[] params;
|
Object[] params;
|
||||||
CloseableIterator<DBO> items;
|
SiphonIterator<DBO> items;
|
||||||
int limit,offset;
|
|
||||||
Condition filter;
|
|
||||||
|
|
||||||
public Action(){
|
public Action(){
|
||||||
type=Type.NONE;
|
trait=null;
|
||||||
}
|
}
|
||||||
public Action(Type t){
|
public Action(Trait t){
|
||||||
type=t;
|
trait=t;
|
||||||
}
|
}
|
||||||
public Action(Terminal t){
|
public Action(Terminal t){
|
||||||
terminal=t;
|
terminal=t;
|
||||||
type=Type.NONE;
|
trait=null;
|
||||||
}
|
}
|
||||||
public Action execute() throws IOException{
|
public Action execute() throws IOException{
|
||||||
return terminal.execute(this);
|
return terminal.execute(this);
|
||||||
@@ -42,11 +54,11 @@ public class Action implements Iterable<DBO>,CloseableIterator<DBO>{
|
|||||||
this.terminal = terminal;
|
this.terminal = terminal;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
public Type getType() {
|
public Trait getTrait() {
|
||||||
return type;
|
return trait;
|
||||||
}
|
}
|
||||||
public Action setType(Type type) {
|
public Action setTrait(Trait t) {
|
||||||
this.type = type;
|
this.trait = t;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
public Entity getEntity() {
|
public Entity getEntity() {
|
||||||
@@ -58,22 +70,27 @@ public class Action implements Iterable<DBO>,CloseableIterator<DBO>{
|
|||||||
}
|
}
|
||||||
public void clear(){
|
public void clear(){
|
||||||
terminal=null;
|
terminal=null;
|
||||||
type=Type.NONE;
|
trait=null;
|
||||||
entity=null;
|
entity=null;
|
||||||
setItems((DBO)null);
|
setItems((DBO)null);
|
||||||
}
|
}
|
||||||
public Action load(Entity ent){
|
public Action load(Entity ent){
|
||||||
type=Type.LOAD;
|
trait=new Load();
|
||||||
entity=ent;
|
entity=ent;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
public Action load(Class<? extends DBO> cls){
|
||||||
|
trait=new Load();
|
||||||
|
entity=Entity.recall(cls);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
public Action save(Entity ent){
|
public Action save(Entity ent){
|
||||||
type=Type.SAVE;
|
trait=new Save();
|
||||||
entity=ent;
|
entity=ent;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
public Action delete(Entity ent){
|
public Action delete(Entity ent){
|
||||||
type=Type.DELETE;
|
trait=new Delete();
|
||||||
entity=ent;
|
entity=ent;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -81,10 +98,10 @@ public class Action implements Iterable<DBO>,CloseableIterator<DBO>{
|
|||||||
params=p;
|
params=p;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
public Action setItems(DBO ...itms){
|
public Action setItems(final DBO ...itms){
|
||||||
CloseableIterator<DBO> it=null;
|
SiphonIterator<DBO> it=null;
|
||||||
if(itms!=null){
|
if(itms!=null){
|
||||||
it=new CloseableIterator<DBO>() {
|
it=new SiphonIterator<DBO>() {
|
||||||
private int index = 0;
|
private int index = 0;
|
||||||
@Override
|
@Override
|
||||||
public boolean hasNext() {
|
public boolean hasNext() {
|
||||||
@@ -101,7 +118,28 @@ public class Action implements Iterable<DBO>,CloseableIterator<DBO>{
|
|||||||
}
|
}
|
||||||
return setItems(it);
|
return setItems(it);
|
||||||
}
|
}
|
||||||
public Action setItems(CloseableIterator<DBO> itms){
|
public Action setItems(final Collection<DBO> itms){
|
||||||
|
SiphonIterator<DBO> it=null;
|
||||||
|
if(itms!=null){
|
||||||
|
it=new SiphonIterator<DBO>() {
|
||||||
|
private final Iterator<DBO> str = itms.iterator();
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return str.hasNext();
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public DBO next() {
|
||||||
|
return str.next();
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return setItems(it);
|
||||||
|
}
|
||||||
|
public Action setItems(SiphonIterator<DBO> itms){
|
||||||
|
if(items==itms) return this;
|
||||||
if(items!=null){
|
if(items!=null){
|
||||||
try {
|
try {
|
||||||
items.close();
|
items.close();
|
||||||
@@ -111,7 +149,7 @@ public class Action implements Iterable<DBO>,CloseableIterator<DBO>{
|
|||||||
items=itms;
|
items=itms;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
protected CloseableIterator<DBO> getItems(){
|
protected SiphonIterator<DBO> getItems(){
|
||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
@@ -130,30 +168,51 @@ public class Action implements Iterable<DBO>,CloseableIterator<DBO>{
|
|||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
if(items!=null){
|
if(items!=null){
|
||||||
items.close();
|
items.close();
|
||||||
|
items=null;
|
||||||
if(terminal!=null) terminal.end(this);
|
if(terminal!=null) terminal.end(this);
|
||||||
}
|
}
|
||||||
items=null;
|
|
||||||
}
|
}
|
||||||
public Action limit(int max) {
|
public Action limit(int max) {
|
||||||
limit=max;
|
((Load)trait).limit=max;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
public Action if_filter(Condition... c){
|
public Action filterBy(Check... c){
|
||||||
|
Check filter=null;
|
||||||
if(c!=null){
|
if(c!=null){
|
||||||
if(c.length>1) filter=Condition.and(c);
|
if(c.length>1) filter=Check.and(c);
|
||||||
else filter=c[0];
|
else filter=c[0];
|
||||||
|
}
|
||||||
|
if(trait instanceof Load){
|
||||||
|
((Load)trait).filter=filter;
|
||||||
|
}else
|
||||||
|
if(trait instanceof Delete){
|
||||||
|
((Delete)trait).filter=filter;
|
||||||
}else{
|
}else{
|
||||||
filter=null;
|
throw new IllegalStateException("filtering not supported by trait:"+trait);
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
public Action if_pk(Object[] id) {
|
public Check getFilter(){
|
||||||
|
if(trait instanceof Load){
|
||||||
|
return ((Load)trait).filter;
|
||||||
|
}else
|
||||||
|
if(trait instanceof Delete){
|
||||||
|
return ((Delete)trait).filter;
|
||||||
|
}else{
|
||||||
|
throw new IllegalStateException("filtering not supported by trait:"+trait);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public Action if_pk(Object... id) {
|
||||||
Field pk=entity.getPk();
|
Field pk=entity.getPk();
|
||||||
return if_filter(Condition.eq(pk,id));
|
return filterBy(pk.eq(id));
|
||||||
}
|
}
|
||||||
public DBO first() {
|
public DBO first() {
|
||||||
try{
|
try{
|
||||||
return items!=null?items.next():null;
|
if(this.hasNext()){
|
||||||
|
return this.next();
|
||||||
|
}else{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}finally{
|
}finally{
|
||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,217 @@
|
|||||||
|
package com.reliancy.dbo;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
/** constraint on a field.
|
||||||
|
* conditions can be leafs or groups such as and,or,not
|
||||||
|
*/
|
||||||
|
public class Check implements Iterable<Check> {
|
||||||
|
public static abstract class Op{
|
||||||
|
public abstract boolean met(Check c,Object val);
|
||||||
|
}
|
||||||
|
public static Op AND=new Op(){
|
||||||
|
public String toString(){return "AND";}
|
||||||
|
public boolean met(Check c,Object val){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
public static Op OR=new Op(){
|
||||||
|
public String toString(){return "OR";}
|
||||||
|
public boolean met(Check c,Object val){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
public static Op NOT=new Op(){
|
||||||
|
public String toString(){return "NOT";}
|
||||||
|
public boolean met(Check c,Object val){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
public static Op EQ=new Op(){
|
||||||
|
public String toString(){return "=";}
|
||||||
|
public boolean met(Check c,Object val){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
public static Op NEQ=new Op(){
|
||||||
|
public String toString(){return "<>";}
|
||||||
|
public boolean met(Check c,Object val){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
public static Op GT=new Op(){
|
||||||
|
public String toString(){return ">";}
|
||||||
|
public boolean met(Check c,Object val){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
public static Op GTE=new Op(){
|
||||||
|
public String toString(){return ">=";}
|
||||||
|
public boolean met(Check c,Object val){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
public static Op LT=new Op(){
|
||||||
|
public String toString(){return "<";}
|
||||||
|
public boolean met(Check c,Object val){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
public static Op LTE=new Op(){
|
||||||
|
public String toString(){return "<=";}
|
||||||
|
public boolean met(Check c,Object val){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
public static Op LIKE=new Op(){
|
||||||
|
public String toString(){return "LIKE";}
|
||||||
|
public boolean met(Check c,Object val){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
public static Op IN=new Op(){
|
||||||
|
public String toString(){return "IN";}
|
||||||
|
public boolean met(Check c,Object val){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
public static Op NOT_IN=new Op(){
|
||||||
|
public String toString(){return "NOT IN";}
|
||||||
|
public boolean met(Check c,Object val){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
public static class CheckIterator implements Iterator<Check>{
|
||||||
|
final Check root;
|
||||||
|
Check cur;
|
||||||
|
int index;
|
||||||
|
public CheckIterator(Check ch){
|
||||||
|
root=ch;
|
||||||
|
cur=root;
|
||||||
|
index=0;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return cur.isLeaf()==false && index<cur.args.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Check next() {
|
||||||
|
return (Check)cur.args[index++];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
public static Check and(Check... c) {
|
||||||
|
return new Check(AND,c);
|
||||||
|
}
|
||||||
|
public static Check all(Check... c) {
|
||||||
|
return new Check(AND,c);
|
||||||
|
}
|
||||||
|
public static Check or(Check... c) {
|
||||||
|
return new Check(OR,c);
|
||||||
|
}
|
||||||
|
public static Check any(Check... c) {
|
||||||
|
return new Check(OR,c);
|
||||||
|
}
|
||||||
|
public static Check not(Check... c) {
|
||||||
|
return new Check(NOT,c);
|
||||||
|
}
|
||||||
|
public static Check none(Check... c) {
|
||||||
|
return new Check(NOT,c);
|
||||||
|
}
|
||||||
|
public static Check eq(Field pk, Object... args) {
|
||||||
|
Object id=args;
|
||||||
|
if(id!=null && args.length==1) id=args[0];
|
||||||
|
return new Check(EQ,pk,id);
|
||||||
|
}
|
||||||
|
public static Check neq(Field pk, Object... args) {
|
||||||
|
Object id=args;
|
||||||
|
if(id!=null && args.length==1) id=args[0];
|
||||||
|
return new Check(NEQ,pk,id);
|
||||||
|
}
|
||||||
|
public static Check gt(Field pk, Object... args) {
|
||||||
|
Object id=args;
|
||||||
|
if(id!=null && args.length==1) id=args[0];
|
||||||
|
return new Check(GT,pk,id);
|
||||||
|
}
|
||||||
|
public static Check gte(Field pk, Object... args) {
|
||||||
|
Object id=args;
|
||||||
|
if(id!=null && args.length==1) id=args[0];
|
||||||
|
return new Check(GTE,pk,id);
|
||||||
|
}
|
||||||
|
public static Check lt(Field pk, Object... args) {
|
||||||
|
Object id=args;
|
||||||
|
if(id!=null && args.length==1) id=args[0];
|
||||||
|
return new Check(LT,pk,id);
|
||||||
|
}
|
||||||
|
public static Check lte(Field pk, Object... args) {
|
||||||
|
Object id=args;
|
||||||
|
if(id!=null && args.length==1) id=args[0];
|
||||||
|
return new Check(LTE,pk,id);
|
||||||
|
}
|
||||||
|
public static Check like(Field pk, Object... args) {
|
||||||
|
Object id=args;
|
||||||
|
if(id!=null && args.length==1) id=args[0];
|
||||||
|
return new Check(LIKE,pk,id);
|
||||||
|
}
|
||||||
|
public static Check in(Field pk, Object... id) {
|
||||||
|
return new Check(IN,pk,id);
|
||||||
|
}
|
||||||
|
public static Check not_in(Field pk, Object... id) {
|
||||||
|
return new Check(NOT_IN,pk,id);
|
||||||
|
}
|
||||||
|
Op code;
|
||||||
|
boolean leaf;
|
||||||
|
Object[] args;
|
||||||
|
boolean locked;
|
||||||
|
|
||||||
|
public Check(Op code,Field f,Object val){
|
||||||
|
this.code=code;
|
||||||
|
leaf=true;
|
||||||
|
args=new Object[]{f,val};
|
||||||
|
}
|
||||||
|
public Check(Op code,Check ... sub){
|
||||||
|
this.code=code;
|
||||||
|
leaf=false;
|
||||||
|
args=sub;
|
||||||
|
}
|
||||||
|
public Check setLocked(boolean f){
|
||||||
|
locked=f;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public boolean isLocked(){
|
||||||
|
return locked;
|
||||||
|
}
|
||||||
|
public Op getCode(){
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
public boolean isLeaf(){
|
||||||
|
return leaf;
|
||||||
|
}
|
||||||
|
public boolean met(Object val){
|
||||||
|
return code.met(this,val);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public Iterator<Check> iterator() {
|
||||||
|
return new CheckIterator(this);
|
||||||
|
}
|
||||||
|
public int getChildCount(){
|
||||||
|
return leaf?0:args.length;
|
||||||
|
}
|
||||||
|
public Check getChild(int index){
|
||||||
|
return leaf?null:(Check)args[index];
|
||||||
|
}
|
||||||
|
public Field getField(){
|
||||||
|
return (Field)args[0];
|
||||||
|
}
|
||||||
|
public Object getValue(){
|
||||||
|
return (Object)args[1];
|
||||||
|
}
|
||||||
|
public Check setValue(Object val){
|
||||||
|
if(locked) throw new IllegalStateException("check value is locked");
|
||||||
|
if(!leaf) throw new IllegalStateException("check is not a leaf");
|
||||||
|
args[1]=val;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
package com.reliancy.dbo;
|
|
||||||
|
|
||||||
/** constraint on a field.
|
|
||||||
* conditions can be leafs or groups such as and,or,not
|
|
||||||
*/
|
|
||||||
public class Condition {
|
|
||||||
public static abstract class Op{
|
|
||||||
public abstract boolean met(Condition c);
|
|
||||||
}
|
|
||||||
public static Op AND=new Op(){
|
|
||||||
public boolean met(Condition c){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
public static Op OR=new Op(){
|
|
||||||
public boolean met(Condition c){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
public static Op NOT=new Op(){
|
|
||||||
public boolean met(Condition c){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
public static Op EQ=new Op(){
|
|
||||||
public boolean met(Condition c){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
public static Op NEQ=new Op(){
|
|
||||||
public boolean met(Condition c){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
public static Op GT=new Op(){
|
|
||||||
public boolean met(Condition c){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
public static Op GTE=new Op(){
|
|
||||||
public boolean met(Condition c){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
public static Op LT=new Op(){
|
|
||||||
public boolean met(Condition c){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
public static Op LTE=new Op(){
|
|
||||||
public boolean met(Condition c){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
public static Op LIKE=new Op(){
|
|
||||||
public boolean met(Condition c){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
public static Op IN=new Op(){
|
|
||||||
public boolean met(Condition c){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
public static Condition and(Condition... c) {
|
|
||||||
return new Condition(AND,c);
|
|
||||||
}
|
|
||||||
public static Condition eq(Field pk, Object... id) {
|
|
||||||
return new Condition(EQ,pk,id);
|
|
||||||
}
|
|
||||||
Op code;
|
|
||||||
Object[] args;
|
|
||||||
public Condition(Op code,Field f,Object val){
|
|
||||||
this.code=code;
|
|
||||||
args=new Object[]{f,val};
|
|
||||||
}
|
|
||||||
public Condition(Op code,Condition ... sub){
|
|
||||||
this.code=code;
|
|
||||||
args=sub;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,34 +1,119 @@
|
|||||||
package com.reliancy.dbo;
|
package com.reliancy.dbo;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import com.reliancy.rec.Hdr;
|
||||||
|
import com.reliancy.rec.JSON;
|
||||||
|
import com.reliancy.rec.Rec;
|
||||||
|
import com.reliancy.rec.Slot;
|
||||||
|
|
||||||
/** Instance of an entity, usually a row in a table.
|
/** Instance of an entity, usually a row in a table.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class DBO{
|
public class DBO implements Rec{
|
||||||
public static enum Status{
|
public static enum Status{
|
||||||
NEW,USED,DELETED,COMPUTED
|
NEW,USED,DELETED,COMPUTED
|
||||||
}
|
}
|
||||||
Terminal terminal;
|
Terminal terminal;
|
||||||
Entity type;
|
Entity type;
|
||||||
Status status;
|
Status status;
|
||||||
|
Object[] values;
|
||||||
|
|
||||||
public DBO() {
|
public DBO() {
|
||||||
|
Class<? extends DBO> cls=this.getClass();
|
||||||
|
if(cls!=DBO.class){
|
||||||
|
Entity ent=Entity.recall(cls);
|
||||||
|
setType(ent);
|
||||||
|
}
|
||||||
|
status=Status.NEW;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public String toString(){
|
||||||
|
try {
|
||||||
|
StringBuffer ret=new StringBuffer();
|
||||||
|
JSON.writes(this,ret);
|
||||||
|
return ret.toString();
|
||||||
|
} catch (IOException e) {
|
||||||
|
return e.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
public Terminal getTerminal() {
|
public Terminal getTerminal() {
|
||||||
return terminal;
|
return terminal;
|
||||||
}
|
}
|
||||||
public void setTerminal(Terminal terminal) {
|
public DBO setTerminal(Terminal terminal) {
|
||||||
this.terminal = terminal;
|
this.terminal = terminal;
|
||||||
}
|
return this;
|
||||||
public Entity getType() {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
public void setType(Entity type) {
|
|
||||||
this.type = type;
|
|
||||||
}
|
}
|
||||||
public Status getStatus(){
|
public Status getStatus(){
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
public void setStatus(Status s) {
|
public DBO setStatus(Status s) {
|
||||||
this.status = s;
|
this.status = s;
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
public final Entity getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
public final DBO setType(Entity type) {
|
||||||
|
this.type = type;
|
||||||
|
if(type==null){
|
||||||
|
values=null;
|
||||||
|
}else{
|
||||||
|
values=new Object[type.count()];
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public Hdr meta() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public int count() {
|
||||||
|
return values!=null?values.length:0;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public Rec set(int pos, Object val) {
|
||||||
|
if(pos<0) pos=count()+pos;
|
||||||
|
values[pos]=val;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public Object get(int pos) {
|
||||||
|
if(pos<0) pos=count()+pos;
|
||||||
|
return values[pos];
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public Rec add(Object val) {
|
||||||
|
throw new UnsupportedOperationException("dbo is not array");
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public Rec remove(int s) {
|
||||||
|
throw new UnsupportedOperationException("dbo is not array");
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public Rec set(Slot s, Object val) {
|
||||||
|
if(s==null) throw new IllegalArgumentException("invalid key provided");
|
||||||
|
int index=s.getPosition(); // try slot position
|
||||||
|
//if(index<0) index=type.findSlot(s.getName());// fall back to search if slot not set
|
||||||
|
if(index<0){
|
||||||
|
throw new IllegalArgumentException("invalid key provided:"+s.getName());
|
||||||
|
}else{
|
||||||
|
values[index]=val;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public Object get(Slot s, Object def) {
|
||||||
|
if(s==null) throw new IllegalArgumentException("invalid key provided");
|
||||||
|
int index=s.getPosition(); // try slot position
|
||||||
|
//if(index<0) index=type.findSlot(s.getName());// fall back to search if slot not set
|
||||||
|
if(index<0) throw new IllegalArgumentException("invalid key provided:"+s.getName());
|
||||||
|
Object ret=values[index];
|
||||||
|
return ret==null?def:ret;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public Rec remove(Slot s) {
|
||||||
|
throw new UnsupportedOperationException("dbo is not resizable");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,52 @@
|
|||||||
package com.reliancy.dbo;
|
package com.reliancy.dbo;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
import com.reliancy.rec.Hdr;
|
import com.reliancy.rec.Hdr;
|
||||||
|
import com.reliancy.rec.Slot;
|
||||||
|
|
||||||
/** Describes an object structure, usually a table.
|
/** Describes an object structure, usually a table.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class Entity extends Hdr{
|
public class Entity extends Hdr{
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target(ElementType.TYPE)
|
||||||
|
public static @interface Info {
|
||||||
|
String name();
|
||||||
|
}
|
||||||
static final HashMap<String,Entity> registry=new HashMap<>();
|
static final HashMap<String,Entity> registry=new HashMap<>();
|
||||||
public static final void publish(Entity ent){
|
public static final void publish(Entity ent){
|
||||||
registry.put(ent.getName(),ent);
|
registry.put(ent.getName(),ent);
|
||||||
|
registry.put(ent.getId(),ent);
|
||||||
}
|
}
|
||||||
public static final void retract(Entity ent){
|
public static final void retract(Entity ent){
|
||||||
registry.values().remove(ent);
|
if(ent==null) return;
|
||||||
|
Collection<Entity> vals=registry.values();
|
||||||
|
while(vals.remove(ent)){}
|
||||||
|
}
|
||||||
|
public static final void retract(Class<? extends DBO> cls){
|
||||||
|
Entity ent=recall(cls.getSimpleName());
|
||||||
|
if(ent!=null){
|
||||||
|
retract(ent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
public static final Entity recall(String name){
|
public static final Entity recall(String name){
|
||||||
return registry.get(name);
|
return registry.get(name);
|
||||||
}
|
}
|
||||||
public static final Entity recall(Class<?> cls){
|
|
||||||
return recall(cls.getSimpleName());
|
public static final Entity recall(Class<? extends DBO> cls){
|
||||||
|
Entity ent=recall(cls.getSimpleName());
|
||||||
|
if(ent==null){
|
||||||
|
ent=publish(cls);
|
||||||
|
}
|
||||||
|
return ent;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* this method will analyze a DBO class and forumate an Entity object out of it.
|
* this method will analyze a DBO class and forumate an Entity object out of it.
|
||||||
@@ -27,15 +54,124 @@ public class Entity extends Hdr{
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public static final Entity publish(Class<? extends DBO> cls){
|
public static final Entity publish(Class<? extends DBO> cls){
|
||||||
return null;
|
Entity ret=registry.get(cls.getSimpleName());
|
||||||
|
if(ret!=null) return ret;
|
||||||
|
//System.out.println("Analyzing:"+cls);
|
||||||
|
Class base=cls.getSuperclass();
|
||||||
|
Entity base_ent=null;
|
||||||
|
int position0=0;
|
||||||
|
if(base!=null && base!=DBO.class){
|
||||||
|
base_ent=publish(base);
|
||||||
|
position0=base_ent.count();
|
||||||
|
}
|
||||||
|
java.lang.reflect.Field[] declaredFields = cls.getDeclaredFields();
|
||||||
|
ArrayList<Field> slots=new ArrayList<>();
|
||||||
|
for (java.lang.reflect.Field field : declaredFields) {
|
||||||
|
if (!java.lang.reflect.Modifier.isStatic(field.getModifiers())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
String sf_name=field.getName();
|
||||||
|
Field slot=(Field) field.get(cls);
|
||||||
|
slot.setId(sf_name);
|
||||||
|
slot.setPosition(position0+slots.size());
|
||||||
|
slots.add(slot);
|
||||||
|
//System.out.println(sf_name+":"+slot+" atpos:"+slot.getPosition());
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Info info=cls.getAnnotation(Info.class);
|
||||||
|
ret=new Entity(info!=null?info.name():cls.getSimpleName()).setId(cls.getSimpleName());
|
||||||
|
ret.setBase(base_ent);
|
||||||
|
ret.setType(cls);
|
||||||
|
ret.getOwnSlots().addAll(slots);
|
||||||
|
publish(ret);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
Entity base;
|
Entity base;
|
||||||
String dbName;
|
String id;
|
||||||
Field pk;
|
Field pk;
|
||||||
public Entity(String name) {
|
public Entity(String name) {
|
||||||
super(name);
|
super(name);
|
||||||
}
|
}
|
||||||
|
@Override
|
||||||
|
public Slot makeSlot(String name){
|
||||||
|
return new Field(name);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public Iterator<Slot> iterator(int offset){
|
||||||
|
if(offset>0) throw new IllegalArgumentException("Offset not supported");
|
||||||
|
final Entity ent=this;
|
||||||
|
return new Iterator<Slot>(){
|
||||||
|
final FieldSlice slice=new FieldSlice(ent).including(Field.FLAG_STORABLE);
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return slice.hasNext();
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public Slot next() {
|
||||||
|
return slice.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public int count(){
|
||||||
|
return super.count()+(base!=null?base.count():0);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* gets a slot which could be here or in base.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Slot getSlot(int pos){
|
||||||
|
if(base!=null){ // we got base
|
||||||
|
int ofs=base.count();
|
||||||
|
if(pos<ofs) return base.getSlot(pos);
|
||||||
|
else return super.getSlot(pos-ofs);
|
||||||
|
}else{ // regular no base
|
||||||
|
return super.getSlot(pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public Field getField(int index){
|
||||||
|
return (Field)getSlot(index);
|
||||||
|
}
|
||||||
|
public int getDepth(){
|
||||||
|
return base!=null?1+base.getDepth():0;
|
||||||
|
}
|
||||||
|
public Entity getBase() {
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
public Entity setBase(Entity base) {
|
||||||
|
this.base = base;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
public Entity setId(String id) {
|
||||||
|
this.id = id;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public Entity setPk(Field pk) {
|
||||||
|
this.pk = pk;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
public Field getPk(){
|
public Field getPk(){
|
||||||
|
if(pk!=null) return pk;
|
||||||
|
// try to locate the pk - this now gos over base as well
|
||||||
|
for(int i=0;i<count() && pk==null;i++){
|
||||||
|
Field pp=(Field) getSlot(i);
|
||||||
|
if(pp.isPk()) pk=pp;
|
||||||
|
}
|
||||||
return pk;
|
return pk;
|
||||||
}
|
}
|
||||||
|
public DBO newInstance() throws InstantiationException, IllegalAccessException{
|
||||||
|
return newInstance(null).setStatus(DBO.Status.NEW);
|
||||||
|
}
|
||||||
|
public DBO newInstance(Terminal t) throws InstantiationException, IllegalAccessException{
|
||||||
|
Class<?> cls=getType();
|
||||||
|
DBO ret=(DBO) cls.newInstance();
|
||||||
|
ret.setType(this).setTerminal(t).setStatus(DBO.Status.NEW);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,101 @@
|
|||||||
package com.reliancy.dbo;
|
package com.reliancy.dbo;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.sql.Date;
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
|
||||||
import com.reliancy.rec.Slot;
|
import com.reliancy.rec.Slot;
|
||||||
/**
|
/**
|
||||||
* Description of a column or property.
|
* Description of a column or property.
|
||||||
*/
|
*/
|
||||||
public class Field extends Slot {
|
public class Field extends Slot {
|
||||||
|
public static Field Int(String name){
|
||||||
|
return new Field(name,Integer.class);
|
||||||
|
}
|
||||||
|
public static Field Str(String name){
|
||||||
|
return new Field(name,String.class);
|
||||||
|
}
|
||||||
|
public static Field Bool(String name){
|
||||||
|
return new Field(name,Boolean.class);
|
||||||
|
}
|
||||||
|
public static Field Float(String name){
|
||||||
|
return new Field(name,Float.class);
|
||||||
|
}
|
||||||
|
public static Field Num(String name){
|
||||||
|
return new Field(name,BigDecimal.class);
|
||||||
|
}
|
||||||
|
public static Field Date(String name){
|
||||||
|
return new Field(name,Date.class);
|
||||||
|
}
|
||||||
|
public static Field DateTime(String name){
|
||||||
|
return new Field(name,Timestamp.class);
|
||||||
|
}
|
||||||
|
public static final int FLAG_PK =0x0100;
|
||||||
|
public static final int FLAG_AUTOINC =0x0200;
|
||||||
|
String id;
|
||||||
|
String typeParams;
|
||||||
public Field(String name) {
|
public Field(String name) {
|
||||||
super(name);
|
super(name);
|
||||||
|
this.raiseFlags(Field.FLAG_STORABLE);
|
||||||
}
|
}
|
||||||
public Field(String name,Class<?> typ) {
|
public Field(String name,Class<?> typ) {
|
||||||
super(name,typ);
|
super(name,typ);
|
||||||
|
this.raiseFlags(Field.FLAG_STORABLE);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public boolean equals(String str){
|
||||||
|
return super.equals(str) || (id!=null && id.equalsIgnoreCase(str));
|
||||||
|
}
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
public void setId(String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
public boolean isPk() {
|
||||||
|
return checkFlags(FLAG_PK);
|
||||||
|
}
|
||||||
|
public Field setPk(boolean pk) {
|
||||||
|
if(pk) raiseFlags(FLAG_PK); else clearFlags(FLAG_PK);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public boolean isAutoIncrement() {
|
||||||
|
return checkFlags(FLAG_AUTOINC);
|
||||||
|
}
|
||||||
|
public Field setAutoIncrement(boolean pk) {
|
||||||
|
if(pk) raiseFlags(FLAG_AUTOINC); else clearFlags(FLAG_AUTOINC);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public String getTypeParams() {
|
||||||
|
return typeParams;
|
||||||
|
}
|
||||||
|
public Field setTypeParams(String p) {
|
||||||
|
typeParams=p;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public Check eq(Object... val) {
|
||||||
|
return Check.eq(this,val);
|
||||||
|
}
|
||||||
|
public Check neq(Object... val) {
|
||||||
|
return Check.neq(this,val);
|
||||||
|
}
|
||||||
|
public Check gt(Object... val) {
|
||||||
|
return Check.gt(this,val);
|
||||||
|
}
|
||||||
|
public Check gte(Object... val) {
|
||||||
|
return Check.gte(this,val);
|
||||||
|
}
|
||||||
|
public Check lt(Object... val) {
|
||||||
|
return Check.lt(this,val);
|
||||||
|
}
|
||||||
|
public Check lte(Object... val) {
|
||||||
|
return Check.lte(this,val);
|
||||||
|
}
|
||||||
|
public Check like(Object... val) {
|
||||||
|
return Check.like(this,val);
|
||||||
|
}
|
||||||
|
public Check in(Object... val) {
|
||||||
|
return Check.in(this,val);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,102 @@
|
|||||||
|
package com.reliancy.dbo;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/** Field iterator matching flags over entity hierarchy.
|
||||||
|
*
|
||||||
|
*/public class FieldSlice implements Iterator<Field>,Iterable<Field>{
|
||||||
|
protected final Entity entity;
|
||||||
|
protected FieldSlice sup;
|
||||||
|
protected int includeMask;
|
||||||
|
protected int excludeMask;
|
||||||
|
protected int raw_index;
|
||||||
|
protected Field next_field;
|
||||||
|
protected int next_index;
|
||||||
|
protected Entity next_entity;
|
||||||
|
public FieldSlice(Entity ent){
|
||||||
|
entity=ent;
|
||||||
|
if(entity.getBase()!=null){
|
||||||
|
sup=new FieldSlice(ent.getBase());
|
||||||
|
}else{
|
||||||
|
sup=null;
|
||||||
|
}
|
||||||
|
raw_index=-1;
|
||||||
|
next_index=-1;
|
||||||
|
}
|
||||||
|
public FieldSlice including(int mask){
|
||||||
|
includeMask=mask;
|
||||||
|
if(sup!=null) sup.including(mask);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public FieldSlice excluding(int mask){
|
||||||
|
excludeMask=mask;
|
||||||
|
if(sup!=null) sup.excluding(mask);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
/** we add rewind capability to allow reuse of same fieldslice.
|
||||||
|
* i.e we use it to generate recipe, then later to properly enumerate values.
|
||||||
|
*/
|
||||||
|
public FieldSlice rewind(){
|
||||||
|
raw_index=-1;
|
||||||
|
next_index=-1;
|
||||||
|
next_field=null;
|
||||||
|
next_entity=null;
|
||||||
|
if(sup!=null) sup.rewind();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
// search for next valid field
|
||||||
|
public final Field findNext(){
|
||||||
|
List<?> local=entity.getOwnSlots();
|
||||||
|
if(raw_index>=local.size()) return null; // we have exhausted local supply
|
||||||
|
next_field=null; // clear prev result
|
||||||
|
// search at base
|
||||||
|
if(sup!=null && sup.hasNext()){
|
||||||
|
next_field=sup.next();
|
||||||
|
next_index++;
|
||||||
|
next_entity=sup.nextEntity();
|
||||||
|
return next_field;
|
||||||
|
}
|
||||||
|
next_entity=entity;
|
||||||
|
// now search locally
|
||||||
|
for(raw_index=raw_index+1;raw_index<local.size();raw_index++){
|
||||||
|
Field f=(Field) local.get(raw_index);
|
||||||
|
int attr=f.getFlags();
|
||||||
|
if((attr & excludeMask)!=0) continue; // skip if in exluding set
|
||||||
|
if((attr & includeMask)==0) continue; // skip if not in including set
|
||||||
|
next_field=f;
|
||||||
|
next_index+=1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return next_field;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public Iterator<Field> iterator() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
Field next=findNext();
|
||||||
|
return next!=null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Field next() {
|
||||||
|
return next_field;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int nextIndex(){
|
||||||
|
return next_field!=null?next_index:-1;
|
||||||
|
}
|
||||||
|
public Entity nextEntity(){
|
||||||
|
return next_entity;
|
||||||
|
}
|
||||||
|
public DBO makeRecord() throws InstantiationException, IllegalAccessException{
|
||||||
|
return entity.newInstance();
|
||||||
|
}
|
||||||
|
public void writeRecord(DBO rec,Object val){
|
||||||
|
rec.set(next_field, val);
|
||||||
|
}
|
||||||
|
public Object readRecord(DBO rec,Object def){
|
||||||
|
return rec.get(next_field, def);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,263 @@
|
|||||||
|
package com.reliancy.dbo;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.reliancy.util.Handy;
|
||||||
|
|
||||||
|
public final class SQL implements Appendable{
|
||||||
|
public final static Object NULL=new Object();
|
||||||
|
public final static String WS=" ";
|
||||||
|
public final static String SELECT="SELECT";
|
||||||
|
public final static String INSERT="INSERT INTO";
|
||||||
|
public final static String UPDATE="UPDATE";
|
||||||
|
public final static String DELETE="DELETE";
|
||||||
|
public final static String FROM="FROM";
|
||||||
|
public final static String INNER_JOIN="INNER JOIN";
|
||||||
|
public final static String ON="ON";
|
||||||
|
public final static String SET="SET";
|
||||||
|
public final static String WHERE="WHERE";
|
||||||
|
|
||||||
|
final StringBuffer buffer=new StringBuffer();
|
||||||
|
final SQLTerminal terminal;
|
||||||
|
final String ql,qr;
|
||||||
|
final HashMap<Entity,String> entAlias=new HashMap<>();
|
||||||
|
|
||||||
|
public SQL(SQLTerminal terminal){
|
||||||
|
this.terminal=terminal;
|
||||||
|
ql=terminal!=null?terminal.getQuoteLeft():"\"";
|
||||||
|
qr=terminal!=null?terminal.getQuoteRight():"\"";
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public String toString(){
|
||||||
|
return buffer.toString();
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public final SQL append(CharSequence csq){
|
||||||
|
buffer.append(csq);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public final SQL append(CharSequence csq, int start, int end){
|
||||||
|
buffer.append(csq,start,end);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public final SQL append(char c){
|
||||||
|
buffer.append(c);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public final SQL select(){
|
||||||
|
append(SELECT);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public final SQL insert(){
|
||||||
|
append(INSERT);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public final SQL update(){
|
||||||
|
append(UPDATE);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public final SQL delete(){
|
||||||
|
append(DELETE);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public final SQL from(){
|
||||||
|
append(WS).append(FROM).append(WS);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public final SQL inner_join(){
|
||||||
|
append(WS).append(INNER_JOIN).append(WS);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public final SQL on(){
|
||||||
|
append(WS).append(ON).append(WS);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public final String wrap(String id){
|
||||||
|
if(id.startsWith(ql) && id.endsWith(qr)){
|
||||||
|
return id;
|
||||||
|
}else{
|
||||||
|
return ql+id.replace(".",qr+"."+ql)+qr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public final SQL id(String id){
|
||||||
|
if(id.startsWith(ql) && id.endsWith(qr)){
|
||||||
|
append(id);
|
||||||
|
}else{
|
||||||
|
append(ql).append(id.replace(".",qr+"."+ql)).append(qr);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public final String getAlias(Entity e){
|
||||||
|
String eAlias=entAlias.get(e);
|
||||||
|
if(eAlias!=null) return eAlias;
|
||||||
|
eAlias="e"+entAlias.size();
|
||||||
|
entAlias.put(e,eAlias);
|
||||||
|
return eAlias;
|
||||||
|
}
|
||||||
|
public final SQL select(Entity ent,FieldSlice fit){
|
||||||
|
entAlias.clear();;
|
||||||
|
select();
|
||||||
|
while(fit.hasNext()){
|
||||||
|
int index=fit.nextIndex();
|
||||||
|
Field f=fit.next();
|
||||||
|
Entity e=fit.nextEntity();
|
||||||
|
String alias=getAlias(e);
|
||||||
|
//System.out.println("It:"+index+":/"+f+"/"+e+"/"+alias);
|
||||||
|
append(index==0?" ":",");
|
||||||
|
append(alias).append(".").id(f.getName());
|
||||||
|
}
|
||||||
|
from();
|
||||||
|
String eAlias=getAlias(ent);
|
||||||
|
id(ent.getName()).append(" ").append(eAlias);
|
||||||
|
for(Entity b=ent.getBase();b!=null;b=b.getBase()){
|
||||||
|
String bAlias=getAlias(b);
|
||||||
|
inner_join();
|
||||||
|
id(b.getName()).append(" ").append(bAlias);
|
||||||
|
on();
|
||||||
|
Field bPk=b.getPk();
|
||||||
|
Field ePk=ent.getPk();
|
||||||
|
append(eAlias).append(".").id(ePk.getName());
|
||||||
|
append("=");
|
||||||
|
append(bAlias).append(".").id(bPk.getName());
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public final SQL where(){
|
||||||
|
append(WS).append(WHERE).append(WS);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public final SQL where(Check filter) {
|
||||||
|
append(WS).append(WHERE).append(WS).check(filter);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
/// using entalias locate field entity and its prefix
|
||||||
|
public final String getFieldPrefix(Field f){
|
||||||
|
for(Map.Entry<Entity,String> e:entAlias.entrySet()){
|
||||||
|
Entity ent=e.getKey();
|
||||||
|
String prefix=e.getValue();
|
||||||
|
if(ent.isOwned(f)) return prefix+".";
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
public final SQL check(Check filter) {
|
||||||
|
if(filter.isLeaf()){
|
||||||
|
Check.Op op=filter.getCode();
|
||||||
|
Field field=filter.getField();
|
||||||
|
String fname=wrap(filter.getField().getName());
|
||||||
|
String opname=op.toString();
|
||||||
|
String arg="?";
|
||||||
|
Object val=filter.getValue();
|
||||||
|
if(op==Check.LIKE && terminal!=null && terminal.getProtocol().contains(":postgre")){
|
||||||
|
opname="ILIKE";
|
||||||
|
}
|
||||||
|
if(op==Check.IN){
|
||||||
|
arg="("+Handy.toString(val)+")";
|
||||||
|
}
|
||||||
|
if(Handy.isEmpty(val)){
|
||||||
|
// if not value then shortcuircuid condition
|
||||||
|
fname="1";
|
||||||
|
opname="=";
|
||||||
|
arg="1";
|
||||||
|
}
|
||||||
|
if(val==NULL){
|
||||||
|
arg="NULL";
|
||||||
|
if(op==Check.EQ) opname="IS";
|
||||||
|
if(op==Check.NEQ) opname="IS NOT";
|
||||||
|
}
|
||||||
|
append("(");
|
||||||
|
String fprefix=getFieldPrefix(field);
|
||||||
|
append(fprefix).append(fname).append(WS).append(opname).append(WS).append(arg);
|
||||||
|
append(")");
|
||||||
|
}else{
|
||||||
|
Check.Op op=filter.getCode();
|
||||||
|
String delim=op.toString();
|
||||||
|
if(op==Check.NOT){
|
||||||
|
append(delim).append("(").check(filter.getChild(0)).append(")");
|
||||||
|
}else{
|
||||||
|
append("(");
|
||||||
|
for(int i=0;i<filter.getChildCount();i++){
|
||||||
|
if(i>0) append(WS).append(delim).append(WS);
|
||||||
|
check(filter.getChild(i));
|
||||||
|
}
|
||||||
|
append(")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
/** fills params list with non-trivial parameters.
|
||||||
|
* we place this method here to be as close as possible to the one which generates the sql code.
|
||||||
|
* check and check_export must be in synch.
|
||||||
|
* @param filter
|
||||||
|
* @param params
|
||||||
|
*/
|
||||||
|
public final void check_export(Check filter,List<Object> params) {
|
||||||
|
if(filter.isLeaf()){
|
||||||
|
Check.Op op=filter.getCode();
|
||||||
|
Object val=filter.getValue();
|
||||||
|
if(Handy.isEmpty(val) || val==NULL || op==Check.IN) return; // skip over empty or NULL values
|
||||||
|
params.add(val);
|
||||||
|
}else{
|
||||||
|
for(Check ch:filter) check_export(ch,params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/** fills check values from dbo record where equal and not-equal are used.
|
||||||
|
* we place this method here to be as close as possible to the one which generates the sql code.
|
||||||
|
* check and check_import must be in synch.
|
||||||
|
* @param filter
|
||||||
|
* @param params
|
||||||
|
*/
|
||||||
|
public final void check_import(Check filter,DBO rec) {
|
||||||
|
if(filter.isLeaf()){
|
||||||
|
if(filter.isLocked()) return; // no import on locked condition
|
||||||
|
Check.Op op=filter.getCode();
|
||||||
|
if(op!=Check.EQ && op!=Check.NEQ) return; // skip over all conditions except = and <>
|
||||||
|
Field f=filter.getField();
|
||||||
|
Object val=f.get(rec,null);
|
||||||
|
filter.setValue(val);
|
||||||
|
}else{
|
||||||
|
for(Check ch:filter) check_import(ch,rec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public final SQL insert(Entity entity,List<Field> supplied){
|
||||||
|
insert();
|
||||||
|
append(SQL.WS).id(entity.getName()).append(" (");
|
||||||
|
StringBuffer ext=new StringBuffer();
|
||||||
|
String delim="";
|
||||||
|
Field pk=entity.getPk();
|
||||||
|
if(!entity.isOwned(pk)){
|
||||||
|
append(delim).id(pk.getName());
|
||||||
|
ext.append(delim).append("?");
|
||||||
|
delim=",";
|
||||||
|
}
|
||||||
|
for(int index=0;index<supplied.size();index++){
|
||||||
|
Field f=supplied.get(index);
|
||||||
|
if(index>0) delim=",";
|
||||||
|
append(delim).id(f.getName());
|
||||||
|
ext.append(delim).append("?");
|
||||||
|
}
|
||||||
|
append(") VALUES (").append(ext).append(")");
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public final SQL update(Entity entity,List<Field> supplied){
|
||||||
|
update();
|
||||||
|
append(SQL.WS).id(entity.getName()).append(" SET ");
|
||||||
|
for(int index=0;index<supplied.size();index++){
|
||||||
|
Field f=supplied.get(index);
|
||||||
|
String delim=index==0?"":",";
|
||||||
|
append(delim);
|
||||||
|
id(f.getName()).append("=?");
|
||||||
|
}
|
||||||
|
where();
|
||||||
|
Field pk=entity.getPk();
|
||||||
|
id(pk.getName()).append("=?");
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public final SQL delete(Entity entity){
|
||||||
|
delete().from().id(entity.getName());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,145 @@
|
|||||||
|
package com.reliancy.dbo;
|
||||||
|
|
||||||
|
import java.io.Closeable;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
/** Helper object which impleents DBO deleting.
|
||||||
|
* It manages the recipe and the prepared statmenet.
|
||||||
|
* The cleaner works in two ways.
|
||||||
|
* If you supply items iterator it will delete by pk id those items.
|
||||||
|
* If you supply a Check filter and no items then it will delete based on a where statement.
|
||||||
|
*/
|
||||||
|
public class SQLCleaner implements Closeable{
|
||||||
|
protected final Entity entity;
|
||||||
|
protected final SQLTerminal terminal;
|
||||||
|
protected final SQLCleaner base; /// used for nesting
|
||||||
|
protected final SQL sql;
|
||||||
|
protected final ArrayList<Object> params;
|
||||||
|
protected Check filter;
|
||||||
|
protected Connection external;
|
||||||
|
protected PreparedStatement deleteStmt;
|
||||||
|
protected int itemsDeleted;
|
||||||
|
protected Exception error;
|
||||||
|
|
||||||
|
public SQLCleaner(Entity ent,SQLTerminal t) {
|
||||||
|
entity=ent;
|
||||||
|
terminal=t;
|
||||||
|
base=(entity.getBase()!=null)?new SQLCleaner(entity.getBase(),t):null;
|
||||||
|
sql=new SQL(terminal);
|
||||||
|
params=new ArrayList<>();
|
||||||
|
}
|
||||||
|
public SQL compileRecipe(){
|
||||||
|
if(filter==null){
|
||||||
|
// no filter we go with PK
|
||||||
|
Field pk=entity.getPk();
|
||||||
|
filter=pk.eq("?");
|
||||||
|
}
|
||||||
|
sql.delete(entity).where(filter);
|
||||||
|
return sql;
|
||||||
|
}
|
||||||
|
public boolean isLinkExternal(){
|
||||||
|
return external!=null;
|
||||||
|
}
|
||||||
|
public SQLCleaner setExternalLink(Connection link){
|
||||||
|
external=link;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
protected Connection getExternalLink(){
|
||||||
|
return external;
|
||||||
|
}
|
||||||
|
protected Connection getInternalLink(){
|
||||||
|
try{
|
||||||
|
if(deleteStmt!=null) return deleteStmt.getConnection();
|
||||||
|
}catch(SQLException ex){
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
public SQLCleaner open() throws SQLException{
|
||||||
|
return open(null);
|
||||||
|
}
|
||||||
|
public SQLCleaner open(Check where) throws SQLException{
|
||||||
|
this.filter=where;
|
||||||
|
Connection link=isLinkExternal()?getExternalLink():terminal.getConnection();
|
||||||
|
if(base!=null) base.setExternalLink(link).open(filter); // definitely external link for base
|
||||||
|
SQL delSQL=compileRecipe();
|
||||||
|
//System.out.println("DEL:"+delSQL+"/"+filter);
|
||||||
|
deleteStmt=link.prepareStatement(delSQL.toString());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException{
|
||||||
|
if(base!=null) base.close(); // since link is external it will not close link just the rest
|
||||||
|
Connection link=getInternalLink();
|
||||||
|
if(deleteStmt!=null){
|
||||||
|
try{
|
||||||
|
deleteStmt.close();
|
||||||
|
}catch(SQLException ex){
|
||||||
|
if(error==null) error=ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try{
|
||||||
|
if(link!=null && !isLinkExternal()) link.close();
|
||||||
|
external=null;
|
||||||
|
}catch(SQLException ex){
|
||||||
|
if(error==null) error=ex;
|
||||||
|
}
|
||||||
|
if(error!=null){
|
||||||
|
if(error instanceof IOException) throw (IOException)error;
|
||||||
|
else throw new IOException(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
public void flush(Iterator<DBO> items) throws SQLException {
|
||||||
|
Connection link=getInternalLink();
|
||||||
|
boolean autocommited=link.getAutoCommit();
|
||||||
|
try{
|
||||||
|
link.setAutoCommit(false);
|
||||||
|
if(items==null){ // deleting by filter
|
||||||
|
throw new SQLException("delete by filter not implemented yet");
|
||||||
|
// we would need to leave the primary filter
|
||||||
|
// we would use filter in an ID in (SUBQUERY)
|
||||||
|
// this is because filter could reference all entities and we have inheritance so multiple
|
||||||
|
// we would generate a select statement with filter and selecting only ID
|
||||||
|
}else{ // deleting by incoming records
|
||||||
|
while(items.hasNext()){
|
||||||
|
DBO rec=items.next();
|
||||||
|
deleteRecord(rec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!link.getAutoCommit()){
|
||||||
|
link.commit();
|
||||||
|
}
|
||||||
|
}catch(SQLException ex){
|
||||||
|
if(!link.getAutoCommit()){
|
||||||
|
link.rollback();
|
||||||
|
}
|
||||||
|
throw ex;
|
||||||
|
}finally{
|
||||||
|
link.setAutoCommit(autocommited);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This calls one delete. It can and is called from outside in case of nesting when link is external.
|
||||||
|
* @param rec
|
||||||
|
* @throws SQLException
|
||||||
|
*/
|
||||||
|
public boolean deleteRecord(DBO rec) throws SQLException{
|
||||||
|
if(rec==null) return false;
|
||||||
|
if(base!=null) base.deleteRecord(rec); // save the superclass first
|
||||||
|
sql.check_import(filter,rec); // get values from dbo
|
||||||
|
params.clear();
|
||||||
|
sql.check_export(filter,params); // move them into params
|
||||||
|
for(int pindex=0;pindex<params.size();pindex++){
|
||||||
|
Object val=params.get(pindex);
|
||||||
|
deleteStmt.setObject(pindex+1,val);
|
||||||
|
}
|
||||||
|
int dcode=deleteStmt.executeUpdate();
|
||||||
|
itemsDeleted+=dcode;
|
||||||
|
return dcode>0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,127 @@
|
|||||||
|
package com.reliancy.dbo;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Statement;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import com.reliancy.dbo.Action.Load;
|
||||||
|
|
||||||
|
|
||||||
|
/** SQLIterator will delay closing a connection and will iterate over result set.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class SQLReader implements SiphonIterator<DBO>{
|
||||||
|
protected final Entity entity;
|
||||||
|
protected final SQLTerminal terminal;
|
||||||
|
protected final SQL sql;
|
||||||
|
protected FieldSlice slice;
|
||||||
|
protected ResultSet result;
|
||||||
|
protected Exception error;
|
||||||
|
|
||||||
|
public SQLReader(Entity ent,SQLTerminal t) {
|
||||||
|
this.entity=ent;
|
||||||
|
terminal=t;
|
||||||
|
// slice controls sql fields but also lets us correctly import values later
|
||||||
|
slice=new FieldSlice(entity).including(Field.FLAG_STORABLE);
|
||||||
|
sql=new SQL(terminal);
|
||||||
|
}
|
||||||
|
public SQLReader open() throws SQLException{
|
||||||
|
return open(null);
|
||||||
|
}
|
||||||
|
public SQLReader open(Action action) throws SQLException{
|
||||||
|
error=null;
|
||||||
|
if(action==null){
|
||||||
|
sql.select(entity,slice); // simple case
|
||||||
|
}else{
|
||||||
|
compileRecipe(action); // complete case
|
||||||
|
}
|
||||||
|
//System.out.println("SQL:"+sql);
|
||||||
|
Connection link=terminal.getConnection();
|
||||||
|
PreparedStatement prep=link.prepareStatement(sql.toString());
|
||||||
|
if(action!=null){
|
||||||
|
Load tr=(Load) action.getTrait();
|
||||||
|
if(tr.filter!=null){
|
||||||
|
ArrayList<Object> params=new ArrayList<>();
|
||||||
|
sql.check_export(tr.filter, params);
|
||||||
|
for(int pindex=0;pindex<params.size();pindex++){
|
||||||
|
Object val=params.get(pindex);
|
||||||
|
prep.setObject(pindex+1,val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result=prep.executeQuery();
|
||||||
|
if(link.getAutoCommit()==false) link.commit();
|
||||||
|
//action.setItems(this); -- maybe we want multiple readers on same actions - leave this to terminal
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public SQL compileRecipe(Action action){
|
||||||
|
sql.select(action.getEntity(),slice);
|
||||||
|
Load tr=(Load) action.getTrait();
|
||||||
|
if(tr.filter!=null){
|
||||||
|
sql.where(tr.filter);
|
||||||
|
}
|
||||||
|
return sql;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
try {
|
||||||
|
return error==null?result.next():false;
|
||||||
|
} catch (SQLException e) {
|
||||||
|
error=e;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DBO next() {
|
||||||
|
try {
|
||||||
|
DBO ret=(DBO) slice.makeRecord();
|
||||||
|
FieldSlice fit=slice.rewind();
|
||||||
|
while(fit.hasNext()){
|
||||||
|
int findex=fit.nextIndex();
|
||||||
|
//Field field=fit.next();
|
||||||
|
Object val=result.getObject(findex+1);
|
||||||
|
fit.writeRecord(ret, val);
|
||||||
|
}
|
||||||
|
ret.setStatus(DBO.Status.USED);
|
||||||
|
return ret;
|
||||||
|
} catch (Exception e) {
|
||||||
|
error=e;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
if(result!=null){
|
||||||
|
Statement stmt=null;
|
||||||
|
Connection link=null;
|
||||||
|
try{
|
||||||
|
stmt=result.getStatement();
|
||||||
|
link=stmt!=null?stmt.getConnection():null;
|
||||||
|
if(!result.isClosed()) result.close();
|
||||||
|
}catch(SQLException ex){
|
||||||
|
if(error==null) error=ex;
|
||||||
|
}
|
||||||
|
try{
|
||||||
|
if(stmt!=null) stmt.close();
|
||||||
|
}catch(SQLException ex){
|
||||||
|
if(error==null) error=ex;
|
||||||
|
}
|
||||||
|
try{
|
||||||
|
if(link!=null) link.close();
|
||||||
|
}catch(SQLException ex){
|
||||||
|
if(error==null) error=ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(error!=null){
|
||||||
|
if(error instanceof IOException) throw (IOException)error;
|
||||||
|
else throw new IOException(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,8 +1,15 @@
|
|||||||
package com.reliancy.dbo;
|
package com.reliancy.dbo;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Array;
|
||||||
|
import java.sql.Blob;
|
||||||
|
import java.sql.Clob;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
|
import java.sql.JDBCType;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Types;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import com.reliancy.util.Path;
|
import com.reliancy.util.Path;
|
||||||
import com.zaxxer.hikari.HikariConfig;
|
import com.zaxxer.hikari.HikariConfig;
|
||||||
@@ -12,6 +19,9 @@ public class SQLTerminal implements Terminal{
|
|||||||
HikariConfig config = new HikariConfig();
|
HikariConfig config = new HikariConfig();
|
||||||
HikariDataSource ds;
|
HikariDataSource ds;
|
||||||
Path url;
|
Path url;
|
||||||
|
String quoteLeft="\""; // quotes could be subject to sql flavour
|
||||||
|
String quoteRight="\"";
|
||||||
|
|
||||||
public SQLTerminal(String url){
|
public SQLTerminal(String url){
|
||||||
this.url=new Path(url);
|
this.url=new Path(url);
|
||||||
String proto=this.url.getProtocol();
|
String proto=this.url.getProtocol();
|
||||||
@@ -20,17 +30,190 @@ public class SQLTerminal implements Terminal{
|
|||||||
config.setJdbcUrl(u);
|
config.setJdbcUrl(u);
|
||||||
config.setUsername(this.url.getUserid());
|
config.setUsername(this.url.getUserid());
|
||||||
config.setPassword(this.url.getPassword());
|
config.setPassword(this.url.getPassword());
|
||||||
|
//config.setAutoCommit(false); -- do this in batch cases only
|
||||||
config.addDataSourceProperty( "cachePrepStmts" , "true" );
|
config.addDataSourceProperty( "cachePrepStmts" , "true" );
|
||||||
config.addDataSourceProperty( "prepStmtCacheSize" , "250" );
|
config.addDataSourceProperty( "prepStmtCacheSize" , "250" );
|
||||||
//config.addDataSourceProperty( "prepStmtCacheSqlLimit" , "2048" );
|
config.addDataSourceProperty( "prepStmtCacheSqlLimit" , "2048" );
|
||||||
ds = new HikariDataSource( config );
|
ds = new HikariDataSource( config );
|
||||||
}
|
}
|
||||||
public Connection getConnection() throws SQLException{
|
public Connection getConnection() throws SQLException{
|
||||||
return ds.getConnection();
|
return ds.getConnection();
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public Action execute(Action q) throws IOException {
|
public Action execute(Action q) throws IOException{
|
||||||
return q;
|
System.out.println("Executing..."+q.getTrait());
|
||||||
|
Action.Trait tr=q.getTrait();
|
||||||
|
if(tr instanceof Action.Load){
|
||||||
|
Entity ent=q.getEntity();
|
||||||
|
SQLReader reader=new SQLReader(ent,this);
|
||||||
|
try {
|
||||||
|
reader.open(q);
|
||||||
|
q.setItems(reader);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
reader.close();
|
||||||
|
throw new IOException(e);
|
||||||
|
}
|
||||||
|
System.out.println("Executing...Done");
|
||||||
|
return q;
|
||||||
|
}else if(tr instanceof Action.Save){
|
||||||
|
Entity ent=q.getEntity();
|
||||||
|
try(SQLWriter writer=new SQLWriter(ent,this)) {
|
||||||
|
writer.open();
|
||||||
|
writer.flush(q.getItems());
|
||||||
|
System.out.println("Executing...Done");
|
||||||
|
return q;
|
||||||
|
}catch(SQLException e){
|
||||||
|
throw new IOException(e);
|
||||||
|
}
|
||||||
|
}else if(tr instanceof Action.Delete){
|
||||||
|
Entity ent=q.getEntity();
|
||||||
|
try(SQLCleaner cleaner=new SQLCleaner(ent,this)) {
|
||||||
|
cleaner.open();
|
||||||
|
cleaner.flush(q.getItems());
|
||||||
|
System.out.println("Executing...Done");
|
||||||
|
return q;
|
||||||
|
}catch(SQLException e){
|
||||||
|
throw new IOException(e);
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
throw new UnsupportedOperationException("Trait not supported:"+tr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
public String getProtocol() {
|
||||||
|
return url.getProtocol();
|
||||||
|
}
|
||||||
|
public String getQuoteLeft(){
|
||||||
|
return this.quoteLeft;
|
||||||
|
}
|
||||||
|
public String getQuoteRight(){
|
||||||
|
return this.quoteRight;
|
||||||
|
}
|
||||||
|
final HashMap<Integer,Class<?>> sql2java=new HashMap<>();
|
||||||
|
final HashMap<Class<?>,Integer> java2sql=new HashMap<>();
|
||||||
|
public Map<Class<?>,Integer> getJava2SQL(){
|
||||||
|
if(!java2sql.isEmpty()) return java2sql;
|
||||||
|
String protocol=url.getProtocol();
|
||||||
|
java2sql.put(java.math.BigDecimal.class,Types.DECIMAL);
|
||||||
|
java2sql.put(java.math.BigInteger.class,Types.DECIMAL);
|
||||||
|
java2sql.put(Boolean.class,protocol.contains(":oracle")?Types.INTEGER:Types.BOOLEAN);
|
||||||
|
java2sql.put(Byte.class,Types.TINYINT);
|
||||||
|
java2sql.put(Short.class,Types.SMALLINT);
|
||||||
|
java2sql.put(Integer.class,Types.INTEGER);
|
||||||
|
java2sql.put(Long.class,Types.BIGINT);
|
||||||
|
java2sql.put(Float.class,Types.FLOAT);
|
||||||
|
java2sql.put(Double.class,Types.DOUBLE);
|
||||||
|
java2sql.put(byte[].class,Types.VARBINARY);
|
||||||
|
java2sql.put(Blob.class,Types.BLOB);
|
||||||
|
java2sql.put(char[].class,Types.VARCHAR);
|
||||||
|
java2sql.put(String.class,Types.VARCHAR);
|
||||||
|
java2sql.put(StringBuffer.class,Types.VARCHAR);
|
||||||
|
java2sql.put(Clob.class,Types.CLOB);
|
||||||
|
java2sql.put(java.sql.Date.class,Types.DATE);
|
||||||
|
java2sql.put(java.sql.Time.class,Types.TIME);
|
||||||
|
java2sql.put(java.sql.Timestamp.class,Types.TIMESTAMP);
|
||||||
|
java2sql.put(Array.class,Types.ARRAY);
|
||||||
|
return java2sql;
|
||||||
|
}
|
||||||
|
public Map<Integer,Class<?>> getSQL2Java(){
|
||||||
|
if(!sql2java.isEmpty()) return sql2java;
|
||||||
|
//String protocol=url.getProtocol();
|
||||||
|
sql2java.put(Types.NUMERIC,java.math.BigDecimal.class);
|
||||||
|
sql2java.put(Types.DECIMAL,java.math.BigDecimal.class);
|
||||||
|
sql2java.put(Types.BIT,Boolean.class);
|
||||||
|
sql2java.put(Types.BOOLEAN,Boolean.class);
|
||||||
|
sql2java.put(Types.TINYINT,Byte.class);
|
||||||
|
sql2java.put(Types.SMALLINT,Short.class);
|
||||||
|
sql2java.put(Types.INTEGER,Integer.class);
|
||||||
|
sql2java.put(Types.BIGINT,Long.class);
|
||||||
|
sql2java.put(Types.REAL,Float.class);
|
||||||
|
sql2java.put(Types.FLOAT,Float.class);
|
||||||
|
sql2java.put(Types.DOUBLE,Double.class);
|
||||||
|
sql2java.put(Types.BINARY,byte[].class);
|
||||||
|
sql2java.put(Types.VARBINARY,byte[].class);
|
||||||
|
sql2java.put(Types.LONGVARBINARY,byte[].class);
|
||||||
|
sql2java.put(Types.CHAR,String.class);
|
||||||
|
sql2java.put(Types.NCHAR,String.class);
|
||||||
|
sql2java.put(Types.VARCHAR,String.class);
|
||||||
|
sql2java.put(Types.NVARCHAR,String.class);
|
||||||
|
sql2java.put(Types.LONGVARCHAR,String.class);
|
||||||
|
sql2java.put(Types.LONGNVARCHAR,String.class);
|
||||||
|
sql2java.put(Types.DATE,java.sql.Date.class);
|
||||||
|
sql2java.put(Types.TIME,java.sql.Time.class);
|
||||||
|
sql2java.put(Types.TIMESTAMP,java.sql.Timestamp.class);
|
||||||
|
sql2java.put(Types.BLOB,byte[].class);
|
||||||
|
sql2java.put(Types.CLOB,char[].class);
|
||||||
|
sql2java.put(Types.ARRAY,java.sql.Array.class);
|
||||||
|
sql2java.put(Types.JAVA_OBJECT,Object.class);
|
||||||
|
return sql2java;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Returns back java class for given id and or name.
|
||||||
|
* The name is not used in default implementation.
|
||||||
|
* @param typeid
|
||||||
|
*/
|
||||||
|
public Class<?> getJavaType(int typeid) {
|
||||||
|
Class<?> ret=getSQL2Java().get(typeid);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This method will correct cases when sqltype is varchar (12) but type name is date or similar.
|
||||||
|
* @param sqltype
|
||||||
|
* @param type_name
|
||||||
|
* @return tries to promote sqltype given type name to something more specific.
|
||||||
|
*/
|
||||||
|
public int getTypeId(int sqltype,String type_name){
|
||||||
|
if(type_name==null) return sqltype;
|
||||||
|
type_name=type_name.toLowerCase();
|
||||||
|
if(sqltype==Types.VARCHAR || sqltype==Types.CHAR){
|
||||||
|
if(type_name.equals("date")) sqltype=Types.DATE;
|
||||||
|
if(type_name.equals("time")) sqltype=Types.TIME;
|
||||||
|
if(type_name.equals("datetime")) sqltype=Types.TIMESTAMP;
|
||||||
|
}
|
||||||
|
return sqltype;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param cls
|
||||||
|
* @param createParams
|
||||||
|
* @return SQL type given java class and create params
|
||||||
|
*/
|
||||||
|
public int getTypeId(Class<?> cls,String createParams){
|
||||||
|
int ret=getJava2SQL().get(cls);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
public String getTypeName(Class<?> cls,String createParams){
|
||||||
|
int id=this.getTypeId(cls, createParams);
|
||||||
|
String ret = JDBCType.valueOf(id).getName();
|
||||||
|
if(ret==null) return null;
|
||||||
|
String protocol=url.getProtocol();
|
||||||
|
if(protocol.contains(":sqlserver")){
|
||||||
|
if("boolean".equalsIgnoreCase(ret)) ret="BIT";
|
||||||
|
if("timestamp".equalsIgnoreCase(ret)) ret="DATETIME";
|
||||||
|
if("double".equalsIgnoreCase(ret)) ret="float";
|
||||||
|
if("float".equalsIgnoreCase(ret)) ret="real";
|
||||||
|
}
|
||||||
|
if(protocol.contains(":postgre")){
|
||||||
|
if("varbinary".equalsIgnoreCase(ret)) ret="bytea";
|
||||||
|
if("double".equalsIgnoreCase(ret)) ret="double precision";
|
||||||
|
}
|
||||||
|
if("varchar".equalsIgnoreCase(ret) && (createParams!=null && !createParams.isEmpty())){
|
||||||
|
long size=Long.parseLong(createParams);
|
||||||
|
if(protocol.contains(":sqlserver")) ret=size>8000?ret.concat("(").concat("MAX").concat(")"):ret.concat("(").concat(String.valueOf(size)).concat(")");
|
||||||
|
else if(protocol.contains(":oracle")) ret=size>2000?"CLOB":ret.concat("(").concat(String.valueOf(size)).concat(")");
|
||||||
|
else if(protocol.contains(":mysql")) ret=size>Character.MAX_VALUE?"TEXT":ret.concat("(").concat(String.valueOf(size)).concat(")");
|
||||||
|
else if(protocol.contains(":h2")) ret=size>Integer.MAX_VALUE?"CLOB":ret.concat("(").concat(String.valueOf(size)).concat(")");
|
||||||
|
else if(protocol.contains(":postgre")) ret=size>Character.MAX_VALUE?"TEXT":ret.concat("(").concat(String.valueOf(size)).concat(")");
|
||||||
|
else ret=(size>Character.MAX_VALUE)?"CLOB":ret.concat("(").concat(String.valueOf(size)).concat(")");
|
||||||
|
}
|
||||||
|
String args=null;
|
||||||
|
if(ret.indexOf('(')==-1 && createParams!=null && !createParams.isEmpty()){
|
||||||
|
if("decimal".equalsIgnoreCase(ret)) args=createParams;
|
||||||
|
if("numeric".equalsIgnoreCase(ret)) args=createParams;
|
||||||
|
}
|
||||||
|
if(args!=null){
|
||||||
|
ret=ret.concat("(").concat(args).concat(")");
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,208 @@
|
|||||||
|
package com.reliancy.dbo;
|
||||||
|
|
||||||
|
import java.io.Closeable;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import com.reliancy.util.Handy;
|
||||||
|
|
||||||
|
/** Helper object which impleents DBO saving. It manages the recipe and the prepared statmenet.
|
||||||
|
* Also keeps track of which fields are sent down to DB.
|
||||||
|
* The writer does the work in flush method during which it exhausts the items. While in flush it
|
||||||
|
* will disable autocommit and enable it at the end. We could call flush multiple times to send multiple
|
||||||
|
* batches down to DB.
|
||||||
|
* Initially we would ctor with Action object but actually we need to generate writes for different entities
|
||||||
|
* especially in inheritance cases.
|
||||||
|
*/
|
||||||
|
public class SQLWriter implements Closeable{
|
||||||
|
protected final Entity entity;
|
||||||
|
protected final SQLTerminal terminal;
|
||||||
|
protected final SQLWriter base; /// used for nesting
|
||||||
|
protected final ArrayList<Field> supplied=new ArrayList<Field>();
|
||||||
|
protected final ArrayList<Field> generated=new ArrayList<Field>();
|
||||||
|
protected String insertSQL;
|
||||||
|
protected String updateSQL;
|
||||||
|
protected Connection external;
|
||||||
|
protected PreparedStatement insertStmt;
|
||||||
|
protected PreparedStatement updateStmt;
|
||||||
|
protected int itemsInserted;
|
||||||
|
protected int itemsUpdated;
|
||||||
|
protected Exception error;
|
||||||
|
|
||||||
|
public SQLWriter(Entity ent,SQLTerminal t) {
|
||||||
|
entity=ent;
|
||||||
|
terminal=t;
|
||||||
|
base=(entity.getBase()!=null)?new SQLWriter(entity.getBase(),t):null;
|
||||||
|
// we select proper fields for this entity
|
||||||
|
FieldSlice slice=new FieldSlice(entity).including(Field.FLAG_STORABLE); // includes all even autoincrement
|
||||||
|
while(slice.hasNext()){
|
||||||
|
Field f=slice.next();
|
||||||
|
Entity e=slice.nextEntity();
|
||||||
|
if(e!=entity) continue; // skip if not part of this entity
|
||||||
|
if(f.isAutoIncrement()){
|
||||||
|
generated.add(f);
|
||||||
|
}else{
|
||||||
|
supplied.add(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public String compileInsertRecipe(){
|
||||||
|
if(insertSQL!=null) return insertSQL;
|
||||||
|
SQL buf=new SQL(terminal);
|
||||||
|
buf.insert(entity,supplied);
|
||||||
|
insertSQL=buf.toString();
|
||||||
|
return insertSQL;
|
||||||
|
}
|
||||||
|
public String compileUpdateRecipe(){
|
||||||
|
if(updateSQL!=null) return updateSQL;
|
||||||
|
SQL buf=new SQL(terminal);
|
||||||
|
buf.update(entity,supplied);
|
||||||
|
updateSQL=buf.toString();
|
||||||
|
return updateSQL;
|
||||||
|
}
|
||||||
|
public boolean isLinkExternal(){
|
||||||
|
return external!=null;
|
||||||
|
}
|
||||||
|
public SQLWriter setExternalLink(Connection link){
|
||||||
|
external=link;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
protected Connection getExternalLink(){
|
||||||
|
return external;
|
||||||
|
}
|
||||||
|
protected Connection getInternalLink(){
|
||||||
|
try{
|
||||||
|
if(insertStmt!=null) return insertStmt.getConnection();
|
||||||
|
if(updateStmt!=null) return updateStmt.getConnection();
|
||||||
|
}catch(SQLException ex){
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
public SQLWriter open() throws SQLException{
|
||||||
|
Connection link=isLinkExternal()?getExternalLink():terminal.getConnection();
|
||||||
|
if(base!=null) base.setExternalLink(link).open(); // definitely external link for base
|
||||||
|
String inSql=compileInsertRecipe();
|
||||||
|
String upSql=compileUpdateRecipe();
|
||||||
|
//System.out.println("INS:"+inSql);
|
||||||
|
//System.out.println("UPD:"+upSql);
|
||||||
|
String[] genkeys=new String[generated.size()];
|
||||||
|
for(int i=0;i<generated.size();i++){
|
||||||
|
Field f=generated.get(i);
|
||||||
|
genkeys[i]=f.getName();
|
||||||
|
}
|
||||||
|
insertStmt=link.prepareStatement(inSql,genkeys);
|
||||||
|
updateStmt=link.prepareStatement(upSql);
|
||||||
|
//result=prep.executeQuery();
|
||||||
|
//if(link.getAutoCommit()==false) link.commit();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException{
|
||||||
|
if(base!=null) base.close(); // since link is external it will not close link just the rest
|
||||||
|
Connection link=getInternalLink();
|
||||||
|
if(insertStmt!=null){
|
||||||
|
try{
|
||||||
|
insertStmt.close();
|
||||||
|
}catch(SQLException ex){
|
||||||
|
if(error==null) error=ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(updateStmt!=null){
|
||||||
|
try{
|
||||||
|
updateStmt.close();
|
||||||
|
}catch(SQLException ex){
|
||||||
|
if(error==null) error=ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try{
|
||||||
|
if(link!=null && external!=link) link.close();
|
||||||
|
external=null;
|
||||||
|
}catch(SQLException ex){
|
||||||
|
if(error==null) error=ex;
|
||||||
|
}
|
||||||
|
if(error!=null){
|
||||||
|
if(error instanceof IOException) throw (IOException)error;
|
||||||
|
else throw new IOException(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
public void flush(Iterator<DBO> items) throws SQLException {
|
||||||
|
Connection link=isLinkExternal()?getExternalLink():getInternalLink();
|
||||||
|
boolean autocommited=link.getAutoCommit();
|
||||||
|
try{
|
||||||
|
link.setAutoCommit(false);
|
||||||
|
while(items.hasNext()){
|
||||||
|
DBO rec=items.next();
|
||||||
|
writeRecord(rec);
|
||||||
|
}
|
||||||
|
if(!link.getAutoCommit()){
|
||||||
|
link.commit();
|
||||||
|
}
|
||||||
|
}catch(SQLException ex){
|
||||||
|
if(!link.getAutoCommit()){
|
||||||
|
link.rollback();
|
||||||
|
}
|
||||||
|
throw ex;
|
||||||
|
}finally{
|
||||||
|
link.setAutoCommit(autocommited);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This calls one update/insert. It can and is called from outside in case of nesting when link is external.
|
||||||
|
* @param rec
|
||||||
|
* @throws SQLException
|
||||||
|
*/
|
||||||
|
public boolean writeRecord(DBO rec) throws SQLException{
|
||||||
|
if(base!=null) base.writeRecord(rec); // save the superclass first
|
||||||
|
// select mode
|
||||||
|
int pindex=0;
|
||||||
|
Field pk=entity.getPk();
|
||||||
|
boolean pk_owned=entity.isOwned(pk);
|
||||||
|
PreparedStatement stmt=null;
|
||||||
|
if(rec.getStatus()==DBO.Status.NEW){
|
||||||
|
stmt=insertStmt;
|
||||||
|
// need to inject pk here is not owned
|
||||||
|
if(!pk_owned) stmt.setObject(++pindex,pk.get(rec,null),terminal.getTypeId(pk.getType(),pk.getTypeParams()));
|
||||||
|
}
|
||||||
|
if(rec.getStatus()==DBO.Status.USED){
|
||||||
|
stmt=updateStmt;
|
||||||
|
// update has a pk condition for sure
|
||||||
|
stmt.setObject(supplied.size()+1,pk.get(rec,null),terminal.getTypeId(pk.getType(),pk.getTypeParams()));
|
||||||
|
}
|
||||||
|
if(stmt==null) return false;
|
||||||
|
// copy values
|
||||||
|
for(int index=0;index<supplied.size();index++){
|
||||||
|
Field f=supplied.get(index);
|
||||||
|
pindex+=1;
|
||||||
|
int tid=terminal.getTypeId(f.getType(),f.getTypeParams());
|
||||||
|
Object val=f.get(rec,null);
|
||||||
|
//System.out.println("Param:"+pindex+":"+f.getName()+":"+val);
|
||||||
|
stmt.setObject(pindex,val,tid);
|
||||||
|
}
|
||||||
|
int ucode=stmt.executeUpdate();
|
||||||
|
//System.out.println("UCode:"+ucode);
|
||||||
|
if(rec.getStatus()==DBO.Status.NEW){
|
||||||
|
this.itemsInserted+=ucode;
|
||||||
|
if(ucode>0 && !generated.isEmpty()){
|
||||||
|
try (ResultSet keys = stmt.getGeneratedKeys()) {
|
||||||
|
if(keys.next()){
|
||||||
|
for(int i=0;i<generated.size();i++){
|
||||||
|
Field f=generated.get(i);
|
||||||
|
Object autoval=keys.getObject(i+1);
|
||||||
|
f.set(rec,autoval);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(rec.getStatus()==DBO.Status.USED){
|
||||||
|
this.itemsUpdated+=ucode;
|
||||||
|
}
|
||||||
|
return ucode>0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package com.reliancy.dbo;
|
||||||
|
|
||||||
|
import java.io.Closeable;
|
||||||
|
import java.util.Iterator;
|
||||||
|
/** Iterator interface suitable for dbo resultsets.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface SiphonIterator<T> extends Iterator<T>, Closeable {
|
||||||
|
}
|
||||||
@@ -25,6 +25,13 @@ public interface Terminal {
|
|||||||
public default Terminal meta(Entity ent){
|
public default Terminal meta(Entity ent){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
public default <T extends DBO> T load(Class<T> cls,Object...id) throws IOException {
|
||||||
|
Entity ent=Entity.recall(cls);
|
||||||
|
String sig="/"+ent.getName()+"/load";
|
||||||
|
try(Action act=begin(sig).load(ent).limit(1).if_pk(id).execute()){
|
||||||
|
return (T)act.first();
|
||||||
|
}
|
||||||
|
}
|
||||||
public default DBO load(Entity ent,Object...id) throws IOException {
|
public default DBO load(Entity ent,Object...id) throws IOException {
|
||||||
String sig="/"+ent.getName()+"/load";
|
String sig="/"+ent.getName()+"/load";
|
||||||
try(Action act=begin(sig).load(ent).limit(1).if_pk(id).execute()){
|
try(Action act=begin(sig).load(ent).limit(1).if_pk(id).execute()){
|
||||||
@@ -39,6 +46,7 @@ public interface Terminal {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
public default boolean delete(DBO rec) throws IOException {
|
public default boolean delete(DBO rec) throws IOException {
|
||||||
|
if(rec==null) return false;
|
||||||
Entity ent=rec.getType();
|
Entity ent=rec.getType();
|
||||||
String sig="/"+ent.getName()+"/delete";
|
String sig="/"+ent.getName()+"/delete";
|
||||||
try(Action act=begin(sig).delete(ent).setItems(rec).execute()){
|
try(Action act=begin(sig).delete(ent).setItems(rec).execute()){
|
||||||
|
|||||||
@@ -47,8 +47,13 @@ public final class HTTP {
|
|||||||
public static String guess_mime(Object ret) {
|
public static String guess_mime(Object ret) {
|
||||||
if(ret instanceof CharSequence){
|
if(ret instanceof CharSequence){
|
||||||
CharSequence retstr=(CharSequence)ret;
|
CharSequence retstr=(CharSequence)ret;
|
||||||
if(retstr.length()>0 && retstr.charAt(0)=='<') return "text/html";
|
for(int index=0;index<retstr.length();index++){
|
||||||
if(retstr.length()>0 && "{[".indexOf(retstr.charAt(0))!=-1) return "application/json";
|
char ch=retstr.charAt(index);
|
||||||
|
if(Character.isWhitespace(ch)) continue;
|
||||||
|
if(ch=='<') return "text/html";
|
||||||
|
if(ch=='{' || ch=='[') return "application/json";
|
||||||
|
break;
|
||||||
|
}
|
||||||
return "text/plain";
|
return "text/plain";
|
||||||
}
|
}
|
||||||
if(ret instanceof byte[]){
|
if(ret instanceof byte[]){
|
||||||
|
|||||||
@@ -206,7 +206,7 @@ public class Router extends AbstractHandler{
|
|||||||
String ret="";
|
String ret="";
|
||||||
try {
|
try {
|
||||||
Template.search_path("./var",SecurityPolicy.class);
|
Template.search_path("./var",SecurityPolicy.class);
|
||||||
Template t=Template.find("resources/login.j2");
|
Template t=Template.find("/templates/login.hbs");
|
||||||
System.out.println("Template:"+t);
|
System.out.println("Template:"+t);
|
||||||
ret = t.render(context).toString();
|
ret = t.render(context).toString();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
{% extends "base.j2" %}
|
|
||||||
{% block content %}
|
|
||||||
<div>Hello from code: {{name}}!</div>
|
|
||||||
{% endblock %}
|
|
||||||
@@ -1,16 +1,23 @@
|
|||||||
package com.reliancy.rec;
|
package com.reliancy.rec;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.ListIterator;
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/** Base class of meta objects.
|
/** Base class of meta objects.
|
||||||
* We use it to describe certain meta information. We derive from it Slot.
|
* We use it to describe certain meta information. We derive from it Slot.
|
||||||
* We define keys list of slots on the header level to describe slots.
|
* We define keys list of slots on the header level to describe sub-slots.
|
||||||
|
*
|
||||||
|
* This class describes structure of Fields or Entities via the keys array of slots.
|
||||||
|
* Additionally we provide a number of methods to locate, set or get or remove or add slots.
|
||||||
|
* However slots could reside in other places such as base classes and so getOwnSlots will return a
|
||||||
|
* bare list of slots in this object while all other methods will take into account other sources.
|
||||||
|
* We do this to stay consistent at Rec level when Hdr inheritance comes into play.
|
||||||
*/
|
*/
|
||||||
public class Hdr {
|
public class Hdr {
|
||||||
public static final int FLAG_ARRAY =0x0001;
|
public static final int FLAG_ARRAY =0x0001;
|
||||||
public static final int FLAG_CHANGED =0x0002;
|
public static final int FLAG_CHANGED =0x0002;
|
||||||
public static final int FLAG_HIDDEN =0x0004;
|
public static final int FLAG_STORABLE =0x0004;
|
||||||
public static final int FLAG_LOCKED =0x0008;
|
public static final int FLAG_LOCKED =0x0008;
|
||||||
int flags;
|
int flags;
|
||||||
String name;
|
String name;
|
||||||
@@ -30,8 +37,11 @@ public class Hdr {
|
|||||||
@Override
|
@Override
|
||||||
public String toString(){
|
public String toString(){
|
||||||
StringBuilder ret=new StringBuilder();
|
StringBuilder ret=new StringBuilder();
|
||||||
ret.append("{").append("flags:").append(flags).append(",name:").append(name);
|
ret.append(name).append(":");
|
||||||
ret.append(",dim:").append(keys.size()).append("}");
|
ret.append("{")
|
||||||
|
.append("flags:").append(flags)
|
||||||
|
.append(",dim:").append(count())
|
||||||
|
.append("}");
|
||||||
return ret.toString();
|
return ret.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,6 +63,9 @@ public class Hdr {
|
|||||||
public void setType(Class<?> type) {
|
public void setType(Class<?> type) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
}
|
}
|
||||||
|
public int getFlags(){
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
public Hdr raiseFlags(int f){
|
public Hdr raiseFlags(int f){
|
||||||
flags|=f;
|
flags|=f;
|
||||||
return this;
|
return this;
|
||||||
@@ -67,36 +80,51 @@ public class Hdr {
|
|||||||
public <T extends Hdr> T castAs(Class<T> clazz){
|
public <T extends Hdr> T castAs(Class<T> clazz){
|
||||||
return clazz.cast(this);
|
return clazz.cast(this);
|
||||||
}
|
}
|
||||||
public int findSlot(String name){
|
public List<Slot> getOwnSlots(){
|
||||||
return findSlot(name,0);
|
return keys;
|
||||||
}
|
}
|
||||||
public int findSlot(String name,int ofs){
|
public boolean isOwned(Slot s){
|
||||||
ListIterator<Slot> it=keys.listIterator(ofs);
|
return keys.contains(s);
|
||||||
|
}
|
||||||
|
public Iterator<Slot> iterator(int offset){
|
||||||
|
return keys.listIterator(offset);
|
||||||
|
}
|
||||||
|
public int indexOf(String name){
|
||||||
|
return indexOf(name,0);
|
||||||
|
}
|
||||||
|
public int indexOf(String name,int ofs){
|
||||||
|
Iterator<Slot> it=iterator(ofs);
|
||||||
|
int index=-1;
|
||||||
while(it.hasNext()){
|
while(it.hasNext()){
|
||||||
int index=it.nextIndex();
|
index+=1;
|
||||||
Slot e=it.next();
|
Slot e=it.next();
|
||||||
if(e.getName().equalsIgnoreCase(name)) return index;
|
//if(e.getName().equalsIgnoreCase(name)) return index;
|
||||||
|
if(e.equals(name)) return index;
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
public int findSlot(Slot s,int ofs){
|
public int indexOf(Slot s,int ofs){
|
||||||
ListIterator<Slot> it=keys.listIterator(ofs);
|
Iterator<Slot> it=iterator(ofs);
|
||||||
|
int index=-1;
|
||||||
while(it.hasNext()){
|
while(it.hasNext()){
|
||||||
int index=it.nextIndex();
|
index+=1;
|
||||||
Slot e=it.next();
|
Slot e=it.next();
|
||||||
if(e==s) return index;
|
if(e==s) return index;
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
/**
|
public Slot makeSlot(String name){
|
||||||
|
return new Slot(name);
|
||||||
|
}
|
||||||
|
/**
|
||||||
* this version will get or create a slot by given name.
|
* this version will get or create a slot by given name.
|
||||||
* @param name
|
* @param name
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Slot getSlot(String name){
|
public Slot getSlot(String name,boolean make){
|
||||||
int index=findSlot(name);
|
int index=indexOf(name);
|
||||||
if(index<0){
|
if(index<0){
|
||||||
return new Slot(name);
|
return make?makeSlot(name):null;
|
||||||
}else{
|
}else{
|
||||||
return getSlot(index);
|
return getSlot(index);
|
||||||
}
|
}
|
||||||
@@ -116,11 +144,7 @@ public class Hdr {
|
|||||||
keys.set(index,s);
|
keys.set(index,s);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
public Slot[] slots(Slot... slots){
|
public int count(){
|
||||||
if(slots!=null && slots.length>0){
|
return keys.size();
|
||||||
keys.clear();
|
|
||||||
for(int i=0;i<slots.length;i++) keys.add(slots[i]);
|
|
||||||
}
|
|
||||||
return keys.toArray(new Slot[keys.size()]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,13 @@ public class JSON {
|
|||||||
public static final void writes(Rec rec,Appendable sink) throws IOException{
|
public static final void writes(Rec rec,Appendable sink) throws IOException{
|
||||||
JSONEncoder.encode(rec, sink);
|
JSONEncoder.encode(rec, sink);
|
||||||
}
|
}
|
||||||
|
public static final String toString(Rec rec){
|
||||||
|
StringBuffer buf=new StringBuffer();
|
||||||
|
try {
|
||||||
|
writes(rec,buf);
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -189,7 +189,7 @@ public class JSONEncoder{
|
|||||||
if (o != null) {
|
if (o != null) {
|
||||||
o.append(val.isArray()?"[":"{");
|
o.append(val.isArray()?"[":"{");
|
||||||
}
|
}
|
||||||
for (int i=0;i<val.count();i++) {
|
for (int i=0;i<val.count();i++) {
|
||||||
Slot k=val.getSlot(i);
|
Slot k=val.getSlot(i);
|
||||||
Object v=val.get(i);
|
Object v=val.get(i);
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ public class Obj implements Rec{
|
|||||||
if(s==null) throw new IllegalArgumentException("invalid key provided");
|
if(s==null) throw new IllegalArgumentException("invalid key provided");
|
||||||
if(isArray()) throw new IllegalStateException("array not mappable with:"+s.getName());
|
if(isArray()) throw new IllegalStateException("array not mappable with:"+s.getName());
|
||||||
int index=s.getPosition(); // try slot position
|
int index=s.getPosition(); // try slot position
|
||||||
if(index<0) index=meta.findSlot(s.getName());// fall back to search if slot not set
|
if(index<0) index=meta.indexOf(s.getName());// fall back to search if slot not set
|
||||||
if(index<0){
|
if(index<0){
|
||||||
values.add(val);
|
values.add(val);
|
||||||
meta.addSlot(s);
|
meta.addSlot(s);
|
||||||
@@ -138,14 +138,14 @@ public class Obj implements Rec{
|
|||||||
if(s==null) throw new IllegalArgumentException("invalid key provided");
|
if(s==null) throw new IllegalArgumentException("invalid key provided");
|
||||||
//if(keys==null) throw new IllegalStateException("array not mappable with:"+s.getName());
|
//if(keys==null) throw new IllegalStateException("array not mappable with:"+s.getName());
|
||||||
int index=s.getPosition(); // try slot position
|
int index=s.getPosition(); // try slot position
|
||||||
if(index<0 && !isArray()) index=meta.findSlot(s.getName());// fall back to search if slot not set
|
if(index<0 && !isArray()) index=meta.indexOf(s.getName());// fall back to search if slot not set
|
||||||
return index<0?def:values.get(index);
|
return index<0?def:values.get(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Rec remove(Slot s) {
|
public Rec remove(Slot s) {
|
||||||
int index=s.getPosition(); // try slot position
|
int index=s.getPosition(); // try slot position
|
||||||
if(index<0 && !isArray()) index=meta.findSlot(s.getName());// fall back to search if slot not set
|
if(index<0 && !isArray()) index=meta.indexOf(s.getName());// fall back to search if slot not set
|
||||||
if(index>=0) remove(index);
|
if(index>=0) remove(index);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ public interface Rec extends Vec{
|
|||||||
public Rec remove(Slot s);
|
public Rec remove(Slot s);
|
||||||
public default Slot getSlot(String name){
|
public default Slot getSlot(String name){
|
||||||
Hdr m=meta();
|
Hdr m=meta();
|
||||||
return m!=null?m.getSlot(name):null;
|
return m!=null?m.getSlot(name,true):null;
|
||||||
}
|
}
|
||||||
public default Slot getSlot(int pos){
|
public default Slot getSlot(int pos){
|
||||||
Hdr m=meta();
|
Hdr m=meta();
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ public class Slot extends Hdr {
|
|||||||
Object getInitalValue(Slot s,Rec rec);
|
Object getInitalValue(Slot s,Rec rec);
|
||||||
}
|
}
|
||||||
public static final Initializer DEFAULT_INITIALIZER=new Initializer(){
|
public static final Initializer DEFAULT_INITIALIZER=new Initializer(){
|
||||||
public Object getInitalValue(Slot s,Rec rec) {return s.getDefaultValue();}
|
public Object getInitalValue(Slot s,Rec rec) {return s.getInitValue();}
|
||||||
};
|
};
|
||||||
int position;
|
int position;
|
||||||
Object defaultValue;
|
Object defaultValue;
|
||||||
@@ -25,23 +25,29 @@ public class Slot extends Hdr {
|
|||||||
this.position=-1;
|
this.position=-1;
|
||||||
this.initValue=DEFAULT_INITIALIZER;
|
this.initValue=DEFAULT_INITIALIZER;
|
||||||
}
|
}
|
||||||
|
public boolean equals(String str){
|
||||||
|
return name.equalsIgnoreCase(str);
|
||||||
|
}
|
||||||
public int getPosition() {
|
public int getPosition() {
|
||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
public void setPosition(int position) {
|
public Slot setPosition(int position) {
|
||||||
this.position = position;
|
this.position = position;
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
public Object getDefaultValue() {
|
public Object getInitValue() {
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
public void setDefaultValue(Object defaultValue) {
|
public Slot setInitValue(Object defaultValue) {
|
||||||
this.defaultValue = defaultValue;
|
this.defaultValue = defaultValue;
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
public Initializer getInitValue() {
|
public Initializer getInitVia() {
|
||||||
return initValue;
|
return initValue;
|
||||||
}
|
}
|
||||||
public void setInitValue(Initializer initValue) {
|
public Slot setInitVia(Initializer initValue) {
|
||||||
this.initValue = initValue;
|
this.initValue = initValue;
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
public int toString(Object val, StringBuilder buf) {
|
public int toString(Object val, StringBuilder buf) {
|
||||||
int length0=buf.length();
|
int length0=buf.length();
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
package com.reliancy.util;
|
|
||||||
|
|
||||||
import java.io.Closeable;
|
|
||||||
import java.util.Iterator;
|
|
||||||
|
|
||||||
public interface CloseableIterator<T> extends Iterator<T>, Closeable {
|
|
||||||
}
|
|
||||||
@@ -45,7 +45,7 @@ public final class Handy {
|
|||||||
if(clazz.isAssignableFrom(val.getClass())) return clazz; // we are assignable
|
if(clazz.isAssignableFrom(val.getClass())) return clazz; // we are assignable
|
||||||
if(val instanceof String){
|
if(val instanceof String){
|
||||||
String value=(String) val;
|
String value=(String) val;
|
||||||
if(value.isBlank() || value.equals("''") || value.equals("\"\"")) return null;
|
if(value.isEmpty() || value.equals("''") || value.equals("\"\"")) return null;
|
||||||
if( Boolean.class==( clazz ) || boolean.class==( clazz ) ) return Boolean.parseBoolean( value );
|
if( Boolean.class==( clazz ) || boolean.class==( clazz ) ) return Boolean.parseBoolean( value );
|
||||||
if( Byte.class==( clazz ) || byte.class==( clazz ) ) return Byte.parseByte( value );
|
if( Byte.class==( clazz ) || byte.class==( clazz ) ) return Byte.parseByte( value );
|
||||||
if( Short.class==( clazz ) || short.class==( clazz ) ) return Short.parseShort( value );
|
if( Short.class==( clazz ) || short.class==( clazz ) ) return Short.parseShort( value );
|
||||||
@@ -454,5 +454,31 @@ public final class Handy {
|
|||||||
all.toArray(ret);
|
all.toArray(ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
public static String toString(Object...args){
|
||||||
|
StringBuilder buf=new StringBuilder();
|
||||||
|
if(args.length>1){
|
||||||
|
buf.append("[");
|
||||||
|
for(int i=0;i<args.length;i++) buf.append(i==0?"":",").append(toString(args[i]));
|
||||||
|
buf.append("]");
|
||||||
|
}else if(args.length==1){
|
||||||
|
Object arg=args[0];
|
||||||
|
if(arg instanceof Iterable){
|
||||||
|
java.util.Iterator<?> it=((Iterable<?>)arg).iterator();
|
||||||
|
buf.append("[");
|
||||||
|
while(it.hasNext()) buf.append(buf.length()>1?",":"").append(it.next());
|
||||||
|
buf.append("]");
|
||||||
|
}else
|
||||||
|
if(arg instanceof java.util.Map){
|
||||||
|
java.util.Map<?,?> marg=(Map<?,?>) arg;
|
||||||
|
buf.append("{");
|
||||||
|
for(java.util.Map.Entry<?,?>e:marg.entrySet()){
|
||||||
|
buf.append(e.getKey().toString()).append(":").append(toString(e.getValue()));
|
||||||
|
}
|
||||||
|
buf.append("}");
|
||||||
|
}else{
|
||||||
|
buf.append(String.valueOf(arg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,28 @@
|
|||||||
package com.reliancy.util;
|
package com.reliancy.util;
|
||||||
|
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import com.github.jknack.handlebars.Handlebars;
|
||||||
|
import com.github.jknack.handlebars.io.AbstractTemplateLoader;
|
||||||
|
import com.github.jknack.handlebars.io.TemplateSource;
|
||||||
|
import com.github.jknack.handlebars.io.URLTemplateSource;
|
||||||
|
|
||||||
|
/*
|
||||||
import com.hubspot.jinjava.Jinjava;
|
import com.hubspot.jinjava.Jinjava;
|
||||||
import com.hubspot.jinjava.interpret.JinjavaInterpreter;
|
import com.hubspot.jinjava.interpret.JinjavaInterpreter;
|
||||||
import com.hubspot.jinjava.loader.ResourceLocator;
|
import com.hubspot.jinjava.loader.ResourceLocator;
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We will manage template rendering thru this class.
|
* We will manage template rendering thru this class.
|
||||||
*/
|
*/
|
||||||
public class Template {
|
public class Template {
|
||||||
|
/*
|
||||||
static Jinjava jinjava;
|
static Jinjava jinjava;
|
||||||
static{
|
static{
|
||||||
jinjava = new Jinjava();
|
jinjava = new Jinjava();
|
||||||
@@ -32,6 +40,27 @@ public class Template {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
public static class HBLoader extends AbstractTemplateLoader{
|
||||||
|
public HBLoader(){
|
||||||
|
this.setPrefix("/templates/");
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public TemplateSource sourceAt(String location) throws IOException {
|
||||||
|
String fullpath=this.resolve(location);
|
||||||
|
URL loc=Resources.findFirst(null,fullpath,Template.search_path);
|
||||||
|
System.out.println(location+":"+loc+":"+fullpath);
|
||||||
|
if (loc == null) {
|
||||||
|
Logger.getLogger(Template.class.getSimpleName()).warning("Missing template"+fullpath);
|
||||||
|
throw new FileNotFoundException(location);
|
||||||
|
}
|
||||||
|
return new URLTemplateSource(location,loc);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
static Handlebars handlebars = new Handlebars(new HBLoader());
|
||||||
|
|
||||||
static Object[] search_path;
|
static Object[] search_path;
|
||||||
static HashMap<String,Template> cache=new HashMap<>();
|
static HashMap<String,Template> cache=new HashMap<>();
|
||||||
/** renders a template to string, possibly locates it first.
|
/** renders a template to string, possibly locates it first.
|
||||||
@@ -56,7 +85,6 @@ public class Template {
|
|||||||
Template ret=cache.get(path);
|
Template ret=cache.get(path);
|
||||||
if(ret!=null) return ret;
|
if(ret!=null) return ret;
|
||||||
URL loc=Resources.findFirst(null, path, (sp!=null && sp.length>0?sp:search_path));
|
URL loc=Resources.findFirst(null, path, (sp!=null && sp.length>0?sp:search_path));
|
||||||
System.out.println("TLOCL:"+loc);
|
|
||||||
if(loc==null) return null;
|
if(loc==null) return null;
|
||||||
ret=new Template(loc);
|
ret=new Template(loc);
|
||||||
cache.put(path,ret);
|
cache.put(path,ret);
|
||||||
@@ -66,7 +94,7 @@ public class Template {
|
|||||||
if(sp!=null && sp.length>0) search_path=sp;
|
if(sp!=null && sp.length>0) search_path=sp;
|
||||||
return search_path;
|
return search_path;
|
||||||
}
|
}
|
||||||
|
com.github.jknack.handlebars.Template recipe;
|
||||||
final URL location;
|
final URL location;
|
||||||
String source;
|
String source;
|
||||||
public Template(URL location){
|
public Template(URL location){
|
||||||
@@ -88,7 +116,11 @@ public class Template {
|
|||||||
}
|
}
|
||||||
public CharSequence render(Map<String,?> context) throws IOException{
|
public CharSequence render(Map<String,?> context) throws IOException{
|
||||||
if(source==null) load();
|
if(source==null) load();
|
||||||
String ret = jinjava.render(source, context);
|
//String ret = jinjava.render(source, context);
|
||||||
|
if(recipe==null){
|
||||||
|
recipe=handlebars.compileInline(source);
|
||||||
|
}
|
||||||
|
String ret=recipe.apply(context);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
{{#partial "content"}}
|
||||||
|
Calling base
|
||||||
|
{{/partial}}
|
||||||
|
{{> base}}
|
||||||
@@ -4,25 +4,67 @@ import java.sql.Connection;
|
|||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.Statement;
|
import java.sql.Statement;
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import com.reliancy.rec.JSON;
|
||||||
|
|
||||||
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
public class TerminalTest {
|
public class TerminalTest {
|
||||||
|
@Entity.Info(
|
||||||
|
name="dbo.Maps"
|
||||||
|
)
|
||||||
public static class Maps extends DBO{
|
public static class Maps extends DBO{
|
||||||
public static Field map_id=new Field("Map_id",Integer.class);
|
public static Field map_id=Field.Int("Map_id").setPk(true);
|
||||||
public static Field map_name=new Field("Map_name",String.class);
|
public static Field map_name=Field.Str("Map_name");
|
||||||
|
public static Field created=Field.DateTime("Created");
|
||||||
|
public static Field active=Field.Bool("Active");
|
||||||
static{
|
static{
|
||||||
Entity.publish(Maps.class);
|
//Entity.publish(Maps.class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@Entity.Info(
|
||||||
|
name="public.securable"
|
||||||
|
)
|
||||||
|
public static class Securable extends DBO{
|
||||||
|
public static Field id=Field.Int("id").setPk(true).setAutoIncrement(true);
|
||||||
|
public static Field kind=Field.Str("kind");
|
||||||
|
public static Field name=Field.Str("name");
|
||||||
|
public static Field display_name=Field.Str("display_name");
|
||||||
|
public static Field created=Field.DateTime("created_on");
|
||||||
|
public static Field is_essential=Field.Bool("is_essential");
|
||||||
|
static{
|
||||||
|
//Entity.publish(Maps.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity.Info(
|
||||||
|
name="public.product"
|
||||||
|
)
|
||||||
|
public static class Product extends Securable{
|
||||||
|
public static Field valid_since=Field.DateTime("valid_since");
|
||||||
|
public static Field valid_until=Field.DateTime("valid_until");
|
||||||
|
public static Field short_info=Field.Str("short_info");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static SQLTerminal t;
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void beforeAllTestMethods() {
|
||||||
|
System.out.println("Invoked once before all test methods");
|
||||||
|
String url="jdbc:postgresql://postgres:Ramudin99@bigbang:5432/Test";
|
||||||
|
t=new SQLTerminal(url);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Plain CRUD
|
* jdbc connectivity
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
* @throws SQLException
|
* @throws SQLException
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void connection() throws IOException, SQLException{
|
public void connection() throws IOException, SQLException{
|
||||||
String url="jdbc:postgresql://postgres:Ramudin99@bigbang:5432/Test";
|
|
||||||
SQLTerminal t=new SQLTerminal(url);
|
|
||||||
try(Connection c=t.getConnection()){
|
try(Connection c=t.getConnection()){
|
||||||
System.out.println("Connection:"+c);
|
System.out.println("Connection:"+c);
|
||||||
try (Statement stmt = c.createStatement()) {
|
try (Statement stmt = c.createStatement()) {
|
||||||
@@ -38,5 +80,38 @@ public class TerminalTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@Test
|
||||||
|
public void simpleCRUD() throws IOException, SQLException{
|
||||||
|
System.out.println("SimpleCRUD");
|
||||||
|
try(Action act=t.begin().load(Maps.class).execute()){
|
||||||
|
for(DBO o:act){
|
||||||
|
System.out.println("DBO:"+o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Entity.retract(Maps.class);
|
||||||
|
}
|
||||||
|
@Test
|
||||||
|
public void complexCRUD() throws IOException, SQLException{
|
||||||
|
System.out.println("ComplexCRUD");
|
||||||
|
try(Action act=t.begin().load(Product.class).execute()){
|
||||||
|
for(DBO o:act){
|
||||||
|
System.out.println("DBO:"+o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Product p=new Product();
|
||||||
|
p.setStatus(DBO.Status.USED);
|
||||||
|
Product.kind.set(p,Product.class.getSimpleName());
|
||||||
|
Product.name.set(p,"myproduct");
|
||||||
|
Product.created.set(p,new Date());
|
||||||
|
Product.short_info.set(p,"a sweet melody");
|
||||||
|
Product.display_name.set(p,"first entry");
|
||||||
|
System.out.println("P0:"+JSON.toString(p));
|
||||||
|
t.save(p);
|
||||||
|
System.out.println("P1:"+JSON.toString(p));
|
||||||
|
Product pp=t.load(Product.class, 35);
|
||||||
|
System.out.println("Returning:"+pp);
|
||||||
|
//t.delete(pp);
|
||||||
|
Entity.retract(Maps.class);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
-27
@@ -1,27 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Flask Template Example</title>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
|
|
||||||
<style type="text/css">
|
|
||||||
.container {
|
|
||||||
max-width: 500px;
|
|
||||||
padding-top: 100px;
|
|
||||||
}
|
|
||||||
h2 {color: red;}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="container">
|
|
||||||
<h2>This is part of my base template</h2>
|
|
||||||
<br>
|
|
||||||
{% block content %}{% endblock %}
|
|
||||||
<br>
|
|
||||||
<h2>This is part of my base template</h2>
|
|
||||||
</div>
|
|
||||||
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
|
|
||||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
Reference in New Issue
Block a user