You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+28-53Lines changed: 28 additions & 53 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -23,7 +23,7 @@ _A modern take on SQL and SQL databases_
23
23
24
24
_Simplify and unify your entire database layer in a single interface_ 🛸<br>
25
25
LinkedQL is a database client (`client.query()`) for PostgreSQL and MySQL/MariaDB, but more broadly, an idea: **[SQL reimagined for modern apps ↗](https://linked-ql.netlify.app/overview)**.
26
-
LinkedQL solves **live querying and realtime apps, local-first and offline-first data architectures with federation and syncing, relationship traversal, schema versioning, version control, and point-in-time local replay** – all in under `80 KiB min | zip`.
26
+
LinkedQL solves **live querying for realtime apps, local-first and offline-first data architectures with federation and syncing, relationship traversal, schema versioning and version control system, point-in-time traversal, and more** – all in under `80 KiB min | zip`.
27
27
28
28
</div>
29
29
@@ -70,14 +70,13 @@ The package provides clients for all supported SQL dialects — including **Flas
70
70
71
71
## Why LinkedQL
72
72
73
-
Modern applications no longer interact with a single database in the traditional 1:1 model.
73
+
Modern applications no longer interact with a single database in the traditional 1:1 `client.query()`model.
74
74
75
75
They span:
76
76
77
-
* direct database connections (the traditional direct `client.query()` model),
78
77
* HTTP boundaries (client / server runtimes that need to operate over same data),
79
78
* client-side storage (requiring a local relational engine),
80
-
* offline-first requirements (requiring local replicas and syncing),
79
+
* offline-first architectures (requiring local replicas backed by a sync engine),
81
80
* realtime updates (requiring live queries and realtime subscriptions),
82
81
* and evolving schemas over time (often creating breaking changes for the application as schema drifts).
83
82
@@ -99,19 +98,15 @@ Each layer:
99
98
* introduces its own caching or consistency rules
100
99
* and breaks composability across runtime boundaries
101
100
102
-
**LinkedQL replaces this fragmented model with a single execution contract that holds across all environments**.
101
+
**LinkedQL replaces this fragmented model with a single execution contract that holds across all environments**,
103
102
104
-
At its core, LinkedQL provides:
103
+
and extends that with built-in support for:
105
104
106
-
* a **unified SQL interface** (`db.query(...)`)
107
-
* across **multiple runtimes** and **database models**
108
-
* with built-in support for:
109
-
110
-
* local execution,
111
-
* remote execution,
112
-
* federation,
113
-
* sync,
114
-
* and reactivity
105
+
* local execution,
106
+
* remote execution,
107
+
* federation,
108
+
* sync,
109
+
* and reactivity
115
110
116
111
---
117
112
@@ -156,14 +151,12 @@ await db.disconnect();
156
151
157
152
However, this is not just a wrapper over `node-postgres`.
158
153
159
-
The significance of this interface is that:
160
-
161
-
* the same `db.query()` call will later support
154
+
The same `db.query()` call will later support
162
155
163
-
* realtime queries
164
-
* cross-runtime execution
165
-
* local-first sync
166
-
* and version-aware querying
156
+
* realtime queries
157
+
* cross-runtime execution
158
+
* local-first sync
159
+
* and version-aware querying
167
160
168
161
**Without changing how you write queries.**
169
162
@@ -331,27 +324,25 @@ export async function POST(request) {
331
324
332
325
#### Important
333
326
334
-
This is not limited to browser → server.
327
+
This is not limited to browser → server models.
335
328
336
-
It applies to:
329
+
`EdgeClient` can be used anywhere a transport boundary exists:
337
330
338
-
* server → server communication
339
-
* edge → origin communication
340
-
* worker → worker communication
331
+
* server → server
332
+
* edge → origin
333
+
* worker → worker
341
334
* browser → worker (as seen in Scenario 4 below)
342
335
343
-
> **Anywhere a transport boundary exists, EdgeClient can bridge it.**
344
-
345
336
---
346
337
347
338
### Scenario 4: Cross-Runtime Querying over Message Ports
348
339
349
340
The same protocol used over HTTP can also run over **message channels**.
350
341
351
-
This is useful when:
342
+
A typical use case is:
352
343
353
-
* your architecture already uses workers
354
-
* or you want to avoid HTTP overhead
344
+
* An app runs on the browser main thread
345
+
* A LinkedQL instance (backed by IndexedDB) runs in a web worker
355
346
356
347
---
357
348
@@ -399,25 +390,9 @@ EdgeWorker.webWorker({
399
390
400
391
---
401
392
402
-
#### Why this matters
403
-
404
-
This completes the idea:
405
-
406
-
> **EdgeClient is a transport-agnostic execution bridge**
407
-
408
-
The same query can execute:
409
-
410
-
* locally
411
-
* over HTTP
412
-
* over message channels
413
-
414
-
without changing application code
415
-
416
-
---
417
-
418
393
#### The Edge Protocol does the heavy lifting
419
394
420
-
As against just sending raw SQL over HTTP, the client (`EdgeClient`) sends structured operations that map directly to the LinkedQL client interface (e.g. `query`, `stream`, `subscribe`, etc.).
395
+
As against just sending raw SQL over HTTP, the client (`EdgeClient`) sends structured operations that map directly to the LinkedQL client interface (e.g. `query()`, `stream()`, `subscribe()`, etc.).
421
396
422
397
This preserves:
423
398
@@ -429,7 +404,7 @@ This preserves:
429
404
430
405
### Scenario 5: Local-First and Offline-First Architectures
431
406
432
-
In this scenario, a hybrid data architecture where the goal is to:
407
+
In this scenario, we demonstrate a hybrid data architecture where the goal is to:
433
408
434
409
> Query remote data **as if it were local**, while controlling
435
410
> what stays remote, what gets cached locally, and what stays in sync.
@@ -476,14 +451,14 @@ await db.connect();
476
451
##### Decoding the above
477
452
478
453
* FlashQL is your **local relational engine**
479
-
* `"primary"` is simply the name we want to give to a **remote database**. (FlashQL lets the origin spec be application-defined. It can be a bare identifier as used here, or an URL, or something else.)
454
+
* `"primary"` is simply the name we want to give to a **remote database**. (FlashQL lets the origin details be application-defined. It can be a bare identifier as used here, or an URL, or something else.)
480
455
* `EdgeClient` is how FlashQL will talk to that remote system
481
456
482
457
At this point:
483
458
484
459
* nothing is mirrored yet
485
460
* no data is local
486
-
* we’ve only defined **how to reach the remote**
461
+
* we’ve only defined **how to reach the remote** from the local
487
462
488
463
But the local database by itself is ready for use as before:
* The programmatic `tx.createNamespace()` call above is equivalent to `db.query('CREATE SCHEMA remote')`, but lets us add the concept of **foreign origin**
508
+
* The programmatic `tx.createNamespace()` call above is equivalent to `db.query('CREATE SCHEMA remote')`, but it lets us add the concept of **foreign origin**
534
509
* `remote` is a **real local namespace (schema)** that can have tables and views (`VIEWS`) just like a regular namespace
535
510
* The difference is what happens when you create a view: **they will mirror tables in the remote database instead of mirror tables in the local database**
0 commit comments