forked from brysgo/graphql-gun
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
121 lines (117 loc) · 3.31 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
const Gun = require("gun/gun");
const graphql = require("graphql-anywhere").default;
const {
thunkish,
deferrableOrImmediate,
arrayOrDeferrable
} = require("./async");
const tryGet = require("try-get");
module.exports = function graphqlGun(query, gun) {
gun = gun || Gun();
let resultValue = {};
let subscriptions = {};
const resolver = (fieldName, container, args, context, info) => {
let key = info.resultKey;
const {
subscribe: parentSubscribed,
index: indexInList,
ref: parentRef,
path,
chain
} = container;
let ref = parentRef;
let subscribe =
(parentSubscribed || "live" in tryGet(info, "directives", {})) &&
!("unlive" in tryGet(info, "directives", {}));
if (info.isLeaf) {
if (key === "_chain") {
ref[key] = chain;
return chain;
} else {
return thunkish(resolve => {
const updater = val => {
if (!!val && val[key]) {
ref[key] = val[key];
resolve(val[key]);
} else {
ref[key] = val;
resolve(val);
}
};
const stringPath = [...path, key].join(".");
if (subscribe && subscriptions[stringPath] === undefined) {
subscriptions[stringPath] = chain.get(key).on(updater, true);
} else {
chain.get(key).once(updater);
}
});
}
} else if (args && args.type === "Set") {
ref[key] = ref[key] || [];
ref = ref[key];
const keyValueSet = {};
const resultSet = {};
const t = thunkish(function(rerunChild) {
const updater = function(data, _key, at) {
var gunRef = this; // also `at.gun`
Gun.obj.map(data, function(val, field) {
// or a for in
if (field === "_") return;
keyValueSet[field] = keyValueSet[field] || {};
resultSet[field] = {
chain: gunRef.get(field),
subscribe,
ref: keyValueSet[field],
path: [...path, key, field]
};
});
ref.splice(0, ref.length, ...Object.values(keyValueSet));
rerunChild(Object.values(resultSet));
};
chain.get(key).on(updater, true);
});
return t;
} else {
ref[key] = ref[key] || {};
return {
chain: chain.get(key),
subscribe,
path: [...path, key],
ref: ref[key]
};
}
};
const graphqlOut = graphql(
resolver,
query,
{ path: [], ref: resultValue, chain: gun },
null,
null,
{
deferrableOrImmediate,
arrayOrDeferrable
}
);
const thunk = thunkish(function(triggerUpdate) {
triggerUpdate(resultValue);
if (graphqlOut.isThunk) {
graphqlOut(function(actualRes) {
triggerUpdate(resultValue); // TODO: Figure out how to use actualRes instead of tracking resultValue
});
}
});
const result = thunk.toPromiseFactory()();
result.next = thunk.toPromiseFactory();
result[Symbol.asyncIterator] = function() {
const factory = thunk.toPromiseFactory();
return {
next: () =>
factory().then(value => ({
value,
done: false
}))
};
};
result[Symbol.iterator] = result[Symbol.asyncIterator]; // TODO: Depricate this usage
return result;
};