🪟 Windows TippsThe Gemini desktop app is now available for Windows(11.09.2026 um 17:06 Uhr)
🪟 Windows TippsSetting up live captions stuck in Windows 11(14.09.2026 um 16:31 Uhr)
🕵️ SicherheitslückenBurn Out, Or Fade Away(14.09.2026 um 14:25 Uhr)
🪟 Windows TippsWindows 11's latest update broke my speakers, and I'm not alone(14.09.2026 um 18:54 Uhr)
🪟 Windows TippsThe Gemini desktop app is now available for Windows(11.09.2026 um 17:06 Uhr)
🪟 Windows TippsSetting up live captions stuck in Windows 11(14.09.2026 um 16:31 Uhr)
🕵️ SicherheitslückenBurn Out, Or Fade Away(14.09.2026 um 14:25 Uhr)
🪟 Windows TippsWindows 11's latest update broke my speakers, and I'm not alone(14.09.2026 um 18:54 Uhr)

🔧 Programmierung 🕛 vor 3 Monaten 4 Min Lesezeit
0

I got tired of writing the same history table boilerplate, so I built a Postgres extension

↗ Quelle (dev.to)
🗣️ Stimme:
📑 Inhaltsübersicht

There's this problem I kept running into - first during my internship, then again on a freelance project I picked up afterward. Both of them used PostgreSQL, and both of them at some point needed an answer to the same question: what did this data look like before?



Could be an audit log. Could be a client asking "what was the price on the 15th?" Could be a bad deployment that nuked a bunch of rows and now someone needs to recover the state from two hours ago.



And every single time, the answer involved the same tedious ritual: add created_at and updated_at columns, create a separate _history table that mirrors the original, write a trigger to populate it on every insert, update, and delete, and hope you got the interval boundaries right. On the freelance project I actually got them wrong on the first try - rows were either double-counted or missing entirely at certain timestamps. Had to tear it out and redo it.



So I finally sat down and built something to handle this properly.









What pgtime does



You run this on any existing table:




CODE
SELECT pgtime.attach('orders');






That's it. From that point on, every INSERT, UPDATE, and DELETE on the orders table is automatically captured in a shadow history table called orders_history. You don't touch your existing schema, your existing queries don't change, and the tracking just works in the background.



When you call attach(), the extension dynamically compiles helper functions matched to your table's exact schema. This means when you need to look at the past, you get clean, native queries with no tedious type casting:




CODE
-- Get a full table snapshot as of Jan 15th, 2026
SELECT * FROM orders_as_of('2026-01-15 10:00:00+00');






Or if you want to see the full change history of a specific row:




CODE
-- Retrieve the full audit trail of order #42
SELECT price, sys_from, _pgtime_op FROM orders_history(42);












Why a C trigger and not PL/pgSQL



The trigger that captures row changes is written in C. The honest reason is performance - PL/pgSQL has overhead on every row operation, and for tables with high write throughput that adds up fast. The C trigger runs closer to the metal.



To back this up, I ran a baseline benchmark on 10,000 operations inside a Postgres 16 container. Even with range-indexing overhead (we use tstzrange and GiST indexes to make point-in-time scans fast), the C trigger still manages to log:




  • ~63,700 operations/sec for INSERTs

  • ~20,100 operations/sec for UPDATEs (which require double writes: closing the old version and inserting the new one)









There are SDKs too



I didn't want this to only be accessible from raw SQL, so I built thin wrappers for Node/TypeScript and Python.



TypeScript:




CODE
import { Pool } from 'pg';
import { PgTime } from 'pgtime-js';

const pool = new Pool({ connectionString: process.env.DATABASE_URL });
const pt = new PgTime(pool);

await pt.attach('orders');

interface Order { id: number; item: string; price: number; }
const snapshot = await pt.asOf<Order>('orders', '2026-01-15T10:00:00Z');
const auditTrail = await pt.history('orders', 42);






Python:




CODE
from pgtime import PgTime
import psycopg2

conn = psycopg2.connect("postgres://...")
pt = PgTime(conn)

pt.attach("orders")
snapshot = pt.as_of("orders", "2026-01-15T10:00:00Z")
logs = pt.history("orders", 42)






And there's a Go CLI for terminal operations:




CODE
pgtime attach orders --db postgres://localhost/mydb
pgtime history orders --id 42 --db postgres://localhost/mydb
pgtime diff orders --from "2026-01-01" --to "2026-02-01" --db postgres://localhost/mydb












Where it stands right now



It's v0.1.1-alpha. Transaction time - meaning the database system clock - is fully working. Valid-time (business time, where you define the time bounds rather than the system) is on the roadmap for v0.2 but not there yet.



The SDKs also aren't on npm or PyPI yet, so installation is from a local clone for now. That'll change in the next release. Installation is Docker-based for development and testing, or you can compile the C extension directly if you have the Postgres dev headers - the README walks through both.









If you want to check it out



GitHub: https://github.com/Sanidhyavijay24/pgtime



If you've dealt with this problem before - or solved it a different way - I'd genuinely like to hear how. And if something looks wrong or off in the implementation, please say so. Still early days and real feedback is more useful than stars right now.

Vollständiger Original-Bericht
Ausführliche Details, Code-Beispiele & Hersteller-Stellungnahme auf dev.to.
↗ Original-Artikel auf dev.to lesen
Wie bewertest du diesen Beitrag?
1 Klick Feedback
Teilen mit Netzwerk & Team:

Community-Analysen & Experten-Meinungen 0

Verfasse deine eigene Analyse, teile Workarounds oder diskutiere diesen Vorfall im Blog.
Noch keine Community-Analyse verfasst. Markiere einen Textabschnitt oder klicke oben auf Eigene Analyse verfassen“!
Community Pulse: Relevanz-Einschätzung
1 Klick Experten-Votum
🔴 Akute Relevanz 0%
🟡 In Evaluierung 0%
🟢 Keine Auswirkung 0%
Spannende Innovation 0%
Verwandte Story-Cluster & Quellen (Vektor-KI)
Port 8095 Engine
1 Quelle
The Gemini desktop app is now available for Windows
1 Quelle
Setting up live captions stuck in Windows 11
1 Quelle
Burn Out, Or Fade Away
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten I got tired of writing the same history table boilerplate, so I built a Postgres extension

Thematisch verwandte Begriffe: tired, writing, same, history · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...