rhosocial-activerecord-postgres 1.0.0.dev2__tar.gz → 1.0.0.dev4__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.
Files changed (63) hide show
  1. {rhosocial_activerecord_postgres-1.0.0.dev2 → rhosocial_activerecord_postgres-1.0.0.dev4}/PKG-INFO +187 -353
  2. rhosocial_activerecord_postgres-1.0.0.dev4/README.md +293 -0
  3. {rhosocial_activerecord_postgres-1.0.0.dev2 → rhosocial_activerecord_postgres-1.0.0.dev4}/pyproject.toml +3 -2
  4. rhosocial_activerecord_postgres-1.0.0.dev4/src/rhosocial/activerecord/backend/impl/postgres/__init__.py +346 -0
  5. {rhosocial_activerecord_postgres-1.0.0.dev2 → rhosocial_activerecord_postgres-1.0.0.dev4}/src/rhosocial/activerecord/backend/impl/postgres/__main__.py +2 -2
  6. rhosocial_activerecord_postgres-1.0.0.dev4/src/rhosocial/activerecord/backend/impl/postgres/adapters/__init__.py +117 -0
  7. rhosocial_activerecord_postgres-1.0.0.dev4/src/rhosocial/activerecord/backend/impl/postgres/adapters/base.py +215 -0
  8. rhosocial_activerecord_postgres-1.0.0.dev4/src/rhosocial/activerecord/backend/impl/postgres/adapters/bit_string.py +124 -0
  9. rhosocial_activerecord_postgres-1.0.0.dev4/src/rhosocial/activerecord/backend/impl/postgres/adapters/geometric.py +162 -0
  10. rhosocial_activerecord_postgres-1.0.0.dev4/src/rhosocial/activerecord/backend/impl/postgres/adapters/json.py +195 -0
  11. rhosocial_activerecord_postgres-1.0.0.dev4/src/rhosocial/activerecord/backend/impl/postgres/adapters/monetary.py +204 -0
  12. rhosocial_activerecord_postgres-1.0.0.dev4/src/rhosocial/activerecord/backend/impl/postgres/adapters/network_address.py +297 -0
  13. rhosocial_activerecord_postgres-1.0.0.dev4/src/rhosocial/activerecord/backend/impl/postgres/adapters/object_identifier.py +411 -0
  14. rhosocial_activerecord_postgres-1.0.0.dev4/src/rhosocial/activerecord/backend/impl/postgres/adapters/pg_lsn.py +132 -0
  15. rhosocial_activerecord_postgres-1.0.0.dev4/src/rhosocial/activerecord/backend/impl/postgres/adapters/range.py +208 -0
  16. rhosocial_activerecord_postgres-1.0.0.dev4/src/rhosocial/activerecord/backend/impl/postgres/adapters/text_search.py +229 -0
  17. rhosocial_activerecord_postgres-1.0.0.dev4/src/rhosocial/activerecord/backend/impl/postgres/adapters/xml.py +134 -0
  18. rhosocial_activerecord_postgres-1.0.0.dev4/src/rhosocial/activerecord/backend/impl/postgres/backend/__init__.py +21 -0
  19. rhosocial_activerecord_postgres-1.0.0.dev4/src/rhosocial/activerecord/backend/impl/postgres/backend/async_backend.py +605 -0
  20. rhosocial_activerecord_postgres-1.0.0.dev4/src/rhosocial/activerecord/backend/impl/postgres/backend/base.py +193 -0
  21. rhosocial_activerecord_postgres-1.0.0.dev4/src/rhosocial/activerecord/backend/impl/postgres/backend/sync.py +606 -0
  22. {rhosocial_activerecord_postgres-1.0.0.dev2 → rhosocial_activerecord_postgres-1.0.0.dev4}/src/rhosocial/activerecord/backend/impl/postgres/config.py +2 -1
  23. rhosocial_activerecord_postgres-1.0.0.dev4/src/rhosocial/activerecord/backend/impl/postgres/dialect.py +845 -0
  24. rhosocial_activerecord_postgres-1.0.0.dev4/src/rhosocial/activerecord/backend/impl/postgres/functions/__init__.py +178 -0
  25. rhosocial_activerecord_postgres-1.0.0.dev4/src/rhosocial/activerecord/backend/impl/postgres/functions/bit_string.py +212 -0
  26. rhosocial_activerecord_postgres-1.0.0.dev4/src/rhosocial/activerecord/backend/impl/postgres/functions/enum.py +160 -0
  27. rhosocial_activerecord_postgres-1.0.0.dev4/src/rhosocial/activerecord/backend/impl/postgres/functions/geometric.py +225 -0
  28. rhosocial_activerecord_postgres-1.0.0.dev4/src/rhosocial/activerecord/backend/impl/postgres/functions/json.py +286 -0
  29. rhosocial_activerecord_postgres-1.0.0.dev4/src/rhosocial/activerecord/backend/impl/postgres/functions/range.py +379 -0
  30. rhosocial_activerecord_postgres-1.0.0.dev4/src/rhosocial/activerecord/backend/impl/postgres/mixins.py +1004 -0
  31. rhosocial_activerecord_postgres-1.0.0.dev4/src/rhosocial/activerecord/backend/impl/postgres/protocols.py +1414 -0
  32. rhosocial_activerecord_postgres-1.0.0.dev4/src/rhosocial/activerecord/backend/impl/postgres/statements.py +405 -0
  33. {rhosocial_activerecord_postgres-1.0.0.dev2 → rhosocial_activerecord_postgres-1.0.0.dev4}/src/rhosocial/activerecord/backend/impl/postgres/transaction.py +175 -5
  34. rhosocial_activerecord_postgres-1.0.0.dev4/src/rhosocial/activerecord/backend/impl/postgres/type_compatibility.py +456 -0
  35. rhosocial_activerecord_postgres-1.0.0.dev4/src/rhosocial/activerecord/backend/impl/postgres/types/__init__.py +262 -0
  36. rhosocial_activerecord_postgres-1.0.0.dev4/src/rhosocial/activerecord/backend/impl/postgres/types/bit_string.py +123 -0
  37. rhosocial_activerecord_postgres-1.0.0.dev4/src/rhosocial/activerecord/backend/impl/postgres/types/constants.py +275 -0
  38. rhosocial_activerecord_postgres-1.0.0.dev4/src/rhosocial/activerecord/backend/impl/postgres/types/enum.py +366 -0
  39. rhosocial_activerecord_postgres-1.0.0.dev4/src/rhosocial/activerecord/backend/impl/postgres/types/geometric.py +385 -0
  40. rhosocial_activerecord_postgres-1.0.0.dev4/src/rhosocial/activerecord/backend/impl/postgres/types/json.py +197 -0
  41. rhosocial_activerecord_postgres-1.0.0.dev4/src/rhosocial/activerecord/backend/impl/postgres/types/monetary.py +137 -0
  42. rhosocial_activerecord_postgres-1.0.0.dev4/src/rhosocial/activerecord/backend/impl/postgres/types/network_address.py +233 -0
  43. rhosocial_activerecord_postgres-1.0.0.dev4/src/rhosocial/activerecord/backend/impl/postgres/types/object_identifier.py +634 -0
  44. rhosocial_activerecord_postgres-1.0.0.dev4/src/rhosocial/activerecord/backend/impl/postgres/types/pg_lsn.py +215 -0
  45. rhosocial_activerecord_postgres-1.0.0.dev4/src/rhosocial/activerecord/backend/impl/postgres/types/range.py +577 -0
  46. rhosocial_activerecord_postgres-1.0.0.dev4/src/rhosocial/activerecord/backend/impl/postgres/types/text_search.py +1099 -0
  47. rhosocial_activerecord_postgres-1.0.0.dev4/src/rhosocial/activerecord/backend/impl/postgres/types/xml.py +152 -0
  48. {rhosocial_activerecord_postgres-1.0.0.dev2 → rhosocial_activerecord_postgres-1.0.0.dev4}/src/rhosocial_activerecord_postgres.egg-info/PKG-INFO +187 -353
  49. rhosocial_activerecord_postgres-1.0.0.dev4/src/rhosocial_activerecord_postgres.egg-info/SOURCES.txt +54 -0
  50. rhosocial_activerecord_postgres-1.0.0.dev2/README.md +0 -459
  51. rhosocial_activerecord_postgres-1.0.0.dev2/src/rhosocial/activerecord/backend/impl/postgres/__init__.py +0 -76
  52. rhosocial_activerecord_postgres-1.0.0.dev2/src/rhosocial/activerecord/backend/impl/postgres/adapters.py +0 -71
  53. rhosocial_activerecord_postgres-1.0.0.dev2/src/rhosocial/activerecord/backend/impl/postgres/backend.py +0 -822
  54. rhosocial_activerecord_postgres-1.0.0.dev2/src/rhosocial/activerecord/backend/impl/postgres/dialect.py +0 -1076
  55. rhosocial_activerecord_postgres-1.0.0.dev2/src/rhosocial/activerecord/backend/impl/postgres/types.py +0 -220
  56. rhosocial_activerecord_postgres-1.0.0.dev2/src/rhosocial_activerecord_postgres.egg-info/SOURCES.txt +0 -18
  57. {rhosocial_activerecord_postgres-1.0.0.dev2 → rhosocial_activerecord_postgres-1.0.0.dev4}/LICENSE +0 -0
  58. {rhosocial_activerecord_postgres-1.0.0.dev2 → rhosocial_activerecord_postgres-1.0.0.dev4}/MANIFEST.in +0 -0
  59. {rhosocial_activerecord_postgres-1.0.0.dev2 → rhosocial_activerecord_postgres-1.0.0.dev4}/setup.cfg +0 -0
  60. {rhosocial_activerecord_postgres-1.0.0.dev2 → rhosocial_activerecord_postgres-1.0.0.dev4}/src/rhosocial/activerecord/backend/impl/postgres/README.md +0 -0
  61. {rhosocial_activerecord_postgres-1.0.0.dev2 → rhosocial_activerecord_postgres-1.0.0.dev4}/src/rhosocial_activerecord_postgres.egg-info/dependency_links.txt +0 -0
  62. {rhosocial_activerecord_postgres-1.0.0.dev2 → rhosocial_activerecord_postgres-1.0.0.dev4}/src/rhosocial_activerecord_postgres.egg-info/requires.txt +0 -0
  63. {rhosocial_activerecord_postgres-1.0.0.dev2 → rhosocial_activerecord_postgres-1.0.0.dev4}/src/rhosocial_activerecord_postgres.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rhosocial_activerecord_postgres
3
- Version: 1.0.0.dev2
3
+ Version: 1.0.0.dev4
4
4
  Summary: postgres backend implementation for rhosocial-activerecord, providing a robust and optimized postgres database support.
5
5
  Author-email: vistart <i@vistart.me>
6
6
  License: Apache License
@@ -255,456 +255,290 @@ Dynamic: license-file
255
255
  [![Python](https://img.shields.io/pypi/pyversions/rhosocial-activerecord-postgres.svg)](https://pypi.org/project/rhosocial-activerecord-postgres/)
256
256
  [![Tests](https://github.com/rhosocial/python-activerecord-postgres/actions/workflows/test.yml/badge.svg)](https://github.com/rhosocial/python-activerecord-postgres/actions)
257
257
  [![Coverage Status](https://codecov.io/gh/rhosocial/python-activerecord-postgres/branch/main/graph/badge.svg)](https://app.codecov.io/gh/rhosocial/python-activerecord-postgres/tree/main)
258
- [![License](https://img.shields.io/github/license/rhosocial/python-activerecord-postgres.svg)](https://github.com/rhosocial/python-activerecord-postgres/blob/main/LICENSE)
258
+ [![Apache 2.0 License](https://img.shields.io/github/license/rhosocial/python-activerecord-postgres.svg)](https://github.com/rhosocial/python-activerecord-postgres/blob/main/LICENSE)
259
259
  [![Powered by vistart](https://img.shields.io/badge/Powered_by-vistart-blue.svg)](https://github.com/vistart)
260
260
 
261
261
  <div align="center">
262
262
  <img src="https://raw.githubusercontent.com/rhosocial/python-activerecord/main/docs/images/logo.svg" alt="rhosocial ActiveRecord Logo" width="200"/>
263
- <p>postgres backend implementation for rhosocial-activerecord, providing a robust and optimized postgres database support.</p>
263
+ <h3>PostgreSQL Backend for rhosocial-activerecord</h3>
264
+ <p><b>Native Array & JSONB Support · Advanced Types · Sync & Async</b></p>
264
265
  </div>
265
266
 
266
- # Postgres Backend Implementation Guide
267
+ > **Note**: This is a backend implementation for [rhosocial-activerecord](https://github.com/rhosocial/python-activerecord). It cannot be used standalone.
267
268
 
268
- ## Overview
269
+ ## Why This Backend?
269
270
 
270
- This postgres backend implementation provides both **synchronous** and **asynchronous** support using the `psycopg` (psycopg3) driver.
271
+ ### 1. PostgreSQL's Unique Type System
271
272
 
272
- ## Key Features
273
+ | Feature | PostgreSQL Backend | MySQL Backend | SQLite Backend |
274
+ |---------|-------------------|---------------|----------------|
275
+ | **Native Arrays** | ✅ `INTEGER[]`, `TEXT[]` | ❌ Serialize to string | ❌ Serialize to string |
276
+ | **JSONB** | ✅ Binary JSON, indexed | ✅ JSON (text-based) | ⚠️ JSON1 extension |
277
+ | **UUID** | ✅ Native type | ⚠️ CHAR(36) | ⚠️ TEXT |
278
+ | **Range Types** | ✅ `DATERANGE`, `INT4RANGE` | ❌ | ❌ |
279
+ | **RETURNING** | ✅ All operations | ❌ | ✅ |
273
280
 
274
- - **Dual Implementation**: Both sync (`PostgresBackend`) and async (`AsyncPostgresBackend`)
275
- - ✅ **Shared Logic**: Common functionality in `PostgresBackendMixin`
276
- - ✅ **Full Transaction Support**: Including savepoints and DEFERRABLE mode
277
- - ✅ **Rich Type Support**: Arrays, JSONB, UUID, ranges, network types, geometry
278
- - ✅ **Complete Capability Declaration**: CTEs, window functions, JSON operations, etc.
279
- - ✅ **Native Driver**: Uses psycopg3 directly, no ORM dependencies
281
+ ### 2. No Adapter Overhead for Arrays
280
282
 
281
- ## Installation
283
+ Unlike databases without native arrays, PostgreSQL stores and queries arrays directly:
282
284
 
283
- ```bash
284
- pip install rhosocial-activerecord-postgres
285
- ```
285
+ ```python
286
+ # PostgreSQL: Native array - no serialization needed
287
+ class Article(ActiveRecord):
288
+ tags: list[str] # Maps directly to TEXT[]
286
289
 
287
- **Dependencies**:
288
- - `rhosocial-activerecord>=1.0.0,<2.0.0`
289
- - `psycopg>=3.2.12`
290
+ # MySQL/SQLite: Requires adapter
291
+ class Article(ActiveRecord):
292
+ tags: Annotated[list[str], UseAdapter(ListToStringAdapter(), str)]
293
+ ```
290
294
 
291
- ## Usage Examples
295
+ ### 3. Powerful Array Operators
292
296
 
293
- ### Synchronous Usage
297
+ Query arrays with native PostgreSQL operators:
294
298
 
295
299
  ```python
296
- from rhosocial.activerecord.model import ActiveRecord
297
- from rhosocial.activerecord.backend.impl.postgres import (
298
- PostgresBackend,
299
- PostgresConnectionConfig
300
- )
300
+ # Contains
301
+ Article.query().where("tags @> ARRAY[?]", ('python',)).all()
301
302
 
302
- # Configure connection
303
- config = PostgresConnectionConfig(
304
- host="localhost",
305
- port=5432,
306
- database="mydb",
307
- username="user",
308
- password="password",
309
- options={
310
- "sslmode": "prefer",
311
- "connect_timeout": 10,
312
- "application_name": "my_app"
313
- }
314
- )
315
-
316
- # Create backend
317
- backend = PostgresBackend(connection_config=config)
303
+ # Overlaps (any element matches)
304
+ Article.query().where("tags && ARRAY[?, ?]", ('python', 'database')).all()
318
305
 
319
- # Configure model
320
- class User(ActiveRecord):
321
- __table_name__ = "users"
322
- name: str
323
- email: str
306
+ # Any element equals
307
+ Article.query().where("? = ANY(tags)", ('python',)).all()
308
+ ```
324
309
 
325
- User.configure(backend)
310
+ > 💡 **AI Prompt**: "Show me all PostgreSQL array operators with examples"
326
311
 
327
- # Use the model
328
- user = User(name="John", email="john@example.com")
329
- user.save()
312
+ ## Quick Start
330
313
 
331
- # Query with CTEs (postgres 8.4+)
332
- results = User.query().with_cte(
333
- "active_users",
334
- User.query().where(is_active=True)
335
- ).from_cte("active_users").all()
314
+ ### Installation
336
315
 
337
- # Use JSONB operations (postgres 9.4+)
338
- users = User.query().where(
339
- "metadata->>'role' = ?", ("admin",)
340
- ).all()
316
+ ```bash
317
+ pip install rhosocial-activerecord-postgres
341
318
  ```
342
319
 
343
- ### Asynchronous Usage
320
+ ### Basic Usage
344
321
 
345
322
  ```python
346
- import asyncio
347
- from rhosocial.activerecord.async_model import ActiveRecord
348
- from rhosocial.activerecord.backend.impl.postgres import (
349
- AsyncPostgresBackend,
350
- PostgresConnectionConfig
351
- )
323
+ from rhosocial.activerecord.model import ActiveRecord
324
+ from rhosocial.activerecord.backend.impl.postgres import PostgresBackend
325
+ from rhosocial.activerecord.backend.impl.postgres.config import PostgresConnectionConfig
326
+ from typing import Optional
327
+ from uuid import UUID
352
328
 
353
- async def main():
354
- # Configure connection
355
- config = PostgresConnectionConfig(
356
- host="localhost",
357
- port=5432,
358
- database="mydb",
359
- username="user",
360
- password="password",
361
- )
362
-
363
- # Create async backend
364
- backend = ActiveRecord(connection_config=config)
365
-
366
- # Connect explicitly for async
367
- await backend.connect()
368
-
369
- # Configure model
370
- class User(ActiveRecord):
371
- __table_name__ = "users"
372
- name: str
373
- email: str
374
-
375
- User.configure(backend)
376
-
377
- # Use the model asynchronously
378
- user = User(name="Jane", email="jane@example.com")
379
- await user.save()
380
-
381
- # Async queries
382
- users = await User.query().where(is_active=True).all()
383
-
384
- # Cleanup
385
- await backend.disconnect()
386
-
387
- # Run async code
388
- asyncio.run(main())
389
- ```
329
+ class User(ActiveRecord):
330
+ __table_name__ = "users"
331
+ id: Optional[UUID] = None # Native UUID type
332
+ name: str
333
+ tags: list[str] # Native array type
334
+ metadata: dict # JSONB type
390
335
 
391
- ### Transaction Usage
336
+ # Configure
337
+ config = PostgresConnectionConfig(
338
+ host="localhost",
339
+ port=5432,
340
+ database="myapp",
341
+ username="user",
342
+ password="password"
343
+ )
344
+ User.configure(config, PostgresBackend)
392
345
 
393
- **Synchronous Transactions**:
346
+ # Use
347
+ user = User(name="Alice", tags=["python", "postgres"])
348
+ user.save()
394
349
 
395
- ```python
396
- # Get transaction manager
397
- tm = backend.transaction_manager
398
-
399
- # Basic transaction
400
- with tm:
401
- user1 = User(name="Alice")
402
- user1.save()
403
- user2 = User(name="Bob")
404
- user2.save()
405
- # Auto-commit on context exit
406
-
407
- # Explicit control
408
- tm.begin()
409
- try:
410
- user = User(name="Charlie")
411
- user.save()
412
- tm.commit()
413
- except Exception:
414
- tm.rollback()
415
- raise
416
-
417
- # With savepoints
418
- tm.begin()
419
- user1 = User(name="Dave")
420
- user1.save()
421
-
422
- savepoint = tm.savepoint()
423
- try:
424
- user2 = User(name="Eve")
425
- user2.save()
426
- tm.release_savepoint(savepoint)
427
- except Exception:
428
- tm.rollback_savepoint(savepoint)
429
-
430
- tm.commit()
431
-
432
- # With isolation level and deferrable mode
433
- tm.set_isolation_level(IsolationLevel.SERIALIZABLE)
434
- tm.set_deferrable(True)
435
- with tm:
436
- # Deferrable serializable transaction
437
- pass
350
+ # Query with array operators
351
+ python_users = User.query().where("tags @> ARRAY[?]", ('python',)).all()
438
352
  ```
439
353
 
440
- **Asynchronous Transactions**:
354
+ > 💡 **AI Prompt**: "How do I configure connection pooling for PostgreSQL?"
441
355
 
442
- ```python
443
- async def async_transaction_example():
444
- # Get async transaction manager
445
- tm = backend.transaction_manager
446
-
447
- # Basic async transaction
448
- async with tm:
449
- user1 = User(name="Alice")
450
- await user1.save()
451
- user2 = User(name="Bob")
452
- await user2.save()
453
- # Auto-commit on context exit
454
-
455
- # Explicit control
456
- await tm.begin()
457
- try:
458
- user = User(name="Charlie")
459
- await user.save()
460
- await tm.commit()
461
- except Exception:
462
- await tm.rollback()
463
- raise
464
-
465
- # With savepoints
466
- await tm.begin()
467
- user1 = User(name="Dave")
468
- await user1.save()
469
-
470
- savepoint = await tm.savepoint()
471
- try:
472
- user2 = User(name="Eve")
473
- await user2.save()
474
- await tm.release_savepoint(savepoint)
475
- except Exception:
476
- await tm.rollback_savepoint(savepoint)
477
-
478
- await tm.commit()
479
- ```
356
+ ## PostgreSQL-Specific Features
480
357
 
481
- ### Postgres-Specific Features
358
+ ### Array Types
482
359
 
483
- **Array Types**:
360
+ Native array support without adapters:
484
361
 
485
362
  ```python
486
- from rhosocial.activerecord.model import ActiveRecord
487
-
488
363
  class Article(ActiveRecord):
489
364
  __table_name__ = "articles"
490
365
  title: str
491
- tags: list # Will use postgres array type
492
-
493
- article = Article(
494
- title="postgres Arrays",
495
- tags=["database", "postgres", "arrays"]
496
- )
497
- article.save()
366
+ tags: list[str] # TEXT[]
367
+ scores: list[int] # INTEGER[]
498
368
 
499
- # Query arrays
500
- articles = Article.query().where(
501
- "? = ANY(tags)", ("postgres",)
502
- ).all()
369
+ # Query with array operators
370
+ Article.query().where("tags @> ARRAY[?]", ('python',)).all()
371
+ Article.query().where("? = ANY(tags)", ('database',)).all()
372
+ Article.query().where("array_length(tags, 1) > ?", (3,)).all()
503
373
  ```
504
374
 
505
- **JSONB Operations**:
375
+ > See [Array Type Comparison](docs/en_US/type_adapters/array_comparison.md) for differences with other databases.
506
376
 
507
- ```python
508
- from rhosocial.activerecord.model import ActiveRecord
377
+ ### JSONB Operations
509
378
 
379
+ Binary JSON with indexing support:
380
+
381
+ ```python
510
382
  class Product(ActiveRecord):
511
383
  __table_name__ = "products"
512
384
  name: str
513
- attributes: dict # Will use JSONB type
514
-
515
- product = Product(
516
- name="Laptop",
517
- attributes={
518
- "brand": "Dell",
519
- "specs": {
520
- "cpu": "Intel i7",
521
- "ram": "16GB"
522
- }
523
- }
524
- )
525
- product.save()
385
+ attributes: dict # JSONB
526
386
 
527
387
  # Query JSONB
528
- products = Product.query().where(
529
- "attributes->>'brand' = ?", ("Dell",)
530
- ).all()
531
-
532
- # JSONB contains
533
- products = Product.query().where(
534
- "attributes @> ?", ('{"brand": "Dell"}',)
535
- ).all()
388
+ Product.query().where("attributes->>'brand' = ?", ("Dell",)).all()
389
+
390
+ # JSONB contains (@>)
391
+ Product.query().where("attributes @> ?", ('{"brand": "Dell"}',)).all()
536
392
  ```
537
393
 
538
- **Range Types**:
394
+ ### UUID Type
395
+
396
+ Native UUID storage and querying:
397
+
398
+ ```python
399
+ from uuid import UUID, uuid4
400
+
401
+ class User(ActiveRecord):
402
+ __table_name__ = "users"
403
+ id: UUID
404
+ name: str
405
+
406
+ user = User(id=uuid4(), name="Alice")
407
+ user.save()
408
+ ```
409
+
410
+ ### Range Types
411
+
412
+ Built-in support for range types:
539
413
 
540
414
  ```python
541
415
  from datetime import date
542
- from rhosocial.activerecord.model import ActiveRecord
543
416
 
544
417
  class Booking(ActiveRecord):
545
418
  __table_name__ = "bookings"
546
419
  room_id: int
547
- date_range: tuple # Will use DATERANGE type
548
-
549
- booking = Booking(
550
- room_id=101,
551
- date_range=(date(2024, 1, 1), date(2024, 1, 7))
552
- )
553
- booking.save()
420
+ date_range: tuple # DATERANGE
554
421
 
555
- # Query ranges
556
- bookings = Booking.query().where(
557
- "date_range @> ?", (date(2024, 1, 3),)
558
- ).all()
422
+ # Query with range operators
423
+ Booking.query().where("date_range @> ?", (date(2024, 1, 15),)).all()
559
424
  ```
560
425
 
561
- ## Configuration Options
426
+ ### RETURNING Clause
562
427
 
563
- ### Connection Options
428
+ Retrieve data after INSERT/UPDATE/DELETE:
564
429
 
565
430
  ```python
566
- config = PostgresConnectionConfig(
567
- host="localhost",
568
- port=5432,
569
- database="mydb",
570
- username="user",
571
- password="password",
572
- options={
573
- # SSL/TLS
574
- "sslmode": "prefer", # disable, allow, prefer, require, verify-ca, verify-full
575
-
576
- # Connection timeout
577
- "connect_timeout": 10,
578
-
579
- # Application identification
580
- "application_name": "my_app",
581
-
582
- # Client encoding
583
- "client_encoding": "UTF8",
584
-
585
- # Connection pooling (if supported)
586
- "pool_min_size": 1,
587
- "pool_max_size": 10,
588
- "pool_timeout": 30.0,
589
- }
590
- )
431
+ # INSERT with RETURNING
432
+ user = User(name="Alice")
433
+ user.save()
434
+ print(user.id) # Populated automatically via RETURNING
435
+
436
+ # Works for all operations (unlike MySQL)
591
437
  ```
592
438
 
593
- ## Postgres Version Compatibility
439
+ ## Requirements
440
+
441
+ - **Python**: 3.8+ (including 3.13t/3.14t free-threaded builds)
442
+ - **Core**: `rhosocial-activerecord>=1.0.0`
443
+ - **Driver**: `psycopg>=3.2.12`
594
444
 
595
- | Feature | Minimum Version | Notes |
596
- |---------|----------------|-------|
445
+ ## PostgreSQL Version Compatibility
446
+
447
+ | Feature | Min Version | Notes |
448
+ |---------|-------------|-------|
597
449
  | Basic operations | 8.0+ | Core functionality |
450
+ | RETURNING | 8.2+ | INSERT/UPDATE/DELETE RETURNING |
598
451
  | CTEs | 8.4+ | WITH clauses |
599
452
  | Window functions | 8.4+ | ROW_NUMBER, RANK, etc. |
600
- | RETURNING clause | 8.2+ | INSERT/UPDATE/DELETE RETURNING |
601
- | JSON type | 9.2+ | Basic JSON support |
602
- | JSONB type | 9.4+ | Binary JSON, better performance |
603
- | UPSERT (ON CONFLICT) | 9.5+ | INSERT ... ON CONFLICT |
453
+ | TRUNCATE RESTART IDENTITY | 8.4+ | Reset sequences on truncate |
454
+ | JSON | 9.2+ | Basic JSON support |
455
+ | LATERAL joins | 9.3+ | LATERAL keyword |
456
+ | JSONB | 9.4+ | Binary JSON, indexed |
457
+ | FILTER clause | 9.4+ | Aggregate FILTER |
458
+ | Ordered-set aggregates | 9.4+ | PERCENTILE_CONT, etc. |
459
+ | UPSERT | 9.5+ | INSERT ... ON CONFLICT |
460
+ | Advanced grouping | 9.5+ | ROLLUP, CUBE, GROUPING SETS |
461
+ | SKIP LOCKED | 9.5+ | FOR UPDATE SKIP LOCKED |
462
+ | MATERIALIZED CTE hints | 12.0+ | MATERIALIZED/NOT MATERIALIZED |
463
+ | JSON_TABLE | 12.0+ | JSON table function |
464
+ | MERGE | 15.0+ | MERGE statement |
604
465
 
605
- **Recommended**: Postgres 12+ for optimal feature support and performance.
466
+ **Supported SQL Protocols:**
467
+ - ✅ SetOperationSupport (UNION, INTERSECT, EXCEPT) — All versions
468
+ - ✅ TruncateSupport (TRUNCATE TABLE) — All versions; RESTART IDENTITY ≥ 8.4
606
469
 
607
- ## Architecture Notes
470
+ **Recommended**: PostgreSQL 12+ for optimal feature support.
608
471
 
609
- ### Backend Structure
472
+ See [PROTOCOL_SUPPORT.md](docs/PROTOCOL_SUPPORT.md) for complete protocol support matrix.
610
473
 
611
- ```
612
- PostgresBackendMixin (Shared Logic)
613
- ├── Configuration validation
614
- ├── Version parsing
615
- ├── Capability initialization
616
- ├── Type converter registration
617
- └── Error mapping
618
-
619
- PostgresBackend (Sync) AsyncPostgresBackend (Async)
620
- ├── Inherits Mixin ├── Inherits Mixin
621
- ├── Inherits StorageBackend ├── Inherits AsyncStorageBackend
622
- ├── Sync connection management ├── Async connection management
623
- ├── Sync query execution ├── Async query execution
624
- └── Sync transaction manager └── Async transaction manager
625
- ```
474
+ ## Get Started with AI Code Agents
626
475
 
627
- ### Transaction Structure
476
+ This project supports AI-assisted development:
628
477
 
478
+ ```bash
479
+ git clone https://github.com/rhosocial/python-activerecord-postgres.git
480
+ cd python-activerecord-postgres
629
481
  ```
630
- PostgresTransactionMixin (Shared Logic)
631
- ├── Isolation level mapping
632
- ├── Savepoint name generation
633
- ├── SQL statement building
634
- └── Deferrable mode support
635
-
636
- PostgresTransactionManager AsyncPostgresTransactionManager
637
- ├── Inherits Mixin ├── Inherits Mixin
638
- ├── Inherits TransactionManager ├── Inherits AsyncTransactionManager
639
- ├── Sync transaction operations ├── Async transaction operations
640
- └── Sync constraint management └── Async constraint management
641
- ```
642
-
643
- ## Testing
644
482
 
645
- The backend includes comprehensive test coverage for both sync and async implementations:
483
+ ### Example AI Prompts
646
484
 
647
- - Connection lifecycle tests
648
- - CRUD operation tests
649
- - Transaction tests (with savepoints)
650
- - Type conversion tests
651
- - Capability declaration verification
652
- - Error handling tests
653
- - Concurrent operation tests
485
+ - "How do I use array operators to query tags?"
486
+ - "What's the difference between JSON and JSONB in PostgreSQL?"
487
+ - "Show me how to create a GIN index on an array column"
488
+ - "How do I use range types for scheduling?"
654
489
 
655
- **Run sync tests**:
656
- ```bash
657
- pytest tests/rhosocial/activerecord_test/feature/backend/postgres/test_backend_sync.py
658
- ```
490
+ ### For Any LLM
659
491
 
660
- **Run async tests**:
661
- ```bash
662
- pytest tests/rhosocial/activerecord_test/feature/backend/postgres/test_backend_async.py
663
- ```
492
+ Feed the documentation files in `docs/` for context-aware assistance.
664
493
 
665
- ## Migration from Old Implementation
494
+ ## Testing
666
495
 
667
- If you have an existing postgres backend implementation, here's how to migrate:
496
+ > ⚠️ **CRITICAL**: Tests MUST run serially. Do NOT use `pytest -n auto` or parallel execution.
668
497
 
669
- **Old code**:
670
- ```python
671
- from rhosocial.activerecord.backend.impl.postgres import PostgresBackend
498
+ ```bash
499
+ # Run all tests
500
+ PYTHONPATH=src pytest tests/
672
501
 
673
- backend = PostgresBackend(...)
502
+ # Run specific feature tests
503
+ PYTHONPATH=src pytest tests/rhosocial/activerecord_postgres_test/feature/basic/
504
+ PYTHONPATH=src pytest tests/rhosocial/activerecord_postgres_test/feature/query/
674
505
  ```
675
506
 
676
- **New code** (no changes needed for sync):
677
- ```python
678
- from rhosocial.activerecord.backend.impl.postgres import PostgresBackend
507
+ See the [Testing Documentation](https://github.com/rhosocial/python-activerecord/blob/main/.claude/testing.md) for details.
679
508
 
680
- backend = PostgresBackend(...) # Same API
681
- ```
509
+ ## Documentation
682
510
 
683
- **New async support**:
684
- ```python
685
- from rhosocial.activerecord.backend.impl.postgres import AsyncPostgresBackend
511
+ - **[Getting Started](docs/en_US/getting_started/)** — Installation and configuration
512
+ - **[PostgreSQL Features](docs/en_US/postgres_specific_features/)** — PostgreSQL-specific capabilities
513
+ - **[Type Adapters](docs/en_US/type_adapters/)** — Data type handling
514
+ - **[Array Comparison](docs/en_US/type_adapters/array_comparison.md)** — Array support across databases
515
+ - **[Transaction Support](docs/en_US/transaction_support/)** — Transaction management
686
516
 
687
- backend = AsyncPostgresBackend(...)
688
- await backend.connect()
689
- ```
517
+ ## Comparison with Other Backends
690
518
 
691
- ## Known Limitations
519
+ | Feature | PostgreSQL | MySQL | SQLite |
520
+ |---------|------------|-------|--------|
521
+ | **Native Arrays** | ✅ | ❌ | ❌ |
522
+ | **JSONB (indexed)** | ✅ | ⚠️ JSON only | ⚠️ Extension |
523
+ | **UUID Type** | ✅ Native | ⚠️ CHAR(36) | ⚠️ TEXT |
524
+ | **Range Types** | ✅ | ❌ | ❌ |
525
+ | **RETURNING** | ✅ | ❌ | ✅ |
526
+ | **CTEs** | ✅ 8.4+ | ✅ 8.0+ | ✅ 3.8.3+ |
527
+ | **Full-Text Search** | ✅ | ✅ | ⚠️ FTS5 |
692
528
 
693
- 1. **Connection Pooling**: Basic implementation, consider using external pooling (pgbouncer) for production
694
- 2. **Async Context**: Async backend requires explicit `await backend.connect()` call
695
- 3. **Type Converters**: Some postgres-specific types may need custom converters
529
+ > 💡 **AI Prompt**: "When should I choose PostgreSQL over MySQL for my project?"
696
530
 
697
531
  ## Contributing
698
532
 
699
- Contributions are welcome! Please ensure:
700
-
701
- - Tests pass for both sync and async implementations
702
- - Code follows project style guidelines
703
- - Documentation is updated
704
- - Changelog fragments are created
533
+ We welcome contributions! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
705
534
 
706
535
  ## License
707
536
 
708
- [![license](https://img.shields.io/github/license/rhosocial/python-activerecord-postgres.svg)](https://github.com/rhosocial/python-activerecord-postgres/blob/main/LICENSE)
537
+ [Apache License 2.0](LICENSE) — Copyright © 2026 [vistart](https://github.com/vistart)
709
538
 
710
- Copyright © 2025 [vistart](https://github.com/vistart)
539
+ ---
540
+
541
+ <div align="center">
542
+ <p><b>Built with ❤️ by the rhosocial team</b></p>
543
+ <p><a href="https://github.com/rhosocial/python-activerecord-postgres">GitHub</a> · <a href="https://docs.python-activerecord.dev.rho.social/backends/postgres.html">Documentation</a> · <a href="https://pypi.org/project/rhosocial-activerecord-postgres/">PyPI</a></p>
544
+ </div>