How to rename generated table references? - jooq

I have two schemas in my database and both share tables with the same names.
In order to not have naming conflicts in generated code, I want to prefix all names with the appropriate schema name.
I made it work for class names by overriding getJavaClassName of DefaultGeneratorStrategy however I could not find a fitting override that is responsible for the table references in tables.references.Tables.kt.

I managed to solve my problem by overriding getJavaIdentifier of DefaultGeneratorStrategy the following way:
override fun getJavaIdentifier(definition: Definition): String {
if (definition is PostgresTableDefinition) {
return "${definition.schema.name.toUppercaseSnakeCase()}_${super.getJavaIdentifier(definition)}"
}
return super.getJavaIdentifier(definition)
}

Related

Antlr4 contextSuperClass to add custom properties for a two pass interpreter

I have just discovered contextSuperClass and have been experimenting with using it to provide scope annotations when building a symbol table in a first pass (I have a forward reference DSL).
I set the option in the grammar:
options {
tokenVocab=MyLexer;
language = CSharp;
contextSuperClass = interpreter.MyParserRuleContext;
}
and I have a class that derives from ParserRuleContext:
public class MyParserRuleContext : ParserRuleContext
{
public MyParserRuleContext()
{ }
public MyParserRuleContext(ParserRuleContext parent, int invokingStateNumber) : base(parent, invokingStateNumber)
{
}
public IScope ContextScope { get; set; }
}
So far so good. I use ParseTreeWalker with a listener (Enter/Exit methods) to walk the tree for the 1st pass and build the symbol table adding local scopes, etc into my ContextScope custom property.
The first issue is of course after the symbol table pass I am at the end of the token stream - the tree is walked.
The 2nd parse uses a visitor to evaluate the final result.
I have two questions:
How do I "reset" the parser so that it is at the root again without loosing scopes I have added into my custom property?
The second question is broader, but similar. Is this even a reasonable way to add scope annotations to the parse tree?
I have previously tried to use ParseTreeProperty<IScope> to add scope annotations, but the problem is similar. During the 2nd phase, the context objects provided in the visitor are not the same objects added to ParseTreeProperty<IScope> concurrent dictionary from the 1st pass - so they are not found. Between the 1st & 2nd passes I have only found parser.reset() as a way to start the parser over, and (of course) it appears to fully reset everything and I loose the any state I created in the 1st pass.
I am likely missing completely missing something here - so any help to put me in the right direction will be greatly appreciated.

Does jooq record use column indexes when fetching data?

I'm investigating an issue where we are seeing strange exceptions related to jooq trying to populate a generated Record class, where it gets data type errors because it uses java.sql.ResultSet::getXXX(int) (column index based) to fetch data.
The part of the stacktrace that I can share looks like:
Caused by: java.sql.SQLDataException: Value 'ABC' is outside of valid range for type java.lang.Byte
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:114)
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97)
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:89)
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:63)
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:73)
at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:92)
at com.mysql.cj.jdbc.result.ResultSetImpl.getObject(ResultSetImpl.java:1423)
at com.mysql.cj.jdbc.result.ResultSetImpl.getByte(ResultSetImpl.java:710)
at com.zaxxer.hikari.pool.HikariProxyResultSet.getByte(HikariProxyResultSet.java)
at org.jooq.tools.jdbc.DefaultResultSet.getByte(DefaultResultSet.java:124)
at org.jooq.tools.jdbc.DefaultResultSet.getByte(DefaultResultSet.java:124)
at org.jooq.impl.CursorImpl$CursorResultSet.getByte(CursorImpl.java:688)
at org.jooq.impl.DefaultBinding$DefaultByteBinding.get0(DefaultBinding.java:1783)
at org.jooq.impl.DefaultBinding$DefaultByteBinding.get0(DefaultBinding.java:1755)
at org.jooq.impl.DefaultBinding$AbstractBinding.get(DefaultBinding.java:871)
at org.jooq.impl.CursorImpl$CursorIterator$CursorRecordInitialiser.setValue(CursorImpl.java:1725)
Which is definitely a column mismatch caused using wrong column index.
The issue comes up because we are using the record on an evolving schema so the underlying table contains columns not available in the record definition.
Note that the actual code that triggers this is:
jooq.insertInto(TABLE)
.set(TABLE.COL, "ABC")
.returning(TABLE.asterisk())
.fetchOne();
What scares me a bit here is, that if it does indeed use column indexes by design, that will make schema evolution somewhat hard (how would you delete a column from a running application).
Long story (sorry), question is: does jooq use column index in records generated by jooq-generator and is there a way to use column names instead?
One thing I have noticed is that when I compare the documentation at https://www.jooq.org/doc/3.14/manual/code-generation/codegen-records/ the shown generated records does not match what the generator actually generates. The documentation show methods like:
// Every column generates a setter and a getter
#Override
public void setId(Integer value) {
setValue(BOOK.ID, value);
}
But in reality the generated code looks like (taken from jOOQ-examples):
/**
* Setter for <code>PUBLIC.BOOK.ID</code>.
*/
public void setId(Integer value) {
set(0, value);
}
Btw we are using jooq 3.14.15.
Ok, this was a local error. What actually caused the issue was that our code was written as:
jooq.insertInto(TABLE)
.set(TABLE.COL, "ABC")
.returning(TABLE.asterisk())
.fetchOne();
And the TABLE.asterisk() is what messes it up (since on the database that contains extra columns it does not return what jooq expects). Fortunately removing it solves the problem so our code now looks like:
jooq.insertInto(TABLE)
.set(TABLE.COL, "ABC")
.returning()
.fetchOne();

ServiceStack.OrmLite: Table collision when class name appears in different namespaces

When having two classes that has the same name, but in different namespaces, ServiceStacks OrmLite is unable to distinguish between the two. For example:
Type type = typeof(FirstNameSpace.BaseModel);
using (IDbConnection db = _dbFactory.Open())
{
db.CreateTable(false, type); // Creates table "basemodel"
}
type = typeof(SecondNamespace.BaseModel);
using (IDbConnection db = _dbFactory.Open())
{
db.CreateTable(false, type); // Creates nothing as there already is a table 'basemodel', even though its a completely different object/class
}
Is there a general, clean way to make sure that this is resolved?
It is not ideal to be forced to name classes uniquely; a part of the namespaces in .NET is to group and categorize different classes. Also, there might be third-party assemblies with the same class names, that is not available to change for you.
Is there a way to handle this?
OrmLite uses the name of the Type for the table name so you can’t use 2 different Types with the same name.
You will need to either rename one of the Types to avoid the collision or use the [Alias(“UseTableName”)] attribute to tell one of the Types to use a different RDBMS Table name.

Orchard Custom User Part is not stored in Database

I can't seem to store additional data in a separate contentpart attached to User. I have done the following:
Created a module
In the module I created a Model for ProfilePart and ProfilePartRecord
In the migration I created a table for ProfilePartRecord (from type ContentPartRecord)
In the migration I altered the typedefinition for User, by setting WithPart ProfilePart
I created a driver class, that has 2 edit methods, one for get and one for post (code snippets are below
I also created a handler that adds a storage filter for profilePartRepository of type ProfilePartRecord
Module Structure
Drivers/ProfilePartDriver.cs
Handlers/ProfileHandler.cs
Models/ProfilePart.cs
Models/ProfilePartRecord.cs
Views/EditorTemplates/Parts/profile.cshtml
Migrations.cs
Placement.info
Since I think the issue is in the Driver. This is my code:
Is it going wrong because the part is attached to User? Or am I missing something else.
public class ProfilePartDriver:ContentPartDriver
{
protected override string Prefix
{
get { return "Profile"; }
}
//GET
protected override DriverResult Editor(ProfilePart part, dynamic shapeHelper)
{
return ContentShape("Parts_Profile_Edit", () =>
shapeHelper.EditorTemplate(TemplateName: "Parts/Profile", Model: part, Prefix: Prefix));
}
//POST
protected override DriverResult Editor(ProfilePart part, IUpdateModel updater, dynamic shapeHelper)
{
updater.TryUpdateModel(part, Prefix, null, null);
return Editor(part, shapeHelper);
}
}
I have used Skywalker's blog. There is one chapter about registering customers by using the User and adding your own content parts to it. Worked nice for me.
First of all - is your ProfilePart editor shown at all when you go to Dashboard and edit a given user? I noticed you're using Parts_Profile_Edit as a shape key, but actually use EditorTemplates/Parts/Profile.cshtml as a template. It's perfectly correct, but note that Placement.info file uses shape keys, so you have to use Parts_Profile_Edit as a shape name in there. Otherwise it won't get displayed.
Second - have you tried debugging to see if the second driver Editor method (the one for handling POST) is being called at all?
Like Bertrand suggested, I'd look into one of the existing modules that work (afaik there is one for user profile in the Gallery) and see the difference. It might be something small, eg. a typo.

Zend_Db_Table_Abstract $_name not working

I encountered a problem regarding changing default table name
class Application_Model_DbTable_Game extends Zend_Db_Table_Abstract
{
protected $_name = 'games';
Error:
Message: SQLSTATE[42S02]: Base table or view not found: 1146 Table 'gamenomad_dev.game' doesn't exist
Help me... it's supposed to be simple!
*EDIT
The problem here is that Zend Framework is supposed to detect the changed table name from the default 'game' into 'games'.
In ZF you have to hardcode your database table to model. It doesn't scan for database changes. You have two ways:
Create class with table name
class Game extends Zend_Db_Table_Abstract
{
// default table name: game
}
If you want to use ZF's default paths, you should put DBTable model into application/models/dbtable directory and name your class like Application_Model_DbTable_Game - then ZF knows it has to look for game table
Create class with any name
e.g. ExtraGameTable and set its parameters to show table name:
class ExtraGameTable extends Zend_Db_Table_Abstract
{
protected $_name = 'game';
}
As stated in documentation: http://framework.zend.com/manual/en/zend.db.table.html
If you don't specify the table name, it defaults to the name of the
class. If you rely on this default, the class name must match the
spelling of the table name as it appears in the database.
You may try to combine it with some configuration file and load table names from there, but still - ZF won't know anything about underlying database changes.
Show the actual line and stacktrace to your problem, maybe you are generating your query in a way it doesn't read the actual table name.

Resources