message-db-py 0.3.2__tar.gz → 0.3.4__tar.gz

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.
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: message-db-py
3
- Version: 0.3.2
3
+ Version: 0.3.4
4
4
  Summary: The Python interface to the MessageDB Event Store and Message Store
5
5
  License: MIT
6
6
  License-File: LICENSE
7
7
  Keywords: message-db,event-sourcing,event-store,messaging,cqrs,command-query-responsibility-segregation,events,streaming,database,postgresql,python,async,microservices,distributed-systems,message-queue,event-driven,real-time
8
8
  Author: Subhash Bhushan
9
9
  Author-email: subhash.bhushan@gmail.com
10
- Requires-Python: >=3.11,<4.0
10
+ Requires-Python: >=3.11
11
11
  Classifier: Development Status :: 4 - Beta
12
12
  Classifier: Intended Audience :: Developers
13
13
  Classifier: Intended Audience :: Information Technology
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "message-db-py"
3
- version = "0.3.2"
3
+ version = "0.3.4"
4
4
  description = "The Python interface to the MessageDB Event Store and Message Store"
5
5
  authors = ["Subhash Bhushan <subhash.bhushan@gmail.com>"]
6
6
  license = "MIT"
@@ -48,7 +48,7 @@ packages = [
48
48
  ]
49
49
 
50
50
  [tool.poetry.dependencies]
51
- python = "^3.11"
51
+ python = ">=3.11"
52
52
  psycopg2 = "^2.9.11"
53
53
 
54
54
  [tool.poetry.group.dev.dependencies]
@@ -1,3 +1,3 @@
1
- __version__ = "0.3.2"
1
+ __version__ = "0.3.4"
2
2
 
3
3
  # Re-export client class
@@ -144,49 +144,51 @@ class MessageDB:
144
144
  Returns a list of messages from the stream or category starting from the given position.
145
145
  """
146
146
  conn = self.connection_pool.get_connection()
147
- cursor = conn.cursor(cursor_factory=RealDictCursor)
148
-
149
- if not sql:
150
- if stream_name == "$all":
151
- sql = """
152
- SELECT
153
- id::varchar,
154
- stream_name::varchar,
155
- type::varchar,
156
- position::bigint,
157
- global_position::bigint,
158
- data::varchar,
159
- metadata::varchar,
160
- time::timestamp
161
- FROM
162
- messages
163
- WHERE
164
- global_position > %(position)s
165
- LIMIT %(batch_size)s
166
- """
167
- elif "-" in stream_name:
168
- sql = "SELECT * FROM get_stream_messages(%(stream_name)s, %(position)s, %(batch_size)s);"
169
- else:
170
- sql = "SELECT * FROM get_category_messages(%(stream_name)s::varchar, %(position)s::bigint, %(batch_size)s::bigint"
171
- if consumer_group_member is not None:
172
- sql += ", NULL, %(consumer_group_member)s::bigint, %(consumer_group_size)s::bigint"
173
- sql += ");"
174
-
175
- params = {
176
- "stream_name": stream_name,
177
- "position": position,
178
- "batch_size": no_of_messages,
179
- }
180
- if consumer_group_member is not None:
181
- params["consumer_group_member"] = consumer_group_member
182
- params["consumer_group_size"] = consumer_group_size
183
-
184
- cursor.execute(sql, params)
185
- raw_messages = cursor.fetchall()
186
-
187
- conn.commit()
188
- cursor.close()
189
- self.connection_pool.release(conn)
147
+ try:
148
+ cursor = conn.cursor(cursor_factory=RealDictCursor)
149
+
150
+ if not sql:
151
+ if stream_name == "$all":
152
+ sql = """
153
+ SELECT
154
+ id::varchar,
155
+ stream_name::varchar,
156
+ type::varchar,
157
+ position::bigint,
158
+ global_position::bigint,
159
+ data::varchar,
160
+ metadata::varchar,
161
+ time::timestamp
162
+ FROM
163
+ messages
164
+ WHERE
165
+ global_position > %(position)s
166
+ LIMIT %(batch_size)s
167
+ """
168
+ elif "-" in stream_name:
169
+ sql = "SELECT * FROM get_stream_messages(%(stream_name)s, %(position)s, %(batch_size)s);"
170
+ else:
171
+ sql = "SELECT * FROM get_category_messages(%(stream_name)s::varchar, %(position)s::bigint, %(batch_size)s::bigint"
172
+ if consumer_group_member is not None:
173
+ sql += ", NULL, %(consumer_group_member)s::bigint, %(consumer_group_size)s::bigint"
174
+ sql += ");"
175
+
176
+ params = {
177
+ "stream_name": stream_name,
178
+ "position": position,
179
+ "batch_size": no_of_messages,
180
+ }
181
+ if consumer_group_member is not None:
182
+ params["consumer_group_member"] = consumer_group_member
183
+ params["consumer_group_size"] = consumer_group_size
184
+
185
+ cursor.execute(sql, params)
186
+ raw_messages = cursor.fetchall()
187
+
188
+ conn.commit()
189
+ cursor.close()
190
+ finally:
191
+ self.connection_pool.release(conn)
190
192
 
191
193
  messages = []
192
194
  for message in raw_messages:
@@ -304,45 +306,49 @@ class MessageDB:
304
306
  raise ValueError(f"{category_name} is not a category")
305
307
 
306
308
  conn = self.connection_pool.get_connection()
307
- cursor = conn.cursor()
308
-
309
- cursor.execute(
310
- """
311
- SELECT DISTINCT
312
- substring(stream_name from position('-' in stream_name) + 1)
313
- FROM message_store.messages
314
- WHERE stream_name LIKE %(pattern)s
315
- AND stream_name NOT LIKE %(snapshot_pattern)s
316
- ORDER BY 1
317
- """,
318
- {
319
- "pattern": f"{category_name}-%",
320
- "snapshot_pattern": f"{category_name}:snapshot-%",
321
- },
322
- )
323
- identifiers = [row[0] for row in cursor.fetchall() if row[0]]
309
+ try:
310
+ cursor = conn.cursor()
324
311
 
325
- conn.commit()
326
- cursor.close()
327
- self.connection_pool.release(conn)
312
+ cursor.execute(
313
+ """
314
+ SELECT DISTINCT
315
+ substring(stream_name from position('-' in stream_name) + 1)
316
+ FROM message_store.messages
317
+ WHERE stream_name LIKE %(pattern)s
318
+ AND stream_name NOT LIKE %(snapshot_pattern)s
319
+ ORDER BY 1
320
+ """,
321
+ {
322
+ "pattern": f"{category_name}-%",
323
+ "snapshot_pattern": f"{category_name}:snapshot-%",
324
+ },
325
+ )
326
+ identifiers = [row[0] for row in cursor.fetchall() if row[0]]
327
+
328
+ conn.commit()
329
+ cursor.close()
330
+ finally:
331
+ self.connection_pool.release(conn)
328
332
 
329
333
  return identifiers
330
334
 
331
335
  def read_last_message(self, stream_name: str) -> Dict[str, Any] | None:
332
336
  """Read the last message from a stream."""
333
337
  conn = self.connection_pool.get_connection()
334
- cursor = conn.cursor(cursor_factory=RealDictCursor)
338
+ try:
339
+ cursor = conn.cursor(cursor_factory=RealDictCursor)
335
340
 
336
- cursor.execute(
337
- "SELECT * from get_last_stream_message(%(stream_name)s);",
338
- {"stream_name": stream_name},
339
- )
341
+ cursor.execute(
342
+ "SELECT * from get_last_stream_message(%(stream_name)s);",
343
+ {"stream_name": stream_name},
344
+ )
340
345
 
341
- message = cursor.fetchone()
346
+ message = cursor.fetchone()
342
347
 
343
- conn.commit()
344
- cursor.close()
345
- self.connection_pool.release(conn)
348
+ conn.commit()
349
+ cursor.close()
350
+ finally:
351
+ self.connection_pool.release(conn)
346
352
 
347
353
  if message:
348
354
  message["data"] = json.loads(message["data"])
@@ -3,7 +3,7 @@ from __future__ import annotations
3
3
  from typing import Any
4
4
 
5
5
  from psycopg2.extensions import connection
6
- from psycopg2.pool import SimpleConnectionPool
6
+ from psycopg2.pool import ThreadedConnectionPool
7
7
 
8
8
 
9
9
  class ConnectionPool:
@@ -35,7 +35,7 @@ class ConnectionPool:
35
35
  # Minimum connections start at 1
36
36
  min_connections = 1
37
37
 
38
- self._connection_pool = SimpleConnectionPool(
38
+ self._connection_pool = ThreadedConnectionPool(
39
39
  min_connections, self.max_connections, *self.args, **self.kwargs
40
40
  )
41
41
 
File without changes
File without changes