def test_as_string(self, conn): assert sql.Literal(None).as_string(conn) == "NULL" assert noe(sql.Literal("foo").as_string(conn)) == "'foo'" assert sql.Literal(42).as_string(conn) == "42" assert ( sql.Literal(dt.date(2017, 1, 1)).as_string(conn) == "'2017-01-01'" )
def test_sum_inplace(self, conn): obj = sql.Composed([sql.SQL("foo ")]) obj += sql.Literal("bar") assert isinstance(obj, sql.Composed) assert noe(obj.as_string(conn)) == "foo 'bar'" obj = sql.Composed([sql.SQL("foo ")]) obj += sql.Composed([sql.Literal("bar")]) assert isinstance(obj, sql.Composed) assert noe(obj.as_string(conn)) == "foo 'bar'"
def test_quote_percent(conn): cur = conn.cursor() cur.execute(sql.SQL("select {ch}").format(ch=sql.Literal("%"))) assert cur.fetchone()[0] == "%" cur.execute( sql.SQL("select {ch} = chr(%s)").format(ch=sql.Literal("%")), (ord("%"), ), ) assert cur.fetchone()[0] is True
def test_quote_1byte(conn): cur = conn.cursor() query = sql.SQL("select {ch} = %s::bytea") for i in range(0, 256): cur.execute(query.format(ch=sql.Literal(bytes([i]))), (fr"\x{i:02x}", )) assert cur.fetchone()[0] is True, i
def test_eq(self): assert sql.Placeholder("foo") == sql.Placeholder("foo") assert sql.Placeholder("foo") != sql.Placeholder("bar") assert sql.Placeholder("foo") != "foo" assert sql.Placeholder() == sql.Placeholder() assert sql.Placeholder("foo") != sql.Placeholder() assert sql.Placeholder("foo") != sql.Literal("foo")
def test_must_be_adaptable(self, conn): class Foo: pass s = sql.SQL("select {0};").format(sql.Literal(Foo())) with pytest.raises(ProgrammingError): s.as_string(conn)
def test_quote_int(conn, val, expr): tx = Transformer() assert tx.get_dumper(val, Format.TEXT).quote(val) == expr cur = conn.cursor() cur.execute(sql.SQL("select {v}, -{v}").format(v=sql.Literal(val))) assert cur.fetchone() == (val, -val)
def test_join(self, conn): obj = sql.SQL(", ").join( [sql.Identifier("foo"), sql.SQL("bar"), sql.Literal(42)] ) assert isinstance(obj, sql.Composed) assert obj.as_string(conn) == '"foo", bar, 42' obj = sql.SQL(", ").join( sql.Composed( [sql.Identifier("foo"), sql.SQL("bar"), sql.Literal(42)] ) ) assert isinstance(obj, sql.Composed) assert obj.as_string(conn) == '"foo", bar, 42' obj = sql.SQL(", ").join([]) assert obj == sql.Composed([])
def test_quote_none(conn): tx = Transformer() assert tx.get_dumper(None, Format.TEXT).quote(None) == b"NULL" cur = conn.cursor() cur.execute(sql.SQL("select {v}").format(v=sql.Literal(None))) assert cur.fetchone()[0] is None
def test_quote_1char(conn): cur = conn.cursor() query = sql.SQL("select {ch} = chr(%s::int)") for i in range(1, 256): if chr(i) == "%": continue cur.execute(query.format(ch=sql.Literal(chr(i))), (i, )) assert cur.fetchone()[0] is True, chr(i)
def test_quote_bool(conn, val): tx = Transformer() assert tx.get_dumper( val, Format.TEXT).quote(val) == str(val).lower().encode("ascii") cur = conn.cursor() cur.execute(sql.SQL("select {v}").format(v=sql.Literal(val))) assert cur.fetchone()[0] is val
def test_dumper_protocol(conn): # This class doesn't inherit from adapt.Dumper but passes a mypy check from .adapters_example import MyStrDumper conn.adapters.register_dumper(str, MyStrDumper) cur = conn.execute("select %s", ["hello"]) assert cur.fetchone()[0] == "hellohello" cur = conn.execute("select %s", [["hi", "ha"]]) assert cur.fetchone()[0] == ["hihi", "haha"] assert sql.Literal("hello").as_string(conn) == "'qelloqello'"
def test_dump_date(self, conn, val, expr, fmt_in): val = as_date(val) cur = conn.cursor() cur.execute(f"select '{expr}'::date = %{fmt_in}", (val, )) assert cur.fetchone()[0] is True cur.execute( sql.SQL("select {}::date = {}").format( sql.Literal(val), sql.Placeholder(format=fmt_in)), (val, ), ) assert cur.fetchone()[0] is True
def test_quote_numeric(conn, val, expr): val = Decimal(val) tx = Transformer() assert tx.get_dumper(val, Format.TEXT).quote(val) == expr cur = conn.cursor() cur.execute(sql.SQL("select {v}, -{v}").format(v=sql.Literal(val))) r = cur.fetchone() if val.is_nan(): assert isnan(r[0]) and isnan(r[1]) else: assert r == (val, -val)
def test_quote_float(conn, val, expr): tx = Transformer() assert tx.get_dumper(val, Format.TEXT).quote(val) == expr cur = conn.cursor() cur.execute(sql.SQL("select {v}, -{v}").format(v=sql.Literal(val))) r = cur.fetchone() if isnan(val): assert isnan(r[0]) and isnan(r[1]) else: if isinstance(r[0], Decimal): r = tuple(map(float, r)) assert r == (val, -val)
def test_quote_1byte(conn, scs, pytype): messages = [] conn.add_notice_handler(lambda msg: messages.append(msg.message_primary)) conn.execute(f"set standard_conforming_strings to {scs}") conn.execute("set escape_string_warning to on") cur = conn.cursor() query = sql.SQL("select {ch} = set_byte('x', 0, %s)") for i in range(0, 256): obj = pytype(bytes([i])) cur.execute(query.format(ch=sql.Literal(obj)), (i, )) assert cur.fetchone()[0] is True, i # No "nonstandard use of \\ in a string literal" warning assert not messages
def test_quote_1char(conn, scs): messages = [] conn.add_notice_handler(lambda msg: messages.append(msg.message_primary)) conn.execute(f"set standard_conforming_strings to {scs}") conn.execute("set escape_string_warning to on") cur = conn.cursor() query = sql.SQL("select {ch} = chr(%s)") for i in range(1, 256): if chr(i) == "%": continue cur.execute(query.format(ch=sql.Literal(chr(i))), (i, )) assert cur.fetchone()[0] is True, chr(i) # No "nonstandard use of \\ in a string literal" warning assert not messages
def test_as_bytes(self, conn): assert sql.Literal(None).as_bytes(conn) == b"NULL" assert noe(sql.Literal("foo").as_bytes(conn)) == b"'foo'" assert sql.Literal(42).as_bytes(conn) == b"42" assert (sql.Literal(dt.date(2017, 1, 1)).as_bytes(conn) == b"'2017-01-01'") conn.execute("set client_encoding to utf8") assert sql.Literal(eur).as_bytes(conn) == f"'{eur}'".encode() conn.execute("set client_encoding to latin9") assert sql.Literal(eur).as_bytes(conn) == f"'{eur}'".encode("latin9")
def quote_literal(value, conn=None): return sql.Literal(value).as_string(conn)
def test_compose_literal(self, conn): s = sql.SQL("select {0};").format(sql.Literal(dt.date(2016, 12, 31))) s1 = s.as_string(conn) assert s1 == "select '2016-12-31';"
def test_minus_minus_quote(conn, pgtype): cur = conn.cursor() cast = f"::{pgtype}" if pgtype is not None else "" cur.execute(sql.SQL("select -{}{}").format(sql.Literal(-1), sql.SQL(cast))) result = cur.fetchone()[0] assert result == 1
def test_braces_escape(self, conn): s = sql.SQL("{{{0}}}").format(sql.Literal(7)) assert s.as_string(conn) == "{7}" s = sql.SQL("{{1,{0}}}").format(sql.Literal(7)) assert s.as_string(conn) == "{1,7}"
def test_percent_escape(self, conn): s = sql.SQL("42 % {0}").format(sql.Literal(7)) s1 = s.as_string(conn) assert s1 == "42 % 7"
def test_repr(self): assert repr(sql.Literal("foo")) == "Literal('foo')" assert str(sql.Literal("foo")) == "Literal('foo')"
def test_init(self): assert isinstance(sql.Literal("foo"), sql.Literal) assert isinstance(sql.Literal("foo"), sql.Literal) assert isinstance(sql.Literal(b"foo"), sql.Literal) assert isinstance(sql.Literal(42), sql.Literal) assert isinstance(sql.Literal(dt.date(2016, 12, 31)), sql.Literal)
def test_must_be_adaptable(self, conn): class Foo: pass with pytest.raises(ProgrammingError): sql.Literal(Foo()).as_string(conn)
def test_eq(self): assert sql.SQL("foo") == sql.SQL("foo") assert sql.SQL("foo") != sql.SQL("bar") assert sql.SQL("foo") != "foo" assert sql.SQL("foo") != sql.Literal("foo")
def test_join(self, conn): obj = sql.Composed([sql.Literal("foo"), sql.Identifier("b'ar")]) obj = obj.join(", ") assert isinstance(obj, sql.Composed) assert noe(obj.as_string(conn)) == "'foo', \"b'ar\""
def test_eq(self): L = [sql.Literal("foo"), sql.Identifier("b'ar")] l2 = [sql.Literal("foo"), sql.Literal("b'ar")] assert sql.Composed(L) == sql.Composed(list(L)) assert sql.Composed(L) != L assert sql.Composed(L) != sql.Composed(l2)
def test_repr(self): obj = sql.Composed([sql.Literal("foo"), sql.Identifier("b'ar")]) assert ( repr(obj) == """Composed([Literal('foo'), Identifier("b'ar")])""") assert str(obj) == repr(obj)