Issue: issue inserting list of dicts as JSON binary into model
Author: bgriffen
State: closed
Created: 2022-03-07 12:00:23

I have a simple list of dicts I want to insert into my LabelModel table in my postgres DB

```python
l = [{'label': 'A',
  'x': 132.56338500976562,
  'y': 333.7539367675781,
  'width': 183.78598022460938,
  'height': 404.6580505371094,
  'score': 0.9848693609237671},
 {'label': 'B',
  'x': 179.97842407226562,
  'y': 367.101318359375,
  'width': 127.43386840820312,
  'height': 59.047882080078125,
  'score': 0.965998113155365},
 {'label': 'C',
  'x': 431.1368408203125,
  'y': 365.9712219238281,
  'width': 127.59616088867188,
  'height': 60.77362060546875,
  'score': 0.9622131586074829}]
```

```python
from playhouse.postgres_ext import BinaryJSONField

class TblLabelByAI(BaseModel):
  name = pw.TextField()
  labels = BinaryJSONField()
  modified_at = pw.DateField(default=datetime.datetime.utcnow)
```

```python
q = {"imagename":"testname","labels":l}
TblLabelByAI.get_or_create(**q)
```

Is there any reason I get the following:


```bash
ProgrammingError: operator does not exist: jsonb = record
LINE 1: ...imagename.jpg') AND ("t1"."labels" = (CAST('{...
                                                             ^
HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.

```

Peewee: 3.14.9  
Python 3.8

@coleifer - amazing work btw

I'm not sure, this is working for me:

```python
from peewee import *
from playhouse.postgres_ext import *

db = PostgresqlExtDatabase('peewee_test')

class Reg(Model):
    key = CharField()
    value = BinaryJSONField()
    class Meta:
        database = db

db.drop_tables([Reg])
db.create_tables([Reg])

data = [{'k1': 'v1', 'k2': 'v2'}]
Reg.get_or_create(key='k1', value=data)

db.drop_tables([Reg])
```

I just tried your simple list but all my other code the same and it inserted, but my list from my example doesn't when I replaced it. Is it something about those numeric values (e.g. precision?)

**Update** - ok it works with one element, but not all three :'(.  A multi-element list should be fine isn't it? 

e.g. `data = [{'x': 123, 'y': 123},{'x': 123, 'y': 123},{'x': 123, 'y': 123}]`

**Update 2** - when I changed to just `.create(**q)` it works, `get_or_create` doesn't seem to work for my list for some strange reason.

Very strange... here is the full error if it helps?

```python
File text.py:173, in insert_update_ai_label(short_name, labels, model_name)
    171 q = {"gcs_name":short_name,"labels":labels,"model_id":mout.id}
    172 print(q)
--> 173 qout,_ = bm.TblLabelByAI.get_or_create(**q)
    174 return ql,q

File ~/miniforge3/lib/python3.8/site-packages/peewee.py:6538, in Model.get_or_create(cls, **kwargs)
   6535     query = query.where(getattr(cls, field) == value)
   6537 try:
-> 6538     return query.get(), False
   6539 except cls.DoesNotExist:
   6540     try:

File ~/miniforge3/lib/python3.8/site-packages/peewee.py:6953, in BaseModelSelect.get(self, database)
   6951 clone._cursor_wrapper = None
   6952 try:
-> 6953     return clone.execute(database)[0]
   6954 except IndexError:
   6955     sql, params = clone.sql()

File ~/miniforge3/lib/python3.8/site-packages/peewee.py:1911, in database_required.<locals>.inner(self, database, *args, **kwargs)
   1908 if not database:
   1909     raise InterfaceError('Query must be bound to a database in order '
   1910                          'to call "%s".' % method.__name__)
-> 1911 return method(self, database, *args, **kwargs)

File ~/miniforge3/lib/python3.8/site-packages/peewee.py:1982, in BaseQuery.execute(self, database)
   1980 @database_required
   1981 def execute(self, database):
-> 1982     return self._execute(database)

File ~/miniforge3/lib/python3.8/site-packages/peewee.py:2155, in SelectBase._execute(self, database)
   2153 def _execute(self, database):
   2154     if self._cursor_wrapper is None:
-> 2155         cursor = database.execute(self)
   2156         self._cursor_wrapper = self._get_cursor_wrapper(cursor)
   2157     return self._cursor_wrapper

File ~/miniforge3/lib/python3.8/site-packages/playhouse/postgres_ext.py:494, in PostgresqlExtDatabase.execute(self, query, commit, named_cursor, array_size, **context_options)
    492 if named_cursor:
    493     commit = __named_cursor__
--> 494 cursor = self.execute_sql(sql, params, commit=commit)
    495 if named_cursor:
    496     cursor = FetchManyCursor(cursor, array_size)

File ~/miniforge3/lib/python3.8/site-packages/peewee.py:3167, in Database.execute_sql(self, sql, params, commit)
   3165     else:
   3166         if commit and not self.in_transaction():
-> 3167             self.commit()
   3168 return cursor

File ~/miniforge3/lib/python3.8/site-packages/peewee.py:2933, in ExceptionWrapper.__exit__(self, exc_type, exc_value, traceback)
   2931 new_type = self.exceptions[exc_type.__name__]
   2932 exc_args = exc_value.args
-> 2933 reraise(new_type, new_type(exc_value, *exc_args), traceback)

File ~/miniforge3/lib/python3.8/site-packages/peewee.py:191, in reraise(tp, value, tb)
    189 def reraise(tp, value, tb=None):
    190     if value.__traceback__ is not tb:
--> 191         raise value.with_traceback(tb)
    192     raise value

File ~/miniforge3/lib/python3.8/site-packages/peewee.py:3160, in Database.execute_sql(self, sql, params, commit)
   3158 cursor = self.cursor(commit)
   3159 try:
-> 3160     cursor.execute(sql, params or ())
   3161 except Exception:
   3162     if self.autorollback and not self.in_transaction():

ProgrammingError: operator does not exist: jsonb = record
LINE 1: ...imagename.jpg') AND ("t1"."labels" = (CAST('{...
                                                             ^
HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
```

I think I see the issue -- Peewee treats top-level lists a little differently when used in expressions.

This workaround should work:

```python
from psycopg2.extras import Json

data = [{'x': 123, 'y': 123},{'x': 123, 'y': 123},{'x': 123, 'y': 123}]
data = Json(data)
```