|
1 | 1 | Dart implementation of Conflict-free Replicated Data Types (CRDTs).
|
2 | 2 |
|
3 |
| -This project is heavily influenced by James Long's talk [CRTDs for Mortals](https://www.dotconferences.com/2019/12/james-long-crdts-for-mortals) and includes a Dart-native implementation of Hybrid Local Clocks (HLC) based on the paper [Logical Physical Clocks and Consistent Snapshots in Globally Distributed Databases](https://cse.buffalo.edu/tech-reports/2014-04.pdf). |
| 3 | +This project is heavily influenced by James Long's talk [CRTDs for Mortals](https://www.dotconferences.com/2019/12/james-long-crdts-for-mortals) and includes a Dart-native implementation of Hybrid Local Clocks (HLC) based on the paper [Logical Physical Clocks and Consistent Snapshots in Globally Distributed Databases](https://cse.buffalo.edu/tech-reports/2014-04.pdf) (pdf). |
4 | 4 |
|
5 |
| -It has [zero external dependencies](https://github.com/cachapa/crdt/blob/master/pubspec.yaml), so it should run everywhere where Dart runs. |
| 5 | +It has [minimal external dependencies](https://github.com/cachapa/crdt/blob/master/pubspec.yaml), so it should run anywhere where Dart runs, which is pretty much everywhere. |
6 | 6 |
|
7 |
| -See [sql_crdt](https://github.com/cachapa/sql_crdt) for an implementation of CRDTs backed by an SQL database. |
| 7 | +The `Crdt` class implements CRDT conflict resolution and serves as a storage-agnostic interface for specific implementations. Als included with this package is `MapCrdt`, an ephemeral implementation using Dart HashMaps. |
| 8 | + |
| 9 | +Other implementations include (so far): |
| 10 | +- [hive_crdt](https://github.com/cachapa/hive_crdt), a no-sql implementation using [Hive](https://pub.dev/packages/hive) as persistent storage. |
| 11 | +- [sql_crdt](https://github.com/cachapa/sql_crdt), an abstract implementation for using relational databases as a data storage backend. |
| 12 | +- [sqlite_crdt](https://github.com/cachapa/sqlite_crdt), an implementation using Sqlite for storage, useful for mobile or small projects. |
| 13 | +- [postgres_crdt](https://github.com/cachapa/postgres_crdt), a `sql_crdt` that benefits from PostgreSQL's performance and scalability intended for backend applications. |
| 14 | + |
| 15 | +See also [crdt_sync](https://github.com/cachapa/crdt_sync), a turnkey approach for real-time network synchronization of `Crdt` nodes. |
8 | 16 |
|
9 | 17 | ## Usage
|
10 | 18 |
|
11 |
| -The `Crdt` class works as a layer on top of a map. The simplest way to experiment is to initialise it with an empty map: |
| 19 | +The simplest way to experiment with this package is to use the provided `MapCrdt` implementation: |
12 | 20 |
|
13 | 21 | ```dart
|
14 |
| -import 'package:crdt/crdt.dart'; |
| 22 | +import 'package:crdt/map_crdt.dart'; |
15 | 23 |
|
16 | 24 | void main() {
|
17 |
| - var crdt = MapCrdt('node_id'); |
18 |
| -
|
19 |
| - // Insert a record |
20 |
| - crdt.put('a', 1); |
21 |
| - // Read the record |
22 |
| - print('Record: ${crdt.get('a')}'); |
23 |
| -
|
24 |
| - // Export the CRDT as Json |
25 |
| - final json = crdt.toJson(); |
26 |
| - // Send to remote node |
27 |
| - final remoteJson = sendToRemote(json); |
28 |
| - // Merge remote CRDT with local |
29 |
| - crdt.mergeJson(remoteJson); |
30 |
| - // Verify updated record |
31 |
| - print('Record after merging: ${crdt.get('a')}'); |
32 |
| -} |
| 25 | + var crdt1 = MapCrdt(['table']); |
| 26 | + var crdt2 = MapCrdt(['table']); |
| 27 | +
|
| 28 | + print('Inserting 2 records in crdt1…'); |
| 29 | + crdt1.put('table', 'a', 1); |
| 30 | + crdt1.put('table', 'b', 1); |
| 31 | +
|
| 32 | + print('crdt1: ${crdt1.get('table')}'); |
33 | 33 |
|
34 |
| -// Mock sending the CRDT to a remote node and getting an updated one back |
35 |
| -String sendToRemote(String json) { |
36 |
| - final hlc = Hlc.now('another_nodeId'); |
37 |
| - return '{"a":{"hlc":"$hlc","value":2}}'; |
| 34 | + print('\nInserting a conflicting record in crdt2…'); |
| 35 | + crdt2.put('table', 'a', 2); |
| 36 | +
|
| 37 | + print('crdt2: ${crdt2.get('table')}'); |
| 38 | +
|
| 39 | + print('\nMerging crdt2 into crdt1…'); |
| 40 | + crdt1.merge(crdt2.getChangeset()); |
| 41 | +
|
| 42 | + print('crdt1: ${crdt1.get('table')}'); |
38 | 43 | }
|
39 | 44 | ```
|
40 | 45 |
|
41 |
| -You'll probably want to implement some sort of persistent storage by subclassing the `Crdt` class. An example using [Hive](https://pub.dev/packages/hive) is provided in [hive_crdt](https://github.com/cachapa/hive_crdt). |
| 46 | +## Implementations |
| 47 | + |
| 48 | +`crdt` is currently helping build local-first experiences for: |
42 | 49 |
|
43 |
| -## Example |
| 50 | +- [Libra](https://libra-app.eu) a weigh management app with 1M+ installs. |
| 51 | +- [tudo](https://github.com/cachapa/tudo) an open-source simple to-do app + backend. |
44 | 52 |
|
45 |
| -A [simple example](https://github.com/cachapa/crdt/blob/master/example/crdt_example.dart) is provided with this project. |
| 53 | +Are you using this package in your project? Let me know! |
46 | 54 |
|
47 | 55 | ## Features and bugs
|
48 | 56 |
|
|
0 commit comments