Implement generic Table for basic CRUD operations & concurrent safe dequeuing#30
Conversation
211e63f to
9df208d
Compare
david-littlefarmer
left a comment
There was a problem hiding this comment.
One comment, looks good, it would be nice to also have paginated methods.
|
Exactly, great point about the pagination 👍 I'd love to see both LIMIT/OFFSET and cursor-based pagination defined as a base data model methods. This needs some more thoughts, so I skipped it for now. |
Co-authored-by: David Sedlacek <david.sedlacek@golang.cz>
.Save() - variadic arg instead of .Save() and .SaveAll() .List() - renamed from .GetAll() .Get() - renamed from .GetOne() .LockForUpdates() - renamed from .LockForUpdate() .LockForUpdate() - renamed from .LockOneForUpdate()
* save multiple * pr comments * return error instead of nil on nil record
a039cc0 to
b2ce7a7
Compare
- Add RestoreByID method that clears DeletedAt by passing zero time - Export HasSetCreatedAt, HasSetUpdatedAt, HasSetDeletedAt interfaces with godoc explaining the contract for each lifecycle hook - Update SetDeletedAt implementations to treat zero time as restore (nil)
ae6bef6 to
2fa3605
Compare
… missing rows.Err, saveOne missing SetCreatedAt - LockForUpdates: add missing return after existing-tx branch to prevent double execution of updateFn via a second transaction - saveAll: use t.IDColumn instead of hardcoded "id" for update WHERE clause - Iter: check rows.Err() after iteration loop to surface driver errors - saveOne: call SetCreatedAt on insert path (consistent with saveAll) - Use min() builtin for chunk bounds
… slice - Move wg.Add(1) before goroutine dispatch in ProcessReview to prevent worker.Wait() returning early before all goroutines register - Replace shared ids[][]uint64 slice (data race across goroutines) with per-worker local slices merged under mutex - Fix articleIDs slice: make([]uint64, len) + append produced leading zeros, changed to make([]uint64, 0, len)
Normalize nil page before passing to PrepareQuery/PrepareResult.
PrepareQuery creates a local &Page{} but the caller's pointer stays nil,
causing PrepareResult to panic on page.More assignment.
…ed ordering - lockForUpdatesWithTx: call Validate() and SetUpdatedAt() on records after updateFn, matching Insert/Update/Save behavior - Page.SetDefaults: fall back to DefaultPageSize/MaxPageSize when PaginatorSettings has zero values (fixes zero-value Paginator capping page size to 0) - ListPaged: add IDColumn fallback ordering when no sort is configured, ensuring deterministic pagination - TestLockForUpdates: use assert instead of require in goroutine (require.FailNow is unsafe off the test goroutine)
- Skip ORDER BY clause when no sort columns are configured - Always inject pgx.NamedArgs for limit/offset even when args is empty
Return true when at least one row was affected, false when zero rows matched. Callers can now distinguish "success" from "not found" without reimplementing methods with RowsAffected checks. Breaking change: signatures go from error to (bool, error).
|
Just adding this here for future reference: I think we should document clearly that We could add a new or |
|
On top of what @VojtechVitek covered in the PR:
|
Concurrent dequeue/update pattern
FOR UPDATE SKIP LOCKEDpatternpgkit/tests/table_test.go
Lines 193 to 200 in d081629
pgkit/tests/tables_test.go
Lines 24 to 47 in d081629
pgkit/tests/worker_test.go
Lines 24 to 64 in d081629
Data models with strongly typed
*data.Recordtype (using generics):pgkit/tests/table_test.go
Lines 24 to 45 in d081629
pgkit/tests/table_test.go
Lines 63 to 83 in d081629