Skip to content

Merge fork #14

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 36 commits into from
Apr 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
c25f16b
converted to es6 using lebab.io
billwashere Feb 18, 2018
9435775
changed structure to jsonb
billwashere Feb 18, 2018
da16bda
rewrote commit to insert ops and snapshot in one transaction
billwashere Feb 18, 2018
9c9773a
revert es6 style imports
billwashere Feb 18, 2018
b803ca1
es6 exports fix
billwashere Feb 18, 2018
5235fa0
revert again
billwashere Feb 18, 2018
b8a81ba
missed var
billwashere Feb 18, 2018
47c3e45
removed second on conflict
billwashere Feb 18, 2018
1c8de9d
upgraded pg
billwashere Feb 18, 2018
d6c8a2d
fixed sql and upgraded to use PG pool. Also iif it doens't commit it …
billwashere Feb 24, 2018
c5af377
fixed typo
billwashere Feb 24, 2018
1180728
updated readme
billwashere Feb 24, 2018
7becba9
reverted es6 convertion
billwashere Feb 25, 2018
3aa6abc
cleanup for release
billwashere Mar 10, 2018
3ed4039
forgot a backtick
billwashere Mar 10, 2018
1ed2925
JSONB, PG library, and check max update
billwashere Mar 10, 2018
bde4c6e
formating and review changes
billwashere Mar 17, 2018
698bb62
typo
billwashere Mar 17, 2018
19210ee
Merge branch 'master' into release
billwashere Jun 10, 2018
cd5b2ef
shift the query range in ops
zbryikt Jul 11, 2018
351485a
shift getops range
zbryikt Jul 11, 2018
51f1c57
by doc, getOps return ops to the latest version if version is null. a…
zbryikt May 24, 2020
7d6b8e6
add index for ops version. dont create table if existed.
zbryikt May 24, 2020
3b81a11
remove log
zbryikt May 24, 2020
a42f2dc
update index. add .gitignore and sample-cmd
zbryikt May 24, 2020
202ea6a
by doc, getOps return ops to the latest version if version is null. a…
zbryikt May 24, 2020
3abe1a0
add index for ops version. dont create table if existed.
zbryikt May 24, 2020
45781a1
update index. add .gitignore and sample-cmd
zbryikt May 24, 2020
955dbd8
Merge branch 'release'
zbryikt May 25, 2020
55a0c76
add pg-pool, update sharedb
zbryikt May 30, 2020
cb0c704
upgrade `pg` from 7.4.1 to 8.5.1 to prevent silent failure for node v14
zbryikt Feb 2, 2021
84ce49e
update repo url
zbryikt Feb 2, 2021
f8890b1
upgrade sharedb
zbryikt Feb 2, 2021
2d9aa16
update package name
cunzhe7 Jul 2, 2021
9d88e6a
Merge pull request #1 from smalllicheng/master
zbryikt Jul 8, 2021
77f58a4
Merge remote-tracking branch 'plotdb/master' into merge-fork
alecgibson Feb 8, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
## 4.0.1

- upgrade sharedb


## 4.0.0

- upgrade `pg` from 7.4.1 to 8.5.1 to prevent silent failure for node v14 or later, reported in [this issue](https://github.com/brianc/node-postgres/issues/2317).
- fix submit ops failed due to version mismatched - https://github.com/share/sharedb-postgres/issues/8

## Note about re-versioning

Original `sharedb-postgres` seems to have been not maintained for a long time since 2018. Thus we made a fork and maintain it as `@plotdb/sharedb-postgre`.


# Change log in original repo

## 3.0.0

Thanks to @billwashere, we upgraded to a more modern version of `pg` (4.5.1 ->
Expand Down
58 changes: 52 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,68 @@
# sharedb-postgres
# @plotdb/sharedb-postgres

PostgreSQL database adapter for [sharedb](https://github.com/share/sharedb). This
driver can be used both as a snapshot store and oplog.
PostgreSQL database adapter for [sharedb](https://github.com/share/sharedb). This driver can be used both as a snapshot store and oplog.

Doesn't support queries (yet?).

Moderately experimental. (This drives [Synaptograph](https://www.synaptograph.com)'s backend, and [@nornagon](https://github.com/nornagon) hasn't noticed any issues so far.)


## Note about versioning

This is a fork from the [original `sharedb-postgres`](https://github.com/share/sharedb-postgres) and its relative forks (see [billwashere](https://github.com/billwashere/sharedb-postgres-jsonb), [zbryikt](https://github.com/zbryikt/sharedb-postgres-jsonb). It seems to have been not maintained for a long time since 2018, Thus we decide to fork it and maintain it as `@plotdb/sharedb-postgre`.


## Installation

```cmd
npm i @plotdb/sharedb-postgres
```


## Requirements

Due to the fix to resolve [high concurency issues](https://github.com/share/sharedb-postgres/issues/1) Postgres 9.5+ is now required.

## Migrating older versions

Older versions of this adaptor used the data type json. You will need to alter the data type prior to using if you are upgrading.

```PLpgSQL
ALTER TABLE ops
ALTER COLUMN operation
SET DATA TYPE jsonb
USING operation::jsonb;

ALTER TABLE snapshots
ALTER COLUMN data
SET DATA TYPE jsonb
USING data::jsonb;
```

## Usage

`sharedb-postgres` wraps native [node-postgres](https://github.com/brianc/node-postgres), and it supports the same configuration options.
`sharedb-postgres-jsonb` wraps native [node-postgres](https://github.com/brianc/node-postgres), and it supports the same configuration options.

To instantiate a sharedb-postgres wrapper, invoke the module and pass in your
PostgreSQL configuration as an argument. For example:
PostgreSQL configuration as an argument or use environmental arguments.

For example using environmental arugments:

```js
var db = require('@plotdb/sharedb-postgres')();
var backend = require('sharedb')({db: db})
```

Then executing via the command line

```
PGUSER=dbuser PGPASSWORD=secretpassword PGHOST=database.server.com PGDATABASE=mydb PGPORT=5433 npm start
```

Example using an object

```js
var db = require('sharedb-postgres')({host: 'localhost', database: 'mydb'});
var db = require('@plotdb/sharedb-postgres')({host: 'localhost', database: 'mydb'});
var backend = require('sharedb')({db: db})
```

Expand Down
161 changes: 77 additions & 84 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ function PostgresDB(options) {

this.closed = false;

this.pg_config = options;
this.pool = new pg.Pool(options);
};
module.exports = PostgresDB;
Expand All @@ -22,11 +23,6 @@ PostgresDB.prototype.close = function(callback) {
if (callback) callback();
};

function rollback(client, done) {
client.query('ROLLBACK', function(err) {
return done(err);
})
}

// Persists an op and snapshot if it is for the next version. Calls back with
// callback(err, succeeded)
Expand All @@ -41,84 +37,78 @@ PostgresDB.prototype.commit = function(collection, id, op, snapshot, options, ca
* }
* snapshot: PostgresSnapshot
*/
this.pool.connect(function(err, client, done) {
if (err) {
done(client);
callback(err);
return;
}
function commit() {
client.query('COMMIT', function(err) {
done(err);
if (err) {
callback(err);
} else {
callback(null, true);
}
})
this.pool.connect((err, client, done) => {
if (err) {
done(client);
callback(err);
return;
}
/*
* This query uses common table expression to upsert the snapshot table
* (iff the new version is exactly 1 more than the latest table or if
* the document id does not exists)
*
* It will then insert into the ops table if it is exactly 1 more than the
* latest table or it the first operation and iff the previous insert into
* the snapshot table is successful.
*
* This result of this query the version of the newly inserted operation
* If either the ops or the snapshot insert fails then 0 rows are returned
*
* If 0 zeros are return then the callback must return false
*
* Casting is required as postgres thinks that collection and doc_id are
* not varchar
*/
const query = {
name: 'sdb-commit-op-and-snap',
text: `WITH snapshot_id AS (
INSERT INTO snapshots (collection, doc_id, doc_type, version, data)
SELECT $1::varchar collection, $2::varchar doc_id, $4 doc_type, $3 v, $5 d
WHERE $3 = (
SELECT version+1 v
FROM snapshots
WHERE collection = $1 AND doc_id = $2
FOR UPDATE
) OR NOT EXISTS (
SELECT 1
FROM snapshots
WHERE collection = $1 AND doc_id = $2
FOR UPDATE
)
ON CONFLICT (collection, doc_id) DO UPDATE SET version = $3, data = $5, doc_type = $4
RETURNING version
)
INSERT INTO ops (collection, doc_id, version, operation)
SELECT $1::varchar collection, $2::varchar doc_id, $3 v, $6 operation
WHERE (
$3 = (
SELECT max(version)+1
FROM ops
WHERE collection = $1 AND doc_id = $2
) OR NOT EXISTS (
SELECT 1
FROM ops
WHERE collection = $1 AND doc_id = $2
)
) AND EXISTS (SELECT 1 FROM snapshot_id)
RETURNING version`,
values: [collection,id,snapshot.v, snapshot.type, snapshot.data,op]
}
client.query(
'SELECT max(version) AS max_version FROM ops WHERE collection = $1 AND doc_id = $2',
[collection, id],
function(err, res) {
var max_version = res.rows[0].max_version;
if (max_version == null)
max_version = 0;
if (snapshot.v !== max_version + 1) {
return callback(null, false);
}
client.query('BEGIN', function(err) {
client.query(
'INSERT INTO ops (collection, doc_id, version, operation) VALUES ($1, $2, $3, $4)',
[collection, id, snapshot.v, op],
function(err, res) {
if (err) {
// TODO: if err is "constraint violation", callback(null, false) instead
rollback(client, done);
callback(err);
return;
}
if (snapshot.v === 1) {
client.query(
'INSERT INTO snapshots (collection, doc_id, doc_type, version, data) VALUES ($1, $2, $3, $4, $5)',
[collection, id, snapshot.type, snapshot.v, snapshot.data],
function(err, res) {
// TODO:
// if the insert was successful and did insert, callback(null, true)
// if the insert was successful and did not insert, callback(null, false)
// if there was an error, rollback and callback(error)
if (err) {
rollback(client, done);
callback(err);
return;
}
commit();
}
)
} else {
client.query(
'UPDATE snapshots SET doc_type = $3, version = $4, data = $5 WHERE collection = $1 AND doc_id = $2 AND version = ($4 - 1)',
[collection, id, snapshot.type, snapshot.v, snapshot.data],
function(err, res) {
// TODO:
// if any rows were updated, success
// if 0 rows were updated, rollback and not success
// if error, rollback and not success
if (err) {
rollback(client, done);
callback(err);
return;
}
commit();
}
)
}
}
)
})
client.query(query, (err, res) => {
if (err) {
callback(err)
} else if(res.rows.length === 0) {
done(client);
callback(null,false)
}
else {
done(client);
callback(null,true)
}
)
})
})

})
};

// Get the named document from the database. The callback is called with (err,
Expand Down Expand Up @@ -181,9 +171,12 @@ PostgresDB.prototype.getOps = function(collection, id, from, to, options, callba
callback(err);
return;
}
client.query(
'SELECT version, operation FROM ops WHERE collection = $1 AND doc_id = $2 AND version >= $3 AND version < $4',
[collection, id, from, to],

var cmd = 'SELECT version, operation FROM ops WHERE collection = $1 AND doc_id = $2 AND version > $3 ';
var params = [collection, id, from];
if(to || to == 0) { cmd += ' AND version <= $4'; params.push(to)}
cmd += ' order by version';
client.query( cmd, params,
function(err, res) {
done();
if (err) {
Expand Down
Loading