@@ -462,15 +462,15 @@ cdef class Buffer:
462
462
"""
463
463
line_sender_buffer_clear(self._impl)
464
464
465
- def __len__(self):
465
+ def __len__(self) -> int :
466
466
"""
467
467
The current number of bytes currently in the buffer .
468
468
469
469
Equivalent (but cheaper) to ``len (str (sender))``.
470
470
"""
471
471
return line_sender_buffer_size(self._impl)
472
472
473
- def __str__(self):
473
+ def __str__(self) -> str :
474
474
""" Return the constructed buffer as a string. Use for debugging."""
475
475
return self._to_str()
476
476
@@ -595,22 +595,19 @@ cdef class Buffer:
595
595
cdef line_sender_error* err = NULL
596
596
if not line_sender_buffer_at(self._impl, ts.value, &err):
597
597
raise c_err_to_py(err)
598
- self._may_trigger_row_complete()
599
598
return 0
600
599
601
600
cdef inline int _at_dt(self, datetime dt) except -1:
602
601
cdef int64_t value = datetime_to_nanos(dt)
603
602
cdef line_sender_error* err = NULL
604
603
if not line_sender_buffer_at(self._impl, value, &err):
605
604
raise c_err_to_py(err)
606
- self._may_trigger_row_complete()
607
605
return 0
608
606
609
607
cdef inline int _at_now(self) except -1:
610
608
cdef line_sender_error* err = NULL
611
609
if not line_sender_buffer_at_now(self._impl, &err):
612
610
raise c_err_to_py(err)
613
- self._may_trigger_row_complete()
614
611
return 0
615
612
616
613
cdef inline int _at(self, object ts) except -1:
@@ -634,6 +631,7 @@ cdef class Buffer:
634
631
"""
635
632
Add a row to the buffer .
636
633
"""
634
+ cdef bint wrote_fields = False
637
635
self._set_marker()
638
636
try:
639
637
self._table(table_name)
@@ -644,14 +642,22 @@ cdef class Buffer:
644
642
if symbols is not None:
645
643
for name, value in symbols.items():
646
644
self._symbol(name, value)
645
+ wrote_fields = True
647
646
if columns is not None:
648
647
for name, value in columns.items():
649
- self._column(name, value)
650
- self._at(at)
651
- self._clear_marker()
648
+ if value is not None:
649
+ self._column(name, value)
650
+ wrote_fields = True
651
+ if wrote_fields:
652
+ self._at(at)
653
+ self._clear_marker()
654
+ else:
655
+ self._rewind_to_marker()
652
656
except:
653
657
self._rewind_to_marker()
654
658
raise
659
+ if wrote_fields:
660
+ self._may_trigger_row_complete()
655
661
656
662
def row(
657
663
self,
@@ -660,7 +666,8 @@ cdef class Buffer:
660
666
symbols: Optional[Dict[str, str]]=None,
661
667
columns: Optional[Dict[
662
668
str,
663
- Union[bool, int, float, str, TimestampMicros, datetime]]]=None,
669
+ Union[None, bool, int, float, str, TimestampMicros, datetime]]
670
+ ]=None,
664
671
at: Union[None, TimestampNanos, datetime]=None):
665
672
"""
666
673
Add a single row (line) to the buffer .
@@ -679,7 +686,8 @@ cdef class Buffer:
679
686
' col3' : 3.14 ,
680
687
' col4' : ' xyz' ,
681
688
' col5' : TimestampMicros(123456789 ),
682
- ' col6' : datetime(2019 , 1 , 1 , 12 , 0 , 0 )},
689
+ ' col6' : datetime(2019 , 1 , 1 , 12 , 0 , 0 ),
690
+ ' col7' : None },
683
691
at = TimestampNanos(123456789 ))
684
692
685
693
# Only symbols specified. Designated timestamp assigned by the db.
@@ -707,10 +715,38 @@ cdef class Buffer:
707
715
understand the difference between the ``SYMBOL`` and ``STRING`` types
708
716
(TL;DR: symbols are interned strings).
709
717
718
+ Column values can be specified with Python types directly and map as so:
719
+
720
+ .. list - table::
721
+ :header- rows: 1
722
+
723
+ * - Python type
724
+ - Serialized as ILP type
725
+ * - ``bool ``
726
+ - `BOOLEAN < https:// questdb.io/ docs/ reference/ api/ ilp/ columnset- types# boolean>`_
727
+ * - ``int ``
728
+ - `INTEGER < https:// questdb.io/ docs/ reference/ api/ ilp/ columnset- types# integer>`_
729
+ * - ``float ``
730
+ - `FLOAT < https:// questdb.io/ docs/ reference/ api/ ilp/ columnset- types# float>`_
731
+ * - ``str ``
732
+ - `STRING < https:// questdb.io/ docs/ reference/ api/ ilp/ columnset- types# string>`_
733
+ * - ``datetime.datetime`` and ``TimestampMicros``
734
+ - `TIMESTAMP < https:// questdb.io/ docs/ reference/ api/ ilp/ columnset- types# timestamp>`_
735
+ * - ``None ``
736
+ - * Column is skipped and not serialized.*
737
+
738
+ If the destination table was already created, then the columns types
739
+ will be cast to the types of the existing columns whenever possible
740
+ (Refer to the QuestDB documentation pages linked above).
741
+
710
742
:param table_name: The name of the table to which the row belongs.
711
743
:param symbols: A dictionary of symbol column names to ``str `` values.
712
744
:param columns: A dictionary of column names to ``bool ``, ``int ``,
713
745
``float ``, ``str ``, ``TimestampMicros`` or ``datetime`` values.
746
+ As a convenience, you can also pass a ``None `` value, however - due
747
+ to ILP protocol limitations - this will skip the column rather
748
+ necessarily writing a ``NULL `` value, so if the column did not exist
749
+ yet it will not be created.
714
750
:param at: The timestamp of the row. If ``None ``, timestamp is assigned
715
751
by the server. If ``datetime``, the timestamp is converted to
716
752
nanoseconds. A nanosecond unix epoch timestamp can be passed
@@ -764,9 +800,9 @@ cdef class Buffer:
764
800
765
801
# buffer.tabular(
766
802
# 'table_name',
767
- # [[True, 123 , 3.14, 'xyz'],
768
- # [False, 456 , 6.28, 'abc'],
769
- # [True, 789 , 9.87, 'def']],
803
+ # [[True, None , 3.14, 'xyz'],
804
+ # [False, 123 , 6.28, 'abc'],
805
+ # [True, 456 , 9.87, 'def']],
770
806
# header=['col1', 'col2', 'col3', 'col4'],
771
807
# at=datetime.datetime.utcnow())
772
808
@@ -848,7 +884,7 @@ cdef class Buffer:
848
884
# buffer.tabular(
849
885
# 'table_name',
850
886
# [['abc', 123, 3.14, 'xyz'],
851
- # ['def', 456, 6.28 , 'abc'],
887
+ # ['def', 456, None , 'abc'],
852
888
# ['ghi', 789, 9.87, 'def']],
853
889
# header=['col1', 'col2', 'col3', 'col4'],
854
890
# symbols=True) # `col1` and `col4` are SYMBOL columns.
@@ -941,7 +977,7 @@ cdef class Sender:
941
977
sender.flush()
942
978
943
979
944
- **Auto-flushing (on by default)**
980
+ **Auto-flushing (on by default, watermark at 63KiB )**
945
981
946
982
To avoid accumulating very large buffers, the sender will flush the buffer
947
983
automatically once its buffer reaches a certain byte-size watermark.
@@ -987,14 +1023,14 @@ cdef class Sender:
987
1023
* A special ``'insecure_skip_verify'`` string: Dangerously disable all
988
1024
TLS certificate verification (do *NOT* use in production environments).
989
1025
990
- **Positional constructor arguments for the `` Sender(..)`` **
1026
+ **Positional constructor arguments for the Sender(..)**
991
1027
992
1028
* ``host``: Hostname or IP address of the QuestDB server.
993
1029
994
1030
* ``port``: Port number of the QuestDB server.
995
1031
996
1032
997
- **Keyword-only constructor arguments for the `` Sender(..)`` **
1033
+ **Keyword-only constructor arguments for the Sender(..)**
998
1034
999
1035
* ``interface`` (``str``): Network interface to bind to.
1000
1036
Set this if you have an accelerated network interface (e.g. Solarflare)
@@ -1011,13 +1047,15 @@ cdef class Sender:
1011
1047
This field is expressed in milliseconds. The default is 15 seconds.
1012
1048
1013
1049
* ``init_capacity`` (``int``): Initial buffer capacity of the internal buffer.
1014
- *See :class:`Buffer`'s constructor for more details.*
1050
+ *Default: 65536 (64KiB).*
1051
+ *See Buffer's constructor for more details.*
1015
1052
1016
1053
* ``max_name_length`` (``int``): Maximum length of a table or column name.
1017
- *See :class:` Buffer` 's constructor for more details.*
1054
+ *See Buffer's constructor for more details.*
1018
1055
1019
1056
* ``auto_flush`` (``bool`` or ``int``): Whether to automatically flush the
1020
1057
buffer when it reaches a certain byte-size watermark.
1058
+ *Default: 64512 (63KiB).*
1021
1059
*See above for details.*
1022
1060
"""
1023
1061
@@ -1195,7 +1233,7 @@ cdef class Sender:
1195
1233
if self ._buffer is not None :
1196
1234
self ._buffer._row_complete_sender = PyWeakref_NewRef(self , None )
1197
1235
1198
- def __enter__ (self ):
1236
+ def __enter__ (self ) -> Sender :
1199
1237
"""Call :func:`Sender.connect` at the start of a ``with`` block."""
1200
1238
self.connect()
1201
1239
return self
@@ -1210,7 +1248,7 @@ cdef class Sender:
1210
1248
"""
1211
1249
return str(self._buffer )
1212
1250
1213
- def __len__(self ):
1251
+ def __len__(self ) -> int :
1214
1252
"""
1215
1253
Number of bytes of unsent data in the internal buffer.
1216
1254
0 commit comments