datanommer.models 1.2.0__py3-none-any.whl → 1.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- datanommer/models/__init__.py +70 -14
- datanommer/models/testing/__init__.py +12 -4
- {datanommer_models-1.2.0.dist-info → datanommer_models-1.3.0.dist-info}/METADATA +2 -1
- {datanommer_models-1.2.0.dist-info → datanommer_models-1.3.0.dist-info}/RECORD +6 -6
- {datanommer_models-1.2.0.dist-info → datanommer_models-1.3.0.dist-info}/LICENSE +0 -0
- {datanommer_models-1.2.0.dist-info → datanommer_models-1.3.0.dist-info}/WHEEL +0 -0
datanommer/models/__init__.py
CHANGED
@@ -168,7 +168,7 @@ def add(message):
|
|
168
168
|
# https://docs.sqlalchemy.org/en/14/core/custom_types.html#marshal-json-strings
|
169
169
|
|
170
170
|
|
171
|
-
class
|
171
|
+
class _JSONEncodedDict(TypeDecorator):
|
172
172
|
"""Represents an immutable structure as a json-encoded string."""
|
173
173
|
|
174
174
|
impl = UnicodeText
|
@@ -227,7 +227,7 @@ class Message(DeclarativeBase):
|
|
227
227
|
crypto = Column(UnicodeText)
|
228
228
|
source_name = Column(Unicode, default="datanommer")
|
229
229
|
source_version = Column(Unicode, default=lambda context: __version__)
|
230
|
-
msg = Column(
|
230
|
+
msg = Column(_JSONEncodedDict, nullable=False)
|
231
231
|
headers = Column(postgresql.JSONB(none_as_null=True))
|
232
232
|
users = relationship(
|
233
233
|
"User",
|
@@ -359,13 +359,10 @@ class Message(DeclarativeBase):
|
|
359
359
|
return self.as_dict(request)
|
360
360
|
|
361
361
|
@classmethod
|
362
|
-
def
|
362
|
+
def make_query(
|
363
363
|
cls,
|
364
364
|
start=None,
|
365
365
|
end=None,
|
366
|
-
page=1,
|
367
|
-
rows_per_page=100,
|
368
|
-
order="asc",
|
369
366
|
msg_id=None,
|
370
367
|
users=None,
|
371
368
|
not_users=None,
|
@@ -376,7 +373,6 @@ class Message(DeclarativeBase):
|
|
376
373
|
topics=None,
|
377
374
|
not_topics=None,
|
378
375
|
contains=None,
|
379
|
-
defer=False,
|
380
376
|
):
|
381
377
|
"""Flexible query interface for messages.
|
382
378
|
|
@@ -404,11 +400,6 @@ class Message(DeclarativeBase):
|
|
404
400
|
|
405
401
|
(user == 'ralph') AND
|
406
402
|
NOT (category == 'bodhi' OR category == 'wiki')
|
407
|
-
|
408
|
-
----
|
409
|
-
|
410
|
-
If the `defer` argument evaluates to True, the query won't actually
|
411
|
-
be executed, but a SQLAlchemy query object returned instead.
|
412
403
|
"""
|
413
404
|
|
414
405
|
users = users or []
|
@@ -468,23 +459,88 @@ class Message(DeclarativeBase):
|
|
468
459
|
if not_topics:
|
469
460
|
query = query.where(not_(or_(*(Message.topic == topic for topic in not_topics))))
|
470
461
|
|
462
|
+
return query
|
463
|
+
|
464
|
+
@classmethod
|
465
|
+
def grep(
|
466
|
+
cls,
|
467
|
+
*,
|
468
|
+
page=1,
|
469
|
+
rows_per_page=100,
|
470
|
+
order="asc",
|
471
|
+
defer=False,
|
472
|
+
**kwargs,
|
473
|
+
):
|
474
|
+
"""Flexible query interface for messages.
|
475
|
+
|
476
|
+
Arguments are filters. start and end should be :mod:`datetime` objs.
|
477
|
+
|
478
|
+
Other filters should be lists of strings. They are applied in a
|
479
|
+
conjunctive-normal-form (CNF) kind of way
|
480
|
+
|
481
|
+
for example, the following::
|
482
|
+
|
483
|
+
users = ['ralph', 'lmacken']
|
484
|
+
categories = ['bodhi', 'wiki']
|
485
|
+
|
486
|
+
should return messages where
|
487
|
+
|
488
|
+
(user=='ralph' OR user=='lmacken') AND
|
489
|
+
(category=='bodhi' OR category=='wiki')
|
490
|
+
|
491
|
+
Furthermore, you can use a negative version of each argument.
|
492
|
+
|
493
|
+
users = ['ralph']
|
494
|
+
not_categories = ['bodhi', 'wiki']
|
495
|
+
|
496
|
+
should return messages where
|
497
|
+
|
498
|
+
(user == 'ralph') AND
|
499
|
+
NOT (category == 'bodhi' OR category == 'wiki')
|
500
|
+
|
501
|
+
----
|
502
|
+
|
503
|
+
The ``jsons`` argument is a list of jsonpath filters, please refer to
|
504
|
+
`PostgreSQL's documentation
|
505
|
+
<https://www.postgresql.org/docs/current/functions-json.html#FUNCTIONS-SQLJSON-PATH>`_
|
506
|
+
on the matter to learn how to build the jsonpath expression.
|
507
|
+
|
508
|
+
The ``jsons_and`` argument is similar to the ``jsons`` argument, but all
|
509
|
+
the values must match for a message to be returned.
|
510
|
+
"""
|
511
|
+
query = cls.make_query(**kwargs)
|
471
512
|
# Finally, tag on our pagination arguments
|
472
|
-
|
513
|
+
Message = cls
|
514
|
+
|
515
|
+
query_total = query.with_only_columns(func.count(Message.id))
|
516
|
+
total = None
|
473
517
|
query = query.order_by(getattr(Message.timestamp, order)())
|
474
518
|
|
475
519
|
if not rows_per_page:
|
476
520
|
pages = 1
|
477
521
|
else:
|
522
|
+
total = session.scalar(query_total)
|
478
523
|
pages = int(math.ceil(total / float(rows_per_page)))
|
479
524
|
query = query.offset(rows_per_page * (page - 1)).limit(rows_per_page)
|
480
525
|
|
481
526
|
if defer:
|
482
|
-
|
527
|
+
if total is None:
|
528
|
+
total = session.scalar(query_total)
|
529
|
+
return total, pages, query
|
483
530
|
else:
|
484
531
|
# Execute!
|
485
532
|
messages = session.scalars(query).all()
|
533
|
+
if pages == 1:
|
534
|
+
total = len(messages)
|
486
535
|
return total, pages, messages
|
487
536
|
|
537
|
+
@classmethod
|
538
|
+
def get_first(cls, *, order="asc", **kwargs):
|
539
|
+
"""Get the first message matching the regular grep filters."""
|
540
|
+
query = cls.make_query(**kwargs)
|
541
|
+
query = query.order_by(getattr(Message.timestamp, order)())
|
542
|
+
return session.scalars(query).first()
|
543
|
+
|
488
544
|
|
489
545
|
class NamedSingleton:
|
490
546
|
id = Column(Integer, primary_key=True, autoincrement=True)
|
@@ -21,8 +21,8 @@ def datanommer_db_url(postgresql_proc):
|
|
21
21
|
)
|
22
22
|
|
23
23
|
|
24
|
-
@pytest.fixture()
|
25
|
-
def
|
24
|
+
@pytest.fixture(scope="session")
|
25
|
+
def datanommer_db_engine(postgresql_proc, datanommer_db_url):
|
26
26
|
with DatabaseJanitor(
|
27
27
|
user=postgresql_proc.user,
|
28
28
|
host=postgresql_proc.host,
|
@@ -32,12 +32,20 @@ def datanommer_db(postgresql_proc, datanommer_db_url):
|
|
32
32
|
# template_dbname=postgresql_proc.template_dbname,
|
33
33
|
version=postgresql_proc.version,
|
34
34
|
):
|
35
|
-
engine = sa.create_engine(datanommer_db_url, future=True
|
35
|
+
engine = sa.create_engine(datanommer_db_url, future=True)
|
36
36
|
# Renew the global object, dm.init checks a custom attribute
|
37
37
|
dm.session = scoped_session(dm.maker)
|
38
38
|
dm.init(engine=engine, create=True)
|
39
39
|
yield engine
|
40
|
-
|
40
|
+
engine.dispose()
|
41
|
+
|
42
|
+
|
43
|
+
@pytest.fixture()
|
44
|
+
def datanommer_db(datanommer_db_url, datanommer_db_engine):
|
45
|
+
for table in reversed(dm.DeclarativeBase.metadata.sorted_tables):
|
46
|
+
dm.session.execute(table.delete())
|
47
|
+
dm.session.commit()
|
48
|
+
yield datanommer_db_engine
|
41
49
|
|
42
50
|
|
43
51
|
@pytest.fixture()
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: datanommer.models
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.3.0
|
4
4
|
Summary: SQLAlchemy models for datanommer
|
5
5
|
Home-page: https://github.com/fedora-infra/datanommer
|
6
6
|
License: GPL-3.0-or-later
|
@@ -32,6 +32,7 @@ Requires-Dist: fmn-messages ; extra == "schemas"
|
|
32
32
|
Requires-Dist: kerneltest-messages (>=1.0.0,<2.0.0) ; extra == "schemas"
|
33
33
|
Requires-Dist: koji-fedoramessaging-messages (>=1.2.2,<2.0.0) ; extra == "schemas"
|
34
34
|
Requires-Dist: koschei-messages ; extra == "schemas"
|
35
|
+
Requires-Dist: maubot-fedora-messages ; extra == "schemas"
|
35
36
|
Requires-Dist: mdapi-messages ; extra == "schemas"
|
36
37
|
Requires-Dist: mediawiki-messages ; extra == "schemas"
|
37
38
|
Requires-Dist: meetbot-messages ; extra == "schemas"
|
@@ -1,10 +1,10 @@
|
|
1
|
-
datanommer/models/__init__.py,sha256=
|
1
|
+
datanommer/models/__init__.py,sha256=j3ZIgc2XnXoHaTuC2edq9RoVEqx0g8dc9-3dKi3ctBU,18628
|
2
2
|
datanommer/models/alembic/env.py,sha256=WNTimgnH70CakhvuV5QCilCnOcjTy7kcx0nD7hryYx0,2793
|
3
3
|
datanommer/models/alembic/script.py.mako,sha256=D8kFI44_9vBJZrAYSkZxDTX2-S5Y-oEetEd9BKlo9S8,412
|
4
4
|
datanommer/models/alembic/versions/5db25abc63be_init.py,sha256=xMD7WGCOqeVNFroCZds_aS_jta2yTrAHc_XhtmZLZRs,249
|
5
5
|
datanommer/models/alembic/versions/951c40020acc_unique.py,sha256=GwKDhppKW7y5BUV8BqILZCAiR7GsNyIvoTXUu2A1ZMI,843
|
6
|
-
datanommer/models/testing/__init__.py,sha256=
|
7
|
-
datanommer_models-1.
|
8
|
-
datanommer_models-1.
|
9
|
-
datanommer_models-1.
|
10
|
-
datanommer_models-1.
|
6
|
+
datanommer/models/testing/__init__.py,sha256=wwAZ-s1U4M7nYNxHgJsn5ZIqLuHMzHrJwGJOwgHAFgc,1693
|
7
|
+
datanommer_models-1.3.0.dist-info/LICENSE,sha256=jOtLnuWt7d5Hsx6XXB2QxzrSe2sWWh3NgMfFRetluQM,35147
|
8
|
+
datanommer_models-1.3.0.dist-info/METADATA,sha256=wKhrCYMD6cECmPOoosFOEIZdtAezEhw1SxwDxlotE54,2561
|
9
|
+
datanommer_models-1.3.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
10
|
+
datanommer_models-1.3.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|