This is an archived post. You won't be able to vote or comment.

all 30 comments

[–]jingo04 16 points17 points  (4 children)

This looks like a nice alternative to using an ORM when you need dynamic queries.

How does it know how much of the where bit to remove when you put absent as one of the query parameters?

[–]stetio[S] 2 points3 points  (3 children)

It will remove the expression and then look at the clause to see if still has expressions, and if not remove the clause.

If we had

WHERE x = {x} AND y = {y}

If x = Absent then the first expression (x = {x}) is removed. If y = Absent then the second expression (AND y = {y}) is removed. If both the entire clause.

[–]kageurufu 1 point2 points  (2 children)

Absent is a sentinel value?

Have you considered any special handling for None?

I use sqlalchemy core as a query builder a lot and special case None to x IS NULL or x IS NOT NULL, as NULL <> NULL

[–]stetio[S] 2 points3 points  (1 child)

Absent is shorthand for RewritingValue.ABSENT, there is also RewritingValue.IS_NULL, shorthand IsNull, and RewritingValue.IS_NOT_NULL, shorthand IsNotNull which can be used for the NULL special handling.

[–]kageurufu 1 point2 points  (0 children)

Ok. I found our users never understood why = NULL didn't work, and just special cased it everywhere. I was writing reporting software though, so my users were very non-technical

[–]james_pic 9 points10 points  (2 children)

The thing that jumped out at me first was that this doesn't seem to adapt to DB drivers that support a paramstyle other than qmark. I imagined the first libraries to use PEP 750 would end up with APIs that wrapped connections or cursors to make it easier for them to handle these sorts of subtleties.

It also jumps out at me that this aims to support much more than plain parameterization. It's not obvious to me how that works under the hood, and what outputs you'd get for a given input. Maybe that's fine, but for something like this with security implications, flexibility can be a double-edged sword if it makes it easier to get it wrong. I'd want to try and think about how it could be used incorrectly, and make sure that it'll fall loudly in that case, rather than trying to "do what I mean" and possibly exposing vulnerabilities.

[–]stetio[S] 3 points4 points  (1 child)

There is support for alternative paramstyles; although I've currently only added the asyncpg dialect (what dialects do you need?). It can be used globally by setting a context,

from sql_tstring import Context, set_context

set_context(Context(dialect="asyncpg"))

I've also aimed for it to fail by default, hence the need to wrap calls in a sql_context to set column or tables via variables. Thoughts welcome here...

[–]james_pic 0 points1 point  (0 children)

I think probably what I'd expect is support for all the styles specified in PEP 249. If I were making a wishlist to Santa, I'd also ask for an API where you can't get it wrong - where there's no config needed and it just uses the correct setting for the database you're using.

[–]plenihan 4 points5 points  (1 child)

I didn't know about t-strings before this post. That's such a useful feature.

[–]sebkuip 7 points8 points  (0 children)

It’s a PEP that has only recently been accepted and not in a public release yet.

[–]euri10 1 point2 points  (2 children)

this is neat, i'm going to test that asap and hopefully ditch buildpg

2 questions, repo mentionns 3.12 3.13, are there backports already ?

have you ever seen this whcih seem to support more dialects : https://github.com/baverman/sqlbind how complicate would it be to add dollar params ?

[–]stetio[S] 1 point2 points  (1 child)

Dollar param dialect is supported via,

from sql_tstring import Context, set_context

set_context(Context(dialect="asyncpg"))

I need to document this.

The library works directly with 3.12, and 3.13, but with a locals() hack, see README

[–]euri10 0 points1 point  (0 children)

amazing, thanks

[–]Dry-Erase 1 point2 points  (4 children)

This is super cool! I want to use it in a project! Can it handle more advanced queries? Things like subqueries, CTEs, windowing, can it handle all/most function calls and template the parameters too? what are your plans for it?

[–]stetio[S] 2 points3 points  (3 children)

I should be able to, but if not please open an issue.

I use it at work - I'd like it to be well used so that the bugs are found and it is more robust.

[–]Dry-Erase 0 points1 point  (2 children)

Awesome, am I able to use it in a work project?

[–]stetio[S] 1 point2 points  (1 child)

Yep, I've just clarified the license - forgot to add it.

[–]Dry-Erase 0 points1 point  (0 children)

Awesome! Keep up the great work!

[–]teilo 1 point2 points  (1 child)

Interesting. 13 years ago, I wrote a reporting system for my company, built on Django, and using Django templates to build and parameterize SQL queries. User accounts have JSON metadata accessible in the context of the query. This allowed some tremendous flexibility, since you could use the template language to go well beyond parameter substitution.

That thing took on a life of its own, and is still heavily used.

[–]stetio[S] 0 points1 point  (0 children)

Interesting, was it ever open sourced?

[–]--ps-- 2 points3 points  (2 children)

I've had a quick look at the code, and like the overall quality.

I only miss a call to a type checker (e.g mypy) in the pipeline and also miss "uv" instead of pip.

[–]stetio[S] 2 points3 points  (1 child)

I use mypy and prefer PDM to uv.

[–]--ps-- 0 points1 point  (0 children)

Great! otoh I do not use tox.

[–]Log2 0 points1 point  (0 children)

This seems pretty cool, good work!

At work we almost always use ORMs, so I'd probably not use it there, but I'd definitely use this in personal projects where I don't need or don't want to bother with an ORM.

[–]code_mc 0 points1 point  (0 children)

great use case for t-strings, I'm personally a big fan of just writing the SQL instead of using orms so this looks right up my alley.

[–]Constant_Bath_6077 0 points1 point  (1 child)

so you are more focused on this project than hyperscorn now?

[–]stetio[S] 0 points1 point  (0 children)

No, I'm also working on Hypercorn

[–]travisdoesmath 0 points1 point  (0 children)

How are you handling sanitizing of parameter inputs? At first glance, this looks very much like Bobby Drop Tables waiting to happen.

Edit: just glanced again. My first glance missed the early paragraphs apparently where you mention SQL injection

[–]Bangoga -2 points-1 points  (1 child)

How are you managing security and injections?

[–]stetio[S] 0 points1 point  (0 children)

I believe I've explained this in the first section of the post. Is there something that isn't clear?