Skip to content

Releases: VinGarcia/ksql

Minor release with a fix to the struct tag parsing mechanism

06 Nov 21:53
Compare
Choose a tag to compare

@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

04 Nov 02:51
Compare
Choose a tag to compare

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

22 Jan 13:49
6356f35
Compare
Choose a tag to compare

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

17 Jan 03:29
Compare
Choose a tag to compare

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 the kpgx 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 the kpgx adapter but works using pgx v5 instead of pgx 4.
  • Add modernc-ksqlite adapter. This adapter is just like the ksqlite 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 the Patch() function instead (which has the exact same implementation). This function was renamed from Update to Patch 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 name Update. Also having the name Update used for this prevented me from in the future adding an actual Update 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 subpackage sqldialect and rename it to sqldialect.Provider.
  • Add ksql.InjectLogger() function for helping debug query errors.
  • When using the Patch() method without providing all required IDs KSQL will now return a ksql.ErrRecordMissingIDs with a more appropriate error message.
  • Fixes an issue that prevented the Insert, Patch and Delete 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

17 Dec 18:16
6ff6720
Compare
Choose a tag to compare

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

13 Nov 17:38
Compare
Choose a tag to compare

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 type time.Time and it sets this attribute to time.Now().UTC() every time before insertions and updates. This modifier was created to be used on UpdatedAt timestamp fields.
  • timeNowUTC/skipUpdates: Does the same as the above but only on insertions. This is useful for CreatedAt fields where you only want them to be set once on Insert().
  • 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

19 Jul 17:11
Compare
Choose a tag to compare
v1.4.7

Remove dependency on ditointernet/go-assert

Update ksql.DB & adapters to implement io.Closer()

20 Apr 23:51
Compare
Choose a tag to compare

Add more flexible constructor for `kpgx`

11 Apr 23:06
Compare
Choose a tag to compare

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

04 Apr 00:30
Compare
Choose a tag to compare
v1.4.4

Add tls.Config to ksql.Config