Releases: VinGarcia/ksql
Minor release with a fix to the struct tag parsing mechanism
@mrheinen found an error on how we were parsing the tags from structs: If an attribute had a KSQL tag and was private we would correctly report an error.
However if the attribute did not had a tag and was private we would still report an error, and this should not happen.
This version has this issue fixed.
Thanks @mrheinen
Minor fix to better support `Insert()` on `kmysql` and `ksqlite` adapters
The Insert()
adapter has a feature that allows IDs created by the database to be returned and saved back to the original struct.
An example of an ID that is generated by the database is a serial or auto-increment integer ID, or an ID that is a string and defaults to a "UUID()" function.
On Postgres the newly created ID is returned using the "RETURNING" key-word on the SQL query, on SQLServer this is done using the "OUTPUT" key-word on the SQL query. But for sqlite and mysql there is no equivalent key-word supported for returning a newly created value during an insert.
This means that we can't really return any ID value directly from the database during an Insert query for neither mysql nor sqlite.
The recommended alternative (which is what KSQL does) is to use LastInsertID()
. This function is implemented on all databases and works specifically for integer IDs with an "auto-increment" behavior.
For the case of retrieving the ID using the LastInsertID()
function we have a separate function called insertWithLastInsertID()
. This function has to use reflection to copy the int64 value returned by the LastInsertID()
function to the struct attribute that should contain this ID. This function used to work fine if the ID was an integer and it correctly ignored IDs if the type was a string
as there is no way of returning this IDs efficiently and returned no errors.
However if the user decided to use a *int
or an *string
as the ID type on the struct the Insert operation would fail with a misleading error message.
v1.12.2 (and v1.12.1) fixes this error and now will cause *string
IDs to be correctly ignored and will correctly work for *int
IDs.
Add adapter kpostgres
This is a minor release that adds a new adapter kpostgres
, this adapter is only meant to be used if you are using a framework that forces you to connect to Postgres over a database/sql.DB
instance.
More specifically this addition was made with help from @devalexandre for integrating KSQL with the encore
framework.
In any case, if you have the choice you should always use kpgx
over kpostgres
since the former is much more efficient.
Fix issue with qualified table names
As suggested by one user of the KSQL library I should start doing official releases like this one explaining all the changes and updates every time I release a new version.
Since I have not been doing actual releases for a long time (I was only creating tags but with no description of the changes) this release will describe all new features and updates ever since the last version that was officially released, namely: v1.6.0
- Remove direct import to
github.com/lib/pq
from thekpgx
adapter. This still doesn´t completely remove it from the indirect dependencies because this library is an indirect dependency used on pgx for testing (if I remember correctly). - Add
kpgx5
adapter. This adapter is just like thekpgx
adapter but works using pgx v5 instead of pgx 4. - Add
modernc-ksqlite
adapter. This adapter is just like theksqlite
adapter but it uses the https://pkg.go.dev/modernc.org/sqlite implementation, which, although not being as widely used and battle-tested as the former, does not depend on CGO which is a big advantage in many situations. - Remove the deprecated
Update()
function: use thePatch()
function instead (which has the exact same implementation). This function was renamed fromUpdate
toPatch
because it contains the "patching" feature of automatically ignoring null pointers instead of trying to set the attribute to NULL. This behavior would be counter-intuitive if someone tried to guess its behavior from the nameUpdate
. Also having the nameUpdate
used for this prevented me from in the future adding an actualUpdate
function on v2, which is something I intend to do, and deprecating/removing this now will probably prevent users from not noticing this subtle difference when updating to v2, so I considered that this breaking change was would probably make the update safer in the future. - Move the
ksql.Dialect
interface to subpackagesqldialect
and rename it tosqldialect.Provider
. - Add
ksql.InjectLogger()
function for helping debug query errors. - When using the
Patch()
method without providing all required IDs KSQL will now return aksql.ErrRecordMissingIDs
with a more appropriate error message. - Fixes an issue that prevented the
Insert
,Patch
andDelete
helper functions from working with qualified table names, e.g.public.users
.
And that is pretty much all of it, I hope you guys like it
Add Nullable Modifier
Before this modifier the Patch function would always ignore null pointers.
Which was no convenient because there was no good way of setting fields to NULL on the database when desired forcing users to use:
db.Exec("UPDATE <table> SET <field_name> = NULL")
manually
Now it is possible to just add the nullable modifier to the attribute, e.g.:
type User struct{
ID int `ksql:"id"`
Name *string `ksql:"name,nullable"`
}
// Set name to NULL:
err := db.Insert(ctx, usersTable, &User{
ID: userID,
Name: nil,
})
Add the concept of attribute modifiers
This release adds the concept of a modifier.
What is a KSQL Modifier?
A KSQL modifier is a special tag you can add to any of the attributes of your struct to alter the behavior of KSQL when reading or writing that attribute into the database. To use it, it is necessary to add the name of the modifier on the ksql
tag after a comma, e.g.:
`ksql:"column_name,json"`
Before this release, the json
modifier was the only one available in KSQL, and it would help the user by converting the attribute to JSON before writing to the database and back from JSON when reading from the database.
Adding Custom Modifiers
This release improves on this idea of modifiers by making it possible for users to add their own user-created modifiers. This release also adds 4 new built-in modifiers so users can use out of the box, namely:
timeNowUTC
: It only works if on attributes of typetime.Time
and it sets this attribute totime.Now().UTC()
every time before insertions and updates. This modifier was created to be used onUpdatedAt
timestamp fields.timeNowUTC/skipUpdates
: Does the same as the above but only on insertions. This is useful forCreatedAt
fields where you only want them to be set once onInsert()
.skipUpdates
: Will ignore fields on updates.skipInserts
: Will ignore fields on inserts.
Here is an example of how a User
struct might look like using some of these modifiers:
type user struct {
ID uint `ksql:"id"`
Name string `ksql:"name"`
Age int `ksql:"age"`
Address Address `ksql:"address,json"`
UpdatedAt time.Time `ksql:"updated_at,timeNowUTC"`
CreatedAt time.Time `ksql:"created_at,timeNowUTC/skipUpdates"`
}
We also have plans on releasing some modifiers for saving time.Time
instances as UNIX timestamps on the database in the future.
Registering new Modifiers
Registering new modifiers is done by instantiating a struct like the below:
func init() {
ksqlmodifiers.RegisterAttrModifier("my_modifier_name", ksqlmodifiers.AttrModifier{
SkipInserts: false, // set it to true if you want this modifier to cause the field to be ignored on inserts.
SkipUpdates: false, // set it to true if you want this modifier to cause the field to be ignored on updates.
Scan: func(ctx context.Context, opInfo ksqlmodifiers.OpInfo, attrPtr interface{}, dbValue interface{}) error {
// Read the dbValue, modify it and then save it into the attrPtr argument using reflection.
},
Value: func(ctx context.Context, opInfo ksqlmodifiers.OpInfo, inputValue interface{}) (outputValue interface{}, _ error) {
// Read the inputValue, modify it and then return it so the database can save it.
},
})
}
This registration should be performed inside your code before making any calls to the KSQL library. I recommend doing it inside a init()
function since then it will run before main()
starts.
Fix a race condition problem and improves the docs
v1.4.7 Remove dependency on ditointernet/go-assert
Update ksql.DB & adapters to implement io.Closer()
v1.4.6 Try to fix CI again
Add more flexible constructor for `kpgx`
Add the new kpgx.NewFromPgxPool(pool *pgxpool.Pool) (ksql.DB, error)
constructor for allowing users to setup more complicated configurations for pgxpool
.
Add support for TLS on ksql.Config
v1.4.4 Add tls.Config to ksql.Config