Commit 6b8f19fb3b608e0c8d3ebdb9053a18257e6fe9d3
Initial commit
Charles Lehner committed on 3/31/2016, 4:29:08 AMFiles changed
README.md | added |
index.js | added |
package.json | added |
test.js | added |
README.md | |||
---|---|---|---|
@@ -1,0 +1,48 @@ | |||
1 … | +# pull-kvdiff | ||
2 … | + | ||
3 … | +diff key-value streams | ||
4 … | + | ||
5 … | +```js | ||
6 … | +var pull = require('pull-stream') | ||
7 … | +var kvdiff = require('pull-kvdiff') | ||
8 … | + | ||
9 … | +pull( | ||
10 … | + kvdiff([ | ||
11 … | + pull.values([ | ||
12 … | + {key: 'a', value: 1}, | ||
13 … | + {key: 'b', value: 2}, | ||
14 … | + {key: 'c', value: 3}, | ||
15 … | + ]), | ||
16 … | + pull.values([ | ||
17 … | + {key: 'a', value: 1}, | ||
18 … | + {key: 'b', value: 3}, | ||
19 … | + {key: 'd', value: 3}, | ||
20 … | + ]) | ||
21 … | + ], 'key'), | ||
22 … | + pull.log() | ||
23 … | +) | ||
24 … | +``` | ||
25 … | +output: | ||
26 … | +```json | ||
27 … | +{ key: 'b', | ||
28 … | + values: [ { key: 'b', value: 2 }, { key: 'b', value: 3 } ], | ||
29 … | + diff: { value: [ 2, 3 ] } } | ||
30 … | +{ key: 'c', | ||
31 … | + values: [ { key: 'c', value: 3 }, ], | ||
32 … | + diff: { key: [ 'c' ], value: [ 3 ] } } | ||
33 … | +{ key: 'd', | ||
34 … | + values: [ , { key: 'd', value: 3 } ], | ||
35 … | + diff: { key: [ , 'd' ], value: [ , 3 ] } } | ||
36 … | +``` | ||
37 … | + | ||
38 … | +#### `kvdiff(sources, keyProp) → source` | ||
39 … | + | ||
40 … | +## License | ||
41 … | + | ||
42 … | +Copyright (c) 2016 Charles Lehner | ||
43 … | + | ||
44 … | +Usage of the works is permitted provided that this instrument is | ||
45 … | +retained with the works, so that any entity that uses the works is | ||
46 … | +notified of this instrument. | ||
47 … | + | ||
48 … | +DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY. |
index.js | ||
---|---|---|
@@ -1,0 +1,81 @@ | ||
1 … | +var multicb = require('multicb') | |
2 … | + | |
3 … | +function diff(objs) { | |
4 … | + if (objs.length < 2) return {} | |
5 … | + var results | |
6 … | + var keys = {} | |
7 … | + for (var i = 0; i < objs.length; i++) | |
8 … | + for (var k in objs[i]) | |
9 … | + keys[k] = true | |
10 … | + | |
11 … | + var first = objs[0] || {} | |
12 … | + for (var i = 1; i < objs.length; i++) { | |
13 … | + var curr = objs[i] || {} | |
14 … | + for (var k in keys) { | |
15 … | + if (curr[k] !== first[k]) { | |
16 … | + changed = true | |
17 … | + var keyResults = (results || (results = {}))[k] || (results[k] = []) | |
18 … | + if (k in curr) | |
19 … | + keyResults[i] = curr[k] | |
20 … | + if (k in first) | |
21 … | + keyResults[0] = first[k] | |
22 … | + } | |
23 … | + } | |
24 … | + } | |
25 … | + return results | |
26 … | +} | |
27 … | + | |
28 … | +module.exports = function (sources, keyProp) { | |
29 … | + var n = sources.length | |
30 … | + var results = {/* key: {values: [argI: value], waiting: n} */} | |
31 … | + var got = {/* key: bool */} | |
32 … | + var waiting = n | |
33 … | + return function read(end, cb) { | |
34 … | + if (end) { | |
35 … | + if (waiting == 0) | |
36 … | + return cb(end) | |
37 … | + var done = multicb({pluck: 1}) | |
38 … | + for (var j = 0; j < sources.length; j++) | |
39 … | + if (sources[j]) | |
40 … | + sources[j](end, done()) | |
41 … | + return done(cb) | |
42 … | + } | |
43 … | + next(cb, -1) | |
44 … | + } | |
45 … | + function next(cb, i) { | |
46 … | + do { | |
47 … | + i++ | |
48 … | + i %= n | |
49 … | + } while (!sources[i]) | |
50 … | + sources[i](null, function (end, item) { | |
51 … | + if (end) { | |
52 … | + sources[i] = null | |
53 … | + if (0 == --waiting) doneReading(cb) | |
54 … | + else next(cb, i) | |
55 … | + return | |
56 … | + } | |
57 … | + var key = keyProp ? item[keyProp] : String(item) | |
58 … | + var keyResults = results[key] || (results[key] = { | |
59 … | + values: new Array(n), | |
60 … | + waiting: n | |
61 … | + }) | |
62 … | + keyResults.values[i] = item | |
63 … | + if (--keyResults.waiting > 0) return next(cb, i) | |
64 … | + delete results[key] | |
65 … | + var result = diff(keyResults.values, keyProp) | |
66 … | + if (!result) return next(cb, i) | |
67 … | + cb(null, {key: key, values: keyResults.values, diff: result}) | |
68 … | + }) | |
69 … | + } | |
70 … | + function doneReading(cb) { | |
71 … | + next = doneReading | |
72 … | + for (var key in results) { | |
73 … | + var values = results[key].values | |
74 … | + var result = diff(values, keyProp) | |
75 … | + delete results[key] | |
76 … | + if (result) | |
77 … | + return cb(null, {key: key, values: values, diff: result}) | |
78 … | + } | |
79 … | + cb(true) | |
80 … | + } | |
81 … | +} |
package.json | ||
---|---|---|
@@ -1,0 +1,20 @@ | ||
1 … | +{ | |
2 … | + "name": "pull-kvdiff", | |
3 … | + "version": "0.0.0", | |
4 … | + "description": "diff key-value streams", | |
5 … | + "homepage": "http://git-ssb.celehner.com/%25TZOXQlZsigfkBWfepmMVvm4jsvgyaXcXXD3GA8Wtmi0%3D.sha256", | |
6 … | + "bugs": "http://git-ssb.celehner.com/%25TZOXQlZsigfkBWfepmMVvm4jsvgyaXcXXD3GA8Wtmi0%3D.sha256/issues", | |
7 … | + "main": "index.js", | |
8 … | + "scripts": { | |
9 … | + "test": "node test" | |
10 … | + }, | |
11 … | + "dependencies": { | |
12 … | + "multicb": "^1.2.1" | |
13 … | + }, | |
14 … | + "devDependencies": { | |
15 … | + "tape": "^4.5.1", | |
16 … | + "pull-stream": "^3.2.0" | |
17 … | + }, | |
18 … | + "author": "Charles Lehner (http://celehner.com/)", | |
19 … | + "license": "Fair" | |
20 … | +} |
test.js | ||
---|---|---|
@@ -1,0 +1,79 @@ | ||
1 … | +var test = require('tape') | |
2 … | +var pull = require('pull-stream') | |
3 … | +var kvdiff = require('.') | |
4 … | + | |
5 … | +test('kvdiff', function (t) { | |
6 … | + pull( | |
7 … | + kvdiff([ | |
8 … | + pull.values([ | |
9 … | + {key: 'a', value: 1}, | |
10 … | + {key: 'b', value: 2}, | |
11 … | + {key: 'c', value: 3}, | |
12 … | + ]), | |
13 … | + pull.values([ | |
14 … | + {key: 'a', value: 1}, | |
15 … | + {key: 'b', value: 2}, | |
16 … | + {key: 'c', value: 4}, | |
17 … | + ]), | |
18 … | + pull.values([ | |
19 … | + {key: 'a', value: 1}, | |
20 … | + {key: 'b', value: 2}, | |
21 … | + {key: 'd', value: 3}, | |
22 … | + ]) | |
23 … | + ], | |
24 … | + 'key' | |
25 … | + ), | |
26 … | + pull.collect(function (err, diff) { | |
27 … | + t.error(err, 'collect') | |
28 … | + t.deepEquals(diff, [ | |
29 … | + { | |
30 … | + diff: { | |
31 … | + key: [ 'c', , ], | |
32 … | + value: [ 3, 4, ] | |
33 … | + }, | |
34 … | + key: 'c', | |
35 … | + values: [ { key: 'c', value: 3 }, { key: 'c', value: 4 }, ] }, | |
36 … | + { | |
37 … | + diff: { | |
38 … | + key: [ , , 'd' ], | |
39 … | + value: [ , , 3 ] | |
40 … | + }, | |
41 … | + key: 'd', | |
42 … | + values: [ , , { key: 'd', value: 3 } ] } | |
43 … | + | |
44 … | + ], 'values') | |
45 … | + t.end() | |
46 … | + })) | |
47 … | +}) | |
48 … | + | |
49 … | +test('kvdiff 2', function (t) { | |
50 … | + pull( | |
51 … | + kvdiff([ | |
52 … | + pull.values([ | |
53 … | + {key: 'a', value: 1}, | |
54 … | + {key: 'b', value: 2}, | |
55 … | + {key: 'c', value: 3}, | |
56 … | + ]), | |
57 … | + pull.values([ | |
58 … | + {key: 'a', value: 1}, | |
59 … | + {key: 'b', value: 3}, | |
60 … | + {key: 'd', value: 3}, | |
61 … | + ]) | |
62 … | + ], 'key'), | |
63 … | + pull.collect(function (err, diff) { | |
64 … | + t.error(err, 'collect') | |
65 … | + t.deepEquals(diff, [ | |
66 … | + { key: 'b', | |
67 … | + values: [ { key: 'b', value: 2 }, { key: 'b', value: 3 } ], | |
68 … | + diff: { value: [ 2, 3 ] } }, | |
69 … | + { key: 'c', | |
70 … | + values: [ { key: 'c', value: 3 }, ], | |
71 … | + diff: { key: [ 'c', ], value: [ 3, ] } }, | |
72 … | + { key: 'd', | |
73 … | + values: [ , { key: 'd', value: 3 } ], | |
74 … | + diff: { key: [ , 'd' ], value: [ , 3 ] } } | |
75 … | + ]) | |
76 … | + t.end() | |
77 … | + }) | |
78 … | + ) | |
79 … | +}) |
Built with git-ssb-web