ueberdb2 4.1.1 → 4.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/package.json +4 -1
  2. package/.eslintignore +0 -2
  3. package/.eslintrc.cjs +0 -66
  4. package/.github/dependabot.yml +0 -11
  5. package/.github/workflows/npmpublish.yml +0 -134
  6. package/.travis.yml +0 -46
  7. package/CHANGELOG.md +0 -304
  8. package/CONTRIBUTING.md +0 -103
  9. package/SECURITY.md +0 -5
  10. package/databases/cassandra_db.ts +0 -265
  11. package/databases/couch_db.ts +0 -189
  12. package/databases/dirty_db.ts +0 -85
  13. package/databases/dirty_git_db.ts +0 -82
  14. package/databases/elasticsearch_db.ts +0 -257
  15. package/databases/memory_db.ts +0 -41
  16. package/databases/mock_db.ts +0 -43
  17. package/databases/mongodb_db.ts +0 -142
  18. package/databases/mssql_db.ts +0 -226
  19. package/databases/mysql_db.ts +0 -183
  20. package/databases/postgres_db.ts +0 -213
  21. package/databases/postgrespool_db.ts +0 -11
  22. package/databases/redis_db.ts +0 -129
  23. package/databases/rethink_db.ts +0 -114
  24. package/databases/sqlite_db.ts +0 -159
  25. package/docker-compose.yml +0 -44
  26. package/index.ts +0 -224
  27. package/lib/AbstractDatabase.ts +0 -79
  28. package/lib/CacheAndBufferLayer.ts +0 -665
  29. package/lib/logging.ts +0 -33
  30. package/test/lib/databases.ts +0 -73
  31. package/test/lib/mysql.sql +0 -84
  32. package/test/test.ts +0 -328
  33. package/test/test_bulk.ts +0 -69
  34. package/test/test_elasticsearch.ts +0 -128
  35. package/test/test_findKeys.ts +0 -41
  36. package/test/test_flush.ts +0 -55
  37. package/test/test_getSub.ts +0 -28
  38. package/test/test_lru.ts +0 -151
  39. package/test/test_memory.ts +0 -32
  40. package/test/test_metrics.ts +0 -734
  41. package/test/test_mysql.ts +0 -62
  42. package/test/test_postgres.ts +0 -16
  43. package/test/test_setSub.ts +0 -19
  44. package/test/test_tojson.ts +0 -34
@@ -1,265 +0,0 @@
1
- /**
2
- * Licensed under the Apache License, Version 2.0 (the "License");
3
- * you may not use this file except in compliance with the License.
4
- * You may obtain a copy of the License at
5
- *
6
- * http://www.apache.org/licenses/LICENSE-2.0
7
- *
8
- * Unless required by applicable law or agreed to in writing, software
9
- * distributed under the License is distributed on an "AS-IS" BASIS,
10
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
- * See the License for the specific language governing permissions and
12
- * limitations under the License.
13
- */
14
-
15
- import AbstractDatabase, {Settings} from '../lib/AbstractDatabase';
16
- import cassandra, {ArrayOrObject, Client, types, ValueCallback} from 'cassandra-driver';
17
- import ResultSet = types.ResultSet;
18
-
19
-
20
- type Result = {
21
- rows: any[];
22
- };
23
-
24
- export type BulkObject = {
25
- type: string
26
- key:string
27
- value?: string
28
- };
29
-
30
- export const Database = class Cassandra_db extends AbstractDatabase {
31
- private client: Client | undefined;
32
- private pool: any;
33
- /**
34
- * @param {Object} settings The required settings object to initiate the Cassandra database
35
- * @param {String[]} settings.clientOptions See
36
- * http://www.datastax.com/drivers/nodejs/2.0/global.html#ClientOptions for a full set of
37
- * options that can be used
38
- * @param {String} settings.columnFamily The column family that should be used to store data. The
39
- * column family will be created if it doesn't exist
40
- * @param {Function} [settings.logger] Function that will be used to pass on log events emitted by
41
- * the Cassandra driver. See https://github.com/datastax/nodejs-driver#logging for more
42
- * information
43
- */
44
- constructor(settings:Settings) {
45
- super();
46
- if (!settings.clientOptions) {
47
- throw new Error('The Cassandra client options should be defined');
48
- }
49
- if (!settings.columnFamily) {
50
- throw new Error('The Cassandra column family should be defined');
51
- }
52
- this.settings = {database: settings.database};
53
- this.settings.clientOptions = settings.clientOptions;
54
- this.settings.columnFamily = settings.columnFamily;
55
- this.settings.logger = settings.logger;
56
- }
57
-
58
- /**
59
- * Initializes the Cassandra client, connects to Cassandra and creates the CF if it didn't exist
60
- * already
61
- *
62
- * @param {Function} callback Standard callback method.
63
- * @param {Error} callback.err An error object (if any.)
64
- */
65
- init(callback: (arg: any)=>{}) {
66
- // Create a client
67
- this.client = new cassandra.Client(this.settings.clientOptions);
68
-
69
- // Pass on log messages if a logger has been configured
70
- if (this.settings.logger) {
71
- this.client.on('log', this.settings.logger);
72
- }
73
-
74
- // Check whether our column family already exists and create it if necessary
75
- this.client.execute(
76
- 'SELECT columnfamily_name FROM system.schema_columnfamilies WHERE keyspace_name = ?',
77
- [this.settings.clientOptions.keyspace],
78
- (err, result) => {
79
- if (err) {
80
- return callback(err);
81
- }
82
-
83
- let isDefined = false;
84
- const length = result.rows.length;
85
- for (let i = 0; i < length; i++) {
86
- if (result.rows[i].columnfamily_name === this.settings.columnFamily) {
87
- isDefined = true;
88
- break;
89
- }
90
- }
91
-
92
- if (isDefined) {
93
- return callback(null);
94
- } else {
95
- const cql =
96
- `CREATE COLUMNFAMILY "${this.settings.columnFamily}" ` +
97
- '(key text PRIMARY KEY, data text)';
98
- this.client && this.client.execute(cql, callback);
99
- }
100
- });
101
- }
102
-
103
- /**
104
- * Gets a value from Cassandra
105
- *
106
- * @param {String} key The key for which the value should be retrieved
107
- * @param {Function} callback Standard callback method
108
- * @param {Error} callback.err An error object, if any
109
- * @param {String} callback.value The value for the given key (if any)
110
- */
111
- get(key:string, callback: (err:Error | null, data?:any)=>{}) {
112
- const cql = `SELECT data FROM "${this.settings.columnFamily}" WHERE key = ?`;
113
- this.client && this.client.execute(cql, [key], (err, result) => {
114
- if (err) {
115
- return callback(err);
116
- }
117
-
118
- if (!result.rows || result.rows.length === 0) {
119
- return callback(null, null);
120
- }
121
-
122
- return callback(null, result.rows[0].data);
123
- });
124
- }
125
-
126
- /**
127
- * Cassandra has no native `findKeys` method. This function implements a naive filter by
128
- * retrieving *all* the keys and filtering those. This should obviously be used with the utmost
129
- * care and is probably not something you want to run in production.
130
- *
131
- * @param {String} key The filter for keys that should match
132
- * @param {String} [notKey] The filter for keys that shouldn't match
133
- * @param {Function} callback Standard callback method
134
- * @param {Error} callback.err An error object, if any
135
- * @param {String[]} callback.keys An array of keys that match the specified filters
136
- */
137
- findKeys(key:string, notKey:string, callback: Function) {
138
- let cql = null;
139
- if (!notKey) {
140
- // Get all the keys
141
- cql = `SELECT key FROM "${this.settings.columnFamily}"`;
142
- this.client && this.client.execute(cql, (err: Error, result:Result) => {
143
- if (err) {
144
- return callback(err);
145
- }
146
-
147
- // Construct a regular expression based on the given key
148
- const regex = new RegExp(`^${key.replace(/\*/g, '.*')}$`);
149
-
150
- const keys:string[] = [];
151
- result.rows.forEach((row) => {
152
- if (regex.test(row.key)) {
153
- keys.push(row.key);
154
- }
155
- });
156
-
157
- return callback(null, keys);
158
- });
159
- } else if (notKey === '*:*:*') {
160
- // restrict key to format 'text:*'
161
- const matches = /^([^:]+):\*$/.exec(key);
162
- if (matches) {
163
- // Get the 'text' bit out of the key and get all those keys from a special column.
164
- // We can retrieve them from this column as we're duplicating them on .set/.remove
165
- cql = `SELECT * from "${this.settings.columnFamily}" WHERE key = ?`;
166
- this.client &&
167
- this.client
168
- .execute(cql, [`ueberdb:keys:${matches[1]}`], (err, result) => {
169
- if (err) {
170
- return callback(err);
171
- }
172
-
173
- if (!result.rows || result.rows.length === 0) {
174
- return callback(null, []);
175
- }
176
-
177
- const keys = result.rows.map((row) => row.data);
178
- return callback(null, keys);
179
- });
180
- } else {
181
- const msg =
182
- 'Cassandra db only supports key patterns like pad:* when notKey is set to *:*:*';
183
- return callback(new Error(msg), null);
184
- }
185
- } else {
186
- return callback(new Error('Cassandra db currently only supports *:*:* as notKey'), null);
187
- }
188
- }
189
-
190
- /**
191
- * Sets a value for a key
192
- *
193
- * @param {String} key The key to set
194
- * @param {String} value The value associated to this key
195
- * @param {Function} callback Standard callback method
196
- * @param {Error} callback.err An error object, if any
197
- */
198
- set(key: string, value:string, callback:()=>{}) {
199
- this.doBulk([{type: 'set', key, value}], callback);
200
- }
201
-
202
- /**
203
- * Removes a key and it's value from the column family
204
- *
205
- * @param {String} key The key to remove
206
- * @param {Function} callback Standard callback method
207
- * @param {Error} callback.err An error object, if any
208
- */
209
- remove(key:string, callback: ValueCallback<ResultSet>) {
210
- this.doBulk([{type: 'remove', key}], callback);
211
- }
212
-
213
-
214
- /**
215
- * Performs multiple operations in one action
216
- *
217
- * @param {Object[]} bulk The set of operations that should be performed
218
- * @param {Function} callback Standard callback method
219
- * @param {Error} callback.err An error object, if any
220
- */
221
- doBulk(bulk:BulkObject[], callback:ValueCallback<ResultSet>) {
222
- const queries:Array<string | {query: string, params?: ArrayOrObject}> = [];
223
- bulk.forEach((operation) => {
224
- // We support finding keys of the form `test:*`. If anything matches, we will try and save
225
- // this
226
- const matches = /^([^:]+):([^:]+)$/.exec(operation.key);
227
- if (operation.type === 'set') {
228
- queries.push({
229
- query: `UPDATE "${this.settings.columnFamily}" SET data = ? WHERE key = ?`,
230
- params: [operation.value, operation.key],
231
- });
232
-
233
- if (matches) {
234
- queries.push({
235
- query: `UPDATE "${this.settings.columnFamily}" SET data = ? WHERE key = ?`,
236
- params: ['1', `ueberdb:keys:${matches[1]}`],
237
- });
238
- }
239
- } else if (operation.type === 'remove') {
240
- queries.push({
241
- query: `DELETE FROM "${this.settings.columnFamily}" WHERE key=?`,
242
- params: [operation.key],
243
- });
244
-
245
- if (matches) {
246
- queries.push({
247
- query: `DELETE FROM "${this.settings.columnFamily}" WHERE key = ?`,
248
- params: [`ueberdb:keys:${matches[1]}`],
249
- });
250
- }
251
- }
252
- });
253
- this.client && this.client.batch(queries, {prepare: true}, callback);
254
- }
255
-
256
- /**
257
- * Closes the Cassandra connection
258
- *
259
- * @param {Function} callback Standard callback method
260
- * @param {Error} callback.err Error object in case something goes wrong
261
- */
262
- close(callback: ()=>{}) {
263
- this.pool.shutdown(callback);
264
- }
265
- };
@@ -1,189 +0,0 @@
1
- /**
2
- * 2012 Max 'Azul' Wiehle
3
- *
4
- * Licensed under the Apache License, Version 2.0 (the "License");
5
- * you may not use this file except in compliance with the License.
6
- * You may obtain a copy of the License at
7
- *
8
- * http://www.apache.org/licenses/LICENSE-2.0
9
- *
10
- * Unless required by applicable law or agreed to in writing, software
11
- * distributed under the License is distributed on an "AS-IS" BASIS,
12
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- * See the License for the specific language governing permissions and
14
- * limitations under the License.
15
- */
16
-
17
- import AbstractDatabase, {Settings} from '../lib/AbstractDatabase';
18
- import http, {Agent} from 'http';
19
- import nano from 'nano';
20
- import {BulkObject} from './cassandra_db';
21
-
22
- type CouchDBSettings = {
23
- url: string,
24
- requestDefaults: {
25
- auth?: {
26
- username: string,
27
- password: string,
28
- },
29
- agent: Agent
30
- }
31
- };
32
- export const Database = class Couch_db extends AbstractDatabase {
33
- private agent: Agent | null;
34
- private db: nano.DocumentScope<string> | null;
35
- constructor(settings: Settings) {
36
- super();
37
- this.agent = null;
38
- this.db = null;
39
- this.settings = settings;
40
-
41
- // force some settings
42
- // used by CacheAndBufferLayer.js
43
- this.settings.cache = 1000;
44
- this.settings.writeInterval = 100;
45
- this.settings.json = false;
46
- }
47
-
48
- get isAsync() { return true; }
49
-
50
- async init() {
51
- this.agent = new http.Agent({
52
- keepAlive: true,
53
- maxSockets: this.settings.maxListeners || 1,
54
- });
55
-
56
- const coudhDBSettings: CouchDBSettings = {
57
- url: `http://${this.settings.host}:${this.settings.port}`,
58
- requestDefaults: {
59
- agent: this.agent,
60
- },
61
- };
62
-
63
- if (this.settings.user && this.settings.password) {
64
- coudhDBSettings.requestDefaults.auth = {
65
- username: this.settings.user,
66
- password: this.settings.password,
67
- };
68
- }
69
-
70
-
71
- const client = nano(coudhDBSettings);
72
- try {
73
- if (this.settings.database != null) {
74
- await client.db.get(this.settings.database);
75
- }
76
- } catch (err: any) {
77
- if (err.statusCode !== 404) throw err;
78
- if (this.settings.database != null) {
79
- await client.db.create(this.settings.database);
80
- }
81
- }
82
- if (this.settings.database != null) {
83
- this.db = client.use(this.settings.database);
84
- }
85
- }
86
-
87
- async get(key:string): Promise<null | string> {
88
- let doc;
89
- try {
90
- if (this.db) {
91
- doc = await this.db.get(key);
92
- }
93
- } catch (err:any) {
94
- if (err.statusCode === 404) return null;
95
- throw err;
96
- }
97
- if (doc && 'value' in doc) {
98
- return doc.value as string;
99
- }
100
- return '';
101
- }
102
-
103
- async findKeys(key:string, notKey:string) {
104
- const pfxLen = key.indexOf('*');
105
- if (!this.db) {
106
- return;
107
- }
108
- const pfx = pfxLen < 0 ? key : key.slice(0, pfxLen);
109
- const results = await this.db.find({
110
- selector: {
111
- _id: pfxLen < 0 ? pfx : {
112
- $gte: pfx,
113
- // https://docs.couchdb.org/en/3.2.2/ddocs/views/collation.html#string-ranges
114
- $lte: `${pfx}\ufff0`,
115
- $regex: this.createFindRegex(key, notKey).source,
116
- },
117
- },
118
- fields: ['_id'],
119
- });
120
- return results.docs.map((doc) => doc._id);
121
- }
122
-
123
- async set(key:string, value:string) {
124
- let doc;
125
-
126
- if (!this.db) {
127
- return;
128
- }
129
-
130
- try {
131
- doc = await this.db.get(key);
132
- } catch (err:any) {
133
- if (err.statusCode !== 404) throw err;
134
- }
135
- await this.db.insert({
136
- _id: key,
137
- // @ts-ignore
138
- value,
139
- ...doc == null ? {} : {
140
- _rev: doc._rev,
141
- },
142
- });
143
- }
144
-
145
- async remove(key:string) {
146
- let header;
147
- if (!this.db) {
148
- return;
149
- }
150
- try {
151
- header = await this.db.head(key);
152
- } catch (err:any) {
153
- if (err.statusCode === 404) return;
154
- throw err;
155
- }
156
- // etag has additional quotation marks, remove them
157
- const etag = JSON.parse(header.etag);
158
- await this.db.destroy(key, etag);
159
- }
160
-
161
- async doBulk(bulk:BulkObject[]) {
162
- if (!this.db) {
163
- return;
164
- }
165
- const keys = bulk.map((op) => op.key);
166
- const revs:{[key:string]:any} = {};
167
- // @ts-ignore
168
- for (const {key, value} of (await this.db.fetchRevs({keys})).rows) {
169
- // couchDB will return error instead of value if key does not exist
170
- if (value != null) revs[key] = value.rev;
171
- }
172
- const setters = [];
173
- for (const item of bulk) {
174
- const set = {_id: item.key, _rev: undefined,
175
- _deleted: false, value: ''};
176
- if (revs[item.key] != null) set._rev = revs[item.key];
177
- if (item.type === 'set') set.value = item.value as string;
178
- if (item.type === 'remove') set._deleted = true;
179
- setters.push(set);
180
- }
181
- await this.db && await this.db.bulk({docs: setters});
182
- }
183
-
184
- async close() {
185
- this.db = null;
186
- if (this.agent) this.agent.destroy();
187
- this.agent = null;
188
- }
189
- };
@@ -1,85 +0,0 @@
1
- /**
2
- * 2011 Peter 'Pita' Martischka
3
- *
4
- * Licensed under the Apache License, Version 2.0 (the "License");
5
- * you may not use this file except in compliance with the License.
6
- * You may obtain a copy of the License at
7
- *
8
- * http://www.apache.org/licenses/LICENSE-2.0
9
- *
10
- * Unless required by applicable law or agreed to in writing, software
11
- * distributed under the License is distributed on an "AS-IS" BASIS,
12
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- * See the License for the specific language governing permissions and
14
- * limitations under the License.
15
- */
16
-
17
- /*
18
- *
19
- * Fair warning that length may not provide the correct value upon load.
20
- * See https://github.com/ether/etherpad-lite/pull/3984
21
- *
22
- */
23
-
24
- import AbstractDatabase, {Settings} from '../lib/AbstractDatabase';
25
- // @ts-ignore
26
- import Dirty from 'dirty';
27
-
28
- type DirtyDBCallback = (p?:any, keys?: string[])=>{};
29
-
30
-
31
- export const Database = class extends AbstractDatabase {
32
- private db: any;
33
- constructor(settings:Settings) {
34
- super();
35
- this.db = null;
36
-
37
- if (!settings || !settings.filename) {
38
- // @ts-ignore
39
- settings = {filename: null};
40
- }
41
-
42
- this.settings = settings;
43
-
44
- // set default settings
45
- this.settings.cache = 0;
46
- this.settings.writeInterval = 0;
47
- this.settings.json = false;
48
- }
49
-
50
- init(callback: ()=>{}) {
51
- this.db = new Dirty(this.settings.filename);
52
- this.db.on('load', (err:string) => {
53
- callback();
54
- });
55
- }
56
-
57
- get(key:string, callback:DirtyDBCallback) {
58
- callback(null, this.db.get(key));
59
- }
60
-
61
- findKeys(key:string, notKey:string, callback:DirtyDBCallback) {
62
- const keys:string[] = [];
63
- const regex = this.createFindRegex(key, notKey);
64
- this.db.forEach((key:string, val:string) => {
65
- if (key.search(regex) !== -1) {
66
- keys.push(key);
67
- }
68
- });
69
- callback(null, keys);
70
- }
71
-
72
- set(key:string, value:string, callback:DirtyDBCallback) {
73
- this.db.set(key, value, callback);
74
- }
75
-
76
- remove(key:string, callback:DirtyDBCallback) {
77
- this.db.rm(key, callback);
78
- }
79
-
80
- close(callback:DirtyDBCallback) {
81
- this.db.close();
82
- this.db = null;
83
- if (callback) callback();
84
- }
85
- };
@@ -1,82 +0,0 @@
1
- import AbstractDatabase, {Settings} from '../lib/AbstractDatabase';
2
-
3
- /**
4
- * 2011 Peter 'Pita' Martischka
5
- *
6
- * Licensed under the Apache License, Version 2.0 (the "License");
7
- * you may not use this file except in compliance with the License.
8
- * You may obtain a copy of the License at
9
- *
10
- * http://www.apache.org/licenses/LICENSE-2.0
11
- *
12
- * Unless required by applicable law or agreed to in writing, software
13
- * distributed under the License is distributed on an "AS-IS" BASIS,
14
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
- * See the License for the specific language governing permissions and
16
- * limitations under the License.
17
- */
18
-
19
-
20
- // @ts-ignore
21
- import {Dirty} from 'dirty';
22
-
23
- export const Database = class extends AbstractDatabase {
24
- private db: any;
25
- constructor(settings: Settings) {
26
- super();
27
- // @ts-ignore
28
- this.db = null;
29
-
30
- if (!settings || !settings.filename) {
31
- settings = {};
32
- }
33
-
34
- this.settings = settings;
35
-
36
- // set default settings
37
- this.settings.cache = 0;
38
- this.settings.writeInterval = 0;
39
- this.settings.json = false;
40
- }
41
-
42
- init(callback: ()=>void) {
43
- this.db = new Dirty(this.settings.filename);
44
- this.db.on('load', (err: Error) => {
45
- callback();
46
- });
47
- }
48
-
49
- get(key:string, callback: (err: string | any, value: string)=>void) {
50
- callback(null, this.db.get(key));
51
- }
52
-
53
- findKeys(key:string, notKey:string, callback:(v:any, keys:string[])=>{}) {
54
- const keys:string[] = [];
55
- const regex = this.createFindRegex(key, notKey);
56
- this.db.forEach((key:string, val:string) => {
57
- if (key.search(regex) !== -1) {
58
- keys.push(key);
59
- }
60
- });
61
- callback(null, keys);
62
- }
63
-
64
- set(key:string, value: string, callback: ()=>{}) {
65
- this.db.set(key, value, callback);
66
- const databasePath = require('path').dirname(this.settings.filename);
67
- require('simple-git')(databasePath)
68
- .silent(true)
69
- .add('./*.db')
70
- .commit('Automated commit...')
71
- .push(['-u', 'origin', 'master'], () => console.debug('Stored git commit'));
72
- }
73
-
74
- remove(key:string, callback:()=> {}) {
75
- this.db.rm(key, callback);
76
- }
77
-
78
- close(callback: ()=>void) {
79
- this.db.close();
80
- if (callback) callback();
81
- }
82
- };