samuelcolvin / buildpg

Query building for the postgresql prepared statements and asyncpg.
MIT License
85 stars 12 forks source link

cant cast to arrays because of brackets #41

Open euri10 opened 2 years ago

euri10 commented 2 years ago

related to #31 (and #27 to some extent) I know I can use RawDangerous, just wanted to mention it

this works:

V('x').cast("int")
<SQL: "x::int">

but casting to arrays fails because of the brackets:

V('x').cast("int[]")
Traceback (most recent call last):
  File "/home/lotso/.asdf/installs/python/3.10.5/lib/python3.10/code.py", line 90, in runcode
    exec(code, self.locals)
  File "<input>", line 1, in <module>
  File "/home/lotso/PycharmProjects/buildpg/buildpg/logic.py", line 217, in cast
    return self.operate(Operator.cast, as_var(cast_type))
  File "/home/lotso/PycharmProjects/buildpg/buildpg/logic.py", line 276, in as_var
    return Var(n)
  File "/home/lotso/PycharmProjects/buildpg/buildpg/logic.py", line 316, in __init__
    super().__init__(VarLiteral(v1), op=op, v2=v2)
  File "/home/lotso/PycharmProjects/buildpg/buildpg/components.py", line 60, in __init__
    check_word(s)
  File "/home/lotso/PycharmProjects/buildpg/buildpg/components.py", line 25, in check_word
    raise UnsafeError(f'str contain unsafe (non word) characters: "{s}"')
buildpg.components.UnsafeError: str contain unsafe (non word) characters: "int[]"

it feels like there are some funcs that could (should ?) allow unsafe characters, space in aliases, brackets in cast ?

I just dicovered that, having to write the below snippet. It's part of a HAVING clause logic I intended to push, but I think I would be shooting myself i the foot here, since countries is client-controlled...

    if countries:
        countries_logic = S(countries).operate(RawDangerous('::character varying[]')).contained_by(RawDangerous("array_agg(distinct dc.alpha_2)"))
        having_logic = (
            countries_logic
            if not having_logic
            else iand(having_logic, countries_logic)
countries
['CI']
S(countries).operate(RawDangerous('::character varying[]')).contained_by(RawDangerous("array_agg(distinct dc.alpha_2)"))
<SQL: "(['CI']::character varying[]) <@ array_agg(distinct dc.alpha_2)">
vincentsarago commented 2 years ago

Slightly related I cannot cast variable to character varying because of the space

from buildpg import funcs
funcs.cast("value", "character varying")

---------------------------------------------------------------------------
UnsafeError                               Traceback (most recent call last)
Input In [4], in <cell line: 1>()
----> 1 funcs.cast("value", "character varying")
...

buildpg/components.py:25, in check_word(s)
     23     raise TypeError('value is not a string')
     24 if NOT_WORD.search(s):
---> 25     raise UnsafeError(f'str contain unsafe (non word) characters: "{s}"')

UnsafeError: str contain unsafe (non word) characters: "character varying"