Jooq - converting nested objects - jooq

the problem which I have is how to convert jooq select query to some object. If I use default jooq mapper, it works but all fields must be mentioned, and in exact order. If I use simple flat mapper, I have problems with multiset.
The problem with simple flat mapper:
class Student {
private final id;
Set<String> bookIds;
}
private static final SelectQueryMapper<Student> studentMapper = SelectQueryMapperFactory.newInstance().newMapper(Studen.class);
var students = studentMapper.asList(
context.select(
STUDENT.ID.as("id),
multiset(
select(BOOK.ID).from(BOOK).where(BOOK.STUDENT_ID.eq(STUDENT.ID)),
).convertFrom(r -> r.intoSet(BOOK.ID)).as("bookIds"))
.from(STUDENT).where(STUDENT.ID.eq("<id>"))
)
Simple flat mapper for attribute bookIds returns:
Set of exact one String ["[[book_id_1], [book_id_2]]"], instead of ["book_id_1", "book_id_2"]
As I already mention, this is working with default jooq mapper, but in my case all attributes are not mention in columns, and there is possibility that some attributes will be added which are not present in table.
The question is, is there any possibility to tell simple flat mapper that mapping is one on one (Set to set), or to have default jooq mapper which will ignore non-matching and disorder fields.
Also what is the best approach in this situations

Once you start using jOOQ's MULTISET and ad-hoc conversion capabilities, then I doubt you still need third parties like SimpleFlatMapper, which I don't think can deserialise jOOQ's internally generated JSON serialisation format (which is currently an array of arrays, not array of objects, but there's no specification for this format, and it might change in any version).
Just use ad-hoc converters.
If I use default jooq mapper, it works but all fields must be mentioned, and in exact order
You should see that as a feature, not a bug. It increases type safety and forces you to think about your exact projection, helping you avoid to project too much data (which will heavily slow down your queries!)
But you don't have to use the programmatic RecordMapper approach that is currently being advocated in the jOOQ manual and blog posts. The "old" reflective DefaultRecordMapper will continue to work, where you simply have to have matching column aliases / target type getters/setters/member names.

Related

Is it allowed to modify value of the Value Object on construction

Assuming that I want that following Value Object contains always capitalized String value. Is it eligible to do it like this with toUpperCase() in constructor?
class CapitalizedId(value: String) {
val value: String = value.toUpperCase()
// getters
// equals and hashCode
}
In general, I do not see a problem of performing such a simple transformation in a value object's constructor. There should of course be no surprises for the user of a constructor but as the name CapitalizedId already tells you that whatever will be created will be capitalized there is no surprise, from my point of view. I also perform validity checks in constructors to ensure business invariants are adhered.
If you are worried to not perform operations in a constructor or if the operations and validations become too complex you can always provide factory methods instead (or in Kotlin using companion, I guess, not a Kotlin expert) containing all the heavy lifting (think of LocalDateTime.of()) and validation logic and use it somehow like this:
CapitalizedId.of("abc5464g");
Note: when implementing a factory method the constructor should be made private in such cases
Is it eligible to do it like this with toUpperCase() in constructor?
Yes, in the sense that what you end up with is still an expression of the ValueObject pattern.
It's not consistent with the idea that initializers should initialize, and not also include other responsibilities. See Misko Hevery 2008.
Will this specific implementation be an expensive mistake? Probably not

What's the usage of field's SQLDataType in JOOQ's auto generated classes

When generating JOOQ classes via JOOQ code gen, for each field, there will be a SQLDataType associated with it like below.
public final TableField<EventsRecord, LocalDateTime> CREATED_AT = createField(DSL.name("CREATED_AT"), SQLDataType.LOCALDATETIME(6).nullable(false), this, "");
What's the usage or purpose to have SQLDataType with each generated field? Since we already have a return type and client code is likely to use the this type to do the compile check.
Why we still need to know the actual SQLDataType in generated class/fields?
By client type, you probably mean the LocalDateTime type, i.e. the <T> type that you will find throughout the jOOQ API. Sure, that's the type you care about, but jOOQ, internally, will care about the org.jooq.DataType instead. Your example already gives away two ideas why this may be useful:
There's a precision of 6 fractional digits on LOCALDATETIME(6), which is used (among other things):
In CAST expressions. Try DSL.cast(inline("2000-01-01 00:00:00"), EVENTS.CREATED_AT),
In DDL statements. Try DSLContext.meta(EVENTS). You should see a CREATE TABLE statement with the appropriate data type
In the optimistic locking feature, to create modification timestamps with the right precision.
There's an indication whether the column is nullable, which is used (again among other things):
In DDL statements, see above
In the implicit join feature, to decide whether to produce an INNER JOIN or a LEFT JOIN
There are many other properties a DataType can have, which would be interesting for jOOQ at runtime including:
Custom data type bindings
Character set
Collation
Converters
Default value
Whether it is an identity
Besides, a String is not a String. For example, it could mean CHAR(2), CHAR(5), VARCHAR(100), CLOB, which are all quite different things in some dialects.
It would be a shame if your runtime meta model didn't have this information available.

Storing a list of mixed types in Cassandra

In Cassandra, when specifying a table and fields, one has to give each field a type (text, int, boolean, etc.). The same applies for collections, you have to give lock a collection to specific type (set<text> and such).
I need to store a list of mixed types in Cassandra. The list may contain numbers, strings and booleans. So I would need something like list<?>.
Is this possible in Cassandra and if not, What workaround would you suggest for storing a list of mixed type items? I sketched a few, but none of them seem the right way to go...
Cassandra's CQL interface is strictly typed, so you will not be able to create a table with an untyped collection column.
I basically see two options:
Create a list field, and convert everything to text (not too nice, I agree)
Use the thift API and store everything as is.
As suggested at http://www.mail-archive.com/user#cassandra.apache.org/msg37103.html I decided to encode the various values into binary and store them into list<blob>. This allows to still query the collection values (in Cassandra 2.1+), one just needs to encode the values in the query.
On python, simplest way is probably to pickle and hexify when storing data:
pickle.dumps('Hello world').encode('hex')
And to load it:
pickle.loads(item.decode('hex'))
Using pickle ties the implementation to python, but it automatically converts to correct type (int, string, boolean, etc.) when loading, so it's convenient.

this has the advanteages of the IQueryable?

If I dont' wrong, I can get the data from a database in to ways:
First with an IEnumerable:
myContext.MyTable.ToList();
With an IQeryable:
IQueryable<MyTable> query = myContext.Mytable;
I know that one of the advantages is that IQueryable execute the conditions in the server, so is more efficient and faster that IEnumerable.
But In my repository, as I return a List, I would like to know if this:
return query.ToList();
has the advantages of the IQueryable.
query.ToList() is the same like myContext.MyTable.ToList(). It returns a collection in memory (the whole database table) and is just an IEnumerable<T>, not an IQueryable<T>. Every further LINQ operator - for example a Where clause - you append, will be performed in memory and not in the database.
If you choose to return IEnumerable<T> or List<T> from your repository you have to design the repository methods so that you can apply filters, sorting, etc. inside of those methods - for example by passing in filter and sort expressions as parameters into the methods or by creating lots of specialized methods for different use cases - like GetOrdersByCustomerId, GetOrdersByShippingDate, etc., etc. If you do it outside of and after calling repository methods you will suffer from poor performance.

Usage of a correct collection Type

I am looking for a native, or a custom-type that covers the following requirements:
A Generic collection that contains only unique objects like a HashSet<T>
It implements INotifyCollectionChanged
It implements IENumerable<T> (duh) and must be wrappable by a ReadOnlyCollection<T> (duh, duh)
It should work with both small and large numbers of items (perhaps changing inner behaviour?)
the signature of the type must be like UniqueList<T> (like a list, not a key/valuepair)
It does not have to be sortable.
Searchability is not a "must-have".
The main purpose of this is to set up a small mesh/network between related objects.
So this network can only unique objects and there has to be a mechanism that notifies the application when changes in the collection happen.Since it is for a proof-of-concept the scope is purely within the assembly (no db's or fs are of any importance).
What is a proper native type for this or what are the best ingredients to create a composite?
Sounds like you could just wrap HashSet<T> in your own type extremely easily, just to implement INotifyCollectionChanged. You can easily proxy everything you need - e.g. GetEnumerator can just call set.GetEnumerator() etc. Implementing INotifyCollectionChanged should just be a matter of raising the event when an element is added or removed. You probably want to make sure you don't raise the event if either you add an element which is already present or remove an element which isn't already present. HashSet<T>.Add/Remove both return bool to help you with this though.
I wouldn't call it UniqueList<T> though, as that suggests list-like behaviour such as maintaining ordering. I'd call it ObservableSet<T> or something like that.

Resources