How to add a semi colon ; automatically to each generated sql statement using jOOQ - sql

I'm trying to add a semi colon ; to every jOOQ generated sql statement as I'm writing multiple DDL and insert statement to an output file.
I found a similar question here suggesting using an ExecuteListener here https://jooq-user.narkive.com/6adKecpt/adding-semicolon-at-the-end-of-sql-statement.
My setup is now as follows (using Groovy):
private DSLContext createDSLContext() {
def configuration = new DefaultConfiguration()
configuration.settings = new Settings()
.withRenderFormatted(true)
.withRenderKeywordCase(RenderKeywordCase.LOWER)
.withRenderQuotedNames(RenderQuotedNames.ALWAYS)
.withStatementType(StatementType.STATIC_STATEMENT)
configuration.set(
new DefaultExecuteListenerProvider(new DefaultExecuteListener() {
#Override
void renderEnd(ExecuteContext ctx) {
ctx.sql(ctx.sql() + ";")
}
}),
new DefaultExecuteListenerProvider(new DefaultExecuteListener() {
#Override
void start(ExecuteContext ctx) {
println "YEAH!!!"
}
}))
// return configuration.dsl();
return DSL.using(configuration)
}
but is not adding the semi colon, nor is it getting in the renderEnd method at all.
I added another execute listener to print something at the start (as I have seen in other examples) but it is also never called..
My code looks like:
file.withWriter { writer ->
// Drop schema objects.
DEFAULT_SCHEMA.tables.each {
switch (it.type) {
case TABLE:
writer.writeLine(dsl.dropTableIfExists(it).SQL)
break
case VIEW:
writer.writeLine(dsl.dropViewIfExists(it).SQL)
break
}
}
writer.writeLine("")
// Create schema objects.
def ddlStatements = dsl.ddl(DEFAULT_SCHEMA)
ddlStatements.each {
writer.writeLine(it.SQL)
writer.writeLine("")
}
// Insert data.
def insert = dsl.insertInto(Tales.CUSTOMER).columns(Tales.CUSTOMER.fields())
customers.each {insert.values(it) }
writer.writeLine(insert.SQL)
}

The ExecuteListener lifecycle is only triggered when you execute your queries with jOOQ. You're not doing that, you're just calling Query.getSQL()
You could wrap your queries into DSLContext.queries(Query...), and jOOQ will separate the statements using ; when you call Queries.getSQL() when you call Queries.toString(). Of course, that's not reliable, the behaviour of toString() might change in the future, which is why it would make sense to offer methods like Queries.getSQL() and the likes: https://github.com/jOOQ/jOOQ/issues/11755
For the time being, why not just add the semi colon manually to the writer in your code?

Related

Regenerate source from Antlr4 ParseTree preserving whitespaces

I am able to use Java.g4 grammar and generate lexers and parsers. This grammar is used to get started. I have a ParseTree and I walk it and change whatever I want and write it back to a Java source code file. The ParseTree is not directly changed though.
So for example this is the code. But I also modify method names and add annotations to methods. In some cases I also remove method parameters
#Override
public void enterClassDeclaration(JavaParser.ClassDeclarationContext ctx) {
printer.write( intervals );
printer.writeList(importFilter );
ParseTree pt = ctx.getChild(1);
/*
The class name is changed by a visitor because
we get a ParseTree back
*/
pt.accept(new ParseTreeVisitor<Object>() {
#Override
public Object visitChildren(RuleNode ruleNode) {
return null;
}
#Override
public Object visitErrorNode(ErrorNode errorNode) {
return null;
}
#Override
public Object visit(ParseTree parseTree) {
return null;
}
#Override
public Object visitTerminal(TerminalNode terminalNode) {
String className = terminalNode.getText();
System.out.println("Name of the class is [ " + className + "]");
printer.writeText( classModifier.get() + " class " + NEW_CLASS_IDENTIFIER );
return null;
}
});
}
But I am not sure how to print the changed Java code while preserving all the original whitespaces.
How is that done ?
Update : It seems that the whitespaces and comments are there but not accessible easily. So it looks like I need to specifically keep track of them and write them along with the code. Not sure though.
So more specifically the code is this.
package x;
import java.util.Enumeration;
import java.util.*;
As I hit the first ImportDeclarationContext I need to store all the hidden space tokens. When I write this code back I want to include those spaces too.
Solution :
Don't skip but add to a HIDDEN channel
//
// Whitespace and comments
//
WS : [ \t\r\n\u000C]+ -> channel(HIDDEN)
;
COMMENT
: '/*' .*? '*/' -> channel(HIDDEN)
;
Use code like this to get them back
I use this to get the whitespaces and comments before each method. But it should be possible to get whitespaces from other places too. I think.
((CommonTokenStream) tokens).getHiddenTokensToLeft( classOrInterfaceModifierContext.getStart().getTokenIndex(),
Token.HIDDEN_CHANNEL);

How to skip value in config if it doesn't exist?

I am writing App, that need to read config at start. Some is not necessary for work.
class ParseConfig
{
string optionalkey;
//...
this()
{
this.optionalkey = config.getKey("key1");
}
//...
}
The problem that I need to find way to skip (do not try to find and parse) it if not exists and config. Now App try to parse config and show me error.
I found only one way - to wrap all in try-catch block, and if value can't be found in config in cantch block set it's to null.
What is the best way to do it?
I am using dini for config.
upd: (added example)
import std.stdio;
import std.path;
import std.file;
import dini;
void main()
{
string confpath = buildPath(getcwd, "config.ini");
if (!exists(confpath)) throw new Exception("ERROR: config.ini do not exists");
auto config = Ini.Parse(confpath);
try
{
string optionalkey;
if(config.getKey("optionalkey"))
{
optionalkey = config.getKey("optionalkey");
}
writeln(optionalkey); // nothing will shown, becouse exception
}
catch( Exception e)
{
writeln("Exception! :(");
writeln(e.msg);
}
}
Catching exception is one way, but it is not perfect (mainly if there will be many cases of optional configs). So better way is test if key exist:
class ParseConfig
{
string optionalkey;
//...
this()
{
this.optionalkey = config.hasKey("key1") ? config.getKey("key1") : "defaultValue";
}
//...
}
But ideal would be if dini has overload of getKey method so you can use something like this:
this.optionalkey = config.getKey("key1", "defaultValue");
But from sources I see it does not have it, but I plan to add it and make a PR.
UPDATE
PR: https://github.com/robik/DIni/pull/3
Wrote a pretty advanced ini file wrapper today which supports sections, comments, thread-safety, default values for reading, writing/reading using template values, entry checks etc.
You can get it here:
https://github.com/BaussProjects/baussini
Here is an example usage (example.d from the repo)
module main;
import baussini;
import std.stdio : writefln, readln;
void main() {
string fileName = "test.ini";
// Thread-safe instance, for a non thread-safe instance replace "true" with "false"
auto ini = new IniFile!(true)(fileName);
// Use open() for reading and close() for write. Both can be combined ...
if (!ini.exists()) {
ini.addSection("Root");
// Write way 1
ini.write!string("Root", "StringValue1", "Hello World!");
// Write way 2
ini.getSection("Root").write!int("IntValue1", 9001);
// Write way 3
ini.getSection("Root")
.write!string("StringValue2", "Hello Universe!")
.write!int("IntValue2", 1000000);
ini.close();
}
else {
ini.open();
// Read way 1
string stringValue1 = ini.read!string("Root", "StringValue1");
// Read way 2
int intValue1 = ini.getSection("Root").read!int("IntValue1");
// Read way 3
string stringValue2;
int intValue2;
ini.getSection("Root")
.read!string("StringValue2", stringValue2)
.read!int("IntValue2", intValue2);
writefln("%s is %s", "stringValue1", stringValue1);
writefln("%s is %s", "intValue1", intValue1);
writefln("%s is %s", "stringValue2", stringValue2);
writefln("%s is %s", "intValue2", intValue2);
readln();
}
}
In your case you could either use IniFile.hasKey or IniSection().hasKey()
Example:
// Check way 1
if (ini.hasKey("Root", "StringValue1")) {
// The section "Root" has an entry named "StringValue1"
}
// Check way 2
auto section = ini.getSection("Root");
if (section.hasKey("StringValue1")) {
// The section "Root" has an entry named "StringValue1"
}
You could also use default values.
string stringValue1 = ini.getSection("Root").read!string("StringValue1", "Default");
// stringValue1 will be "Default" if it doesn't exist within "Root"
The default value has to be a string input, but it will always convert the value of it to T.
Ex.
int defaultValue = ini.getSection("Root").read!int("IntValue3", "1000");
// defaultValue will be 1000 if it doesn't exist within "Root"
You can test if a key is present with hasKey
class ParseConfig
{
string optionalkey;
//...
this()
{
if (config.hasKey("key1"))
this.optionalkey = config.getKey("key1");
}
//...
}
assuming that we talk about the same dini

Adding 'GO' statements to Entity Framework migrations

So I have an application with a ton of migrations made by Entity framework.
We want to get a script for all the migrations at once and using the -Script tag does work fine.
However...it does not add GO statements in the SQL giving us problems like Alter view should be the first statement in a batch file...
I have been searching around and manually adding Sql("GO"); help with this problem but only for the entire script. When I use the package console manager again it returns an exception.
System.Data.SqlClient.SqlException (0x80131904): Could not find stored procedure 'GO'.
Is there a way to add these GO tags only when using the -Script tag?
If not, what is a good approach for this?
Note: we have also tried having multiple files but since we have so many migrations, this is near impossible to maintain every time.
If you are trying to alter your view using Sql("Alter View dbo.Foos As etc"), then you can avoid the should be the first statement in a batch file error without adding GO statements by putting the sql inside an EXEC command:
Sql("EXEC('Alter View dbo.Foos As etc')")
In order to change the SQL Generated by entity framework migrations you can create a new SqlServerMigrationSqlGenerator
We have done this to add a GO statement before and after the migration history:
public class MigrationScriptBuilder: SqlServerMigrationSqlGenerator
{
protected override void Generate(System.Data.Entity.Migrations.Model.InsertHistoryOperation insertHistoryOperation)
{
Statement("GO");
base.Generate(insertHistoryOperation);
Statement("GO");
}
}
then add in the Configuration constructor (in the Migrations folder of the project where you DbContext is) so that it uses this new sql generator:
[...]
internal sealed class Configuration : DbMigrationsConfiguration<PMA.Dal.PmaContext>
{
public Configuration()
{
SetSqlGenerator("System.Data.SqlClient", new MigrationScriptBuilder());
AutomaticMigrationsEnabled = false;
}
[...]
So now when you generate a script using the -Script tag, you can see that the insert into [__MigrationHistory] is surrounded by GO
Alternatively in your implementation of SqlServerMigrationSqlGenerator you can override any part of the script generation, the InsertHistoryOperation was suitable for us.
Turn out the concept exist deep in the SqlServerMigrationSqlGenerator as an optional argument for Statement(sql, batchTerminator). Here is something based on Skyp idea. It works both in -script mode or not. The GOs are for different operations than for Skyp only because our needs are a little different. You then need to register this class in the Configuration as per Skyp instructions.
public class MigrationScriptBuilder : SqlServerMigrationSqlGenerator
{
private string Marker = Guid.NewGuid().ToString(); //To cheat on the check null or empty of the base generator
protected override void Generate(AlterProcedureOperation alterProcedureOperation)
{
SqlGo();
base.Generate(alterProcedureOperation);
SqlGo();
}
protected override void Generate(CreateProcedureOperation createProcedureOperation)
{
SqlGo();
base.Generate(createProcedureOperation);
SqlGo();
}
protected override void Generate(SqlOperation sqlOperation)
{
SqlGo();
base.Generate(sqlOperation);
}
private void SqlGo()
{
Statement(Marker, batchTerminator: "GO");
}
public override IEnumerable<MigrationStatement> Generate(IEnumerable<MigrationOperation> migrationOperations, string providerManifestToken)
{
var result = new List<MigrationStatement>();
var statements = base.Generate(migrationOperations, providerManifestToken);
bool pendingBatchTerminator = false;
foreach (var item in statements)
{
if(item.Sql == Marker && item.BatchTerminator == "GO")
{
pendingBatchTerminator = true;
}
else
{
if(pendingBatchTerminator)
{
item.BatchTerminator = "GO";
pendingBatchTerminator = false;
}
result.Add(item);
}
}
return result;
}
}
The easiest way is to add /**/ before the GO statement.
Just replace the current statement with a .Replace("GO", "");

Pros & cons bean vs SSJS?

I was trying to build a bean that always retrieves the same document ( a counter document), gets the current value, increment it and save the document with the new value. Finally it should return the value to the calling method and that would get me a new sequential number in my Xpage.
Since the Domino objects cannot be serialized or singleton'ed what's the benefit creating a bean doing this, over creating a SSJS function doing the exact same thing?
My bean must have calls to session, database, view and document, which then will be called every time.
The same within the SSJS-function except for session and database.
Bean:
public double getTransNo() {
try {
Session session = ExtLibUtil.getCurrentSession();
Database db = session.getCurrentDatabase();
View view = db.getView("vCount");
view.refresh();
doc = view.getFirstDocument();
transNo = doc.getItemValueDouble("count");
doc.replaceItemValue("count", ++transNo);
doc.save();
doc.recycle();
view.recycle();
} catch (NotesException e) {
e.printStackTrace();
}
return transNo;
}
SSJS:
function getTransNo() {
var view:NotesView = database.getView("vCount");
var doc:NotesDocument = view.getFirstDocument();
var transNo = doc.getItemValueDouble("count");
doc.replaceItemValue("count", ++transNo);
doc.save();
doc.recycle();
view.recycle();
return transNo;
}
Thank you
Both pieces of code are not good (sorry to be blunt).
If you have one document in your view, you don't need a view refresh which might be queued behind a refresh on another view and be very slow. Presumably you are talking about a single sever solution (since replication of the counter document would for sure lead to conflicts).
What you do in XPages is to create a Java class and declare it as application bean:
public class SequenceGenerator {
// Error handling is missing in this class
private double sequence = 0;
private String docID;
public SequenceGenerator() {
// Here you load from the document
Session session = ExtLibUtil.getCurrentSession();
Database db = session.getCurrentDatabase();
View view = db.getView("vCount");
doc = view.getFirstDocument();
this.sequence = doc.getItemValueDouble("count");
this.docID = doc.getUniversalId();
Utils.shred(doc, view); //Shred currenDatabase isn't a good idea
}
public synchronized double getNextSequence() {
return this.updateSequence();
}
private double updateSequence() {
this.sequence++;
// If speed if of essence I would spin out a new thread here
Session session = ExtLibUtil.getCurrentSession();
Database db = session.getCurrentDatabase();
doc = db.getDocumentByUnid(this.docID);
doc.ReplaceItemValue("count", this.sequence);
doc.save(true,true);
Utils.shred(doc);
// End of the candidate for a thread
return this.sequence;
}
}
The problem for the SSJS code: what happens if 2 users hit that together? At least you need to use synchronized there too. Using a bean makes it accessible in EL too (you need to watch out not to call it too often). Also in Java you can defer the writing back to a different thread - or not write it back at all and in your class initialization code read the view with the actual documents and pick the value from there.
Update: Utils is a class with static methods:
/**
* Get rid of all Notes objects
*
* #param morituri = the one designated to die, read your Caesar!
*/
public static void shred(Base... morituri) {
for (Base obsoleteObject : morituri) {
if (obsoleteObject != null) {
try {
obsoleteObject.recycle();
} catch (NotesException e) {
// We don't care we want go get
// rid of it anyway
} finally {
obsoleteObject = null;
}
}
}
}

Parsing Expression Tree To Sqlstring - Not Reinventing the wheel

I need to parse an expressiontree to get a sql where clause.
Aren't there any classes in the .NET FX or any third party library which already have this abilities ?
I mean Linq2SQL, EntityFramework , all of them have to do this, so does anyone know, if there is something that can be reused instead of reinventing the wheel?
MyType.Where(Func<TEntity,bool>((entity)=>entity.Id == 5)))
now i need to get the corresponding string representing a where clause:
where abc.Id = "5"
this is just an simple example. it should also work with logical conjunctions.
I know I can create the expressiontree and parse it on my own, but i think there could be something already existing, which I'm missing
You could create an ExpressionVisitor with the sole purpose of finding and processing the where calls. Making this task very easy to handle.
e.g.,
public class WhereCallVisitor : ExpressionVisitor
{
protected override Expression VisitMethodCall(MethodCallExpression node)
{
var method = node.Method;
if (method.Name == "Where" && method.DeclaringType == typeof(Queryable))
{ // we are in a Queryable.Where() call
ProcessWhereCall(node);
}
return base.VisitMethodCall(node);
}
private void ProcessWhereCall(MethodCallExpression whereCall)
{
// extract the predicate expression
var predicateExpr = ((dynamic)whereCall.Arguments[1]).Operand as LambdaExpression;
// do stuff with predicateExpr
}
// p.s., dynamic used here to simplify the extraction
}
Then to use it:
var query = from row in table
where row.Foo == "Bar"
select row.Baz;
var visitor = new WhereCallVisitor();
visitor.Visit(query.Expression);