Skip to content

Commit 1902625

Browse files
committed
init merge feature
1 parent 0cfc831 commit 1902625

File tree

3 files changed

+164
-32
lines changed

3 files changed

+164
-32
lines changed

README.md

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ const users = await allUsers()
5858

5959
console.log(users)
6060
// {
61-
// "allUsers": [{ "id": 1, "name": "John Doe" }]
61+
// "allUsers": [{ "id": 1, "name": "John Doe" }]
6262
// }
6363
```
6464

@@ -553,6 +553,29 @@ fragment username_admin on AdminUser {
553553
}
554554
```
555555

556+
## Debugging
557+
558+
You can pass `debug: true` to options parameter to get a console output looks like following:
559+
560+
```
561+
[graphql]: POST http://localhost:3000/graphql
562+
QUERY: query ($email: String!, $password: String!) {
563+
auth(email: $email, password: $password) {
564+
.. login_auth
565+
}
566+
}
567+
568+
fragment info on User { hasPin }
569+
fragment login_auth on User { token, ...info }
570+
571+
VARIABLES: {
572+
"email": "[email protected]",
573+
"password": "12345678"
574+
}
575+
576+
sending as form url-data
577+
```
578+
556579
## Advanced
557580
### Using with Vue.js
558581

example/index.html

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,33 +2,46 @@
22
<head>
33
<script src="../graphql.js"></script>
44
<script>
5-
var graph = graphql("http://localhost:3000/graphql", {
5+
var graph = graphql("https://8f0a24.pod-1.api-dev.simprapos.com/admin", {
66
alwaysAutodeclare: true,
7+
asJSON: true,
8+
debug: true,
79
headers: {
8-
"User-Token": "E4iXrF78TF7V6mYbwEwI"
10+
'Auth-Token': 'VXNlcjpmYTc4MDBkNzcyYzUwNGNhN2E4NGFkYzM4N2ZkMzE5Mw=='
911
},
1012
fragments: {
11-
info: "on User {hasPin}",
12-
login: {
13-
auth: "on User {token, ...info}"
14-
}
13+
tax: "on Tax { id, name }",
14+
reason: "on Reason { id, name }"
1515
}
1616
})
1717

18-
var login = graph.query(`
19-
auth(email: $email, password: $password) {
20-
... login.auth
21-
}`)
18+
var allTaxes = graph.query(`
19+
taxes(with_inactive: true) {
20+
... tax
21+
}
22+
`)
23+
24+
var allReasons = graph.query(`
25+
reasons(with_inactive: true, kind: [returned, cancelled]) {
26+
... reason
27+
}
28+
`)
29+
30+
allTaxes.merge('fetchAll').then(function (response) {
31+
console.log('Taxes', response)
32+
})
2233

23-
login({
24-
25-
password: "12345678",
26-
}).then(function (response) {
27-
console.log(response)
34+
allReasons.merge('fetchAll').then(function (response) {
35+
console.log('Reasons', response)
2836
})
37+
38+
setTimeout(function () {
39+
graph.commit('fetchAll')
40+
}, 1000)
41+
2942
</script>
3043
</head>
3144
<body>
32-
45+
3346
</body>
3447
</html>

graphql.js

Lines changed: 111 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
})
3232
}
3333

34-
function __request(method, url, headers, data, asJson, onRequestError, callback) {
34+
function __request(debug, method, url, headers, data, asJson, onRequestError, callback) {
3535
if (!url) {
3636
return;
3737
}
@@ -40,6 +40,15 @@
4040
} else {
4141
var body = "query=" + encodeURIComponent(data.query) + "&variables=" + encodeURIComponent(JSON.stringify(data.variables))
4242
}
43+
if (debug) {
44+
console.groupCollapsed('[graphql]: '
45+
+ method.toUpperCase() + ' ' + url + ': '
46+
+ data.query.split(/\n/)[0].substr(0, 50) + '... with '
47+
+ JSON.stringify(data.variables).substr(0, 50) + '...')
48+
console.log('QUERY: %c%s', 'font-weight: bold', data.query)
49+
console.log('VARIABLES: %c%s\n\nsending as ' + (asJson ? 'json' : 'form url-data'), 'font-weight: bold', JSON.stringify(data.variables, null, 2), data.variables)
50+
console.groupEnd()
51+
}
4352
if (typeof XMLHttpRequest != 'undefined') {
4453
var xhr = new XMLHttpRequest
4554
xhr.open(method, url, true)
@@ -114,15 +123,16 @@
114123
this.url = url
115124
this.options = options || {}
116125
this._fragments = this.buildFragments(options.fragments)
117-
this._sender = this.createSenderFunction()
126+
this._sender = this.createSenderFunction(options.debug)
118127
this.createHelpers(this._sender)
128+
this._transaction = {}
119129
}
120130

121131
// "fragment auth.login" will be "fragment auth_login"
122132
FRAGMENT_SEPERATOR = "_"
123133

124134
// The autodeclare keyword.
125-
GraphQLClient.AUTODECLARE_PATTERN = /\(@autodeclare\)|\(@autotype\)/
135+
GraphQLClient.AUTODECLARE_PATTERN = /\(@autodeclare\)|\(@autotype\)/g
126136

127137
GraphQLClient.FRAGMENT_PATTERN = /\.\.\.\s*([A-Za-z0-9\.\_]+)/g
128138

@@ -265,9 +275,9 @@
265275
return this.autoDeclare(this.processQuery(query, this._fragments), variables)
266276
}
267277

268-
GraphQLClient.prototype.createSenderFunction = function () {
278+
GraphQLClient.prototype.createSenderFunction = function (debug) {
269279
var that = this
270-
return function (query) {
280+
return function (query, originalQuery, type) {
271281
if (__isTagCall(query)) {
272282
return that.run(that.ql.apply(that, arguments))
273283
}
@@ -278,7 +288,7 @@
278288
headers = __extend((that.options.headers||{}), (requestOptions.headers||{}))
279289

280290
return new Promise(function (resolve, reject) {
281-
__request(that.options.method || "post", that.getUrl(), headers, {
291+
__request(debug, that.options.method || "post", that.getUrl(), headers, {
282292
query: fragmentedQuery,
283293
variables: that.cleanAutoDeclareAnnotations(variables)
284294
}, !!that.options.asJSON, that.options.onRequestError, function (response, status) {
@@ -296,13 +306,78 @@
296306
})
297307
})
298308
}
299-
if (arguments.length > 1) {
300-
return caller.apply(null, Array.prototype.slice.call(arguments, 1))
309+
310+
caller.merge = function (mergeName, variables) {
311+
that._transaction[mergeName] = that._transaction[mergeName] || {
312+
query: [],
313+
mutation: []
314+
}
315+
return new Promise(function (resolve) {
316+
that._transaction[mergeName][type].push({
317+
type: type,
318+
query: originalQuery,
319+
variables: variables,
320+
resolver: resolve
321+
})
322+
})
323+
}
324+
if (arguments.length > 3) {
325+
return caller.apply(null, Array.prototype.slice.call(arguments, 3))
301326
}
302327
return caller
303328
}
304329
}
305330

331+
GraphQLClient.prototype.commit = function (mergeName) {
332+
var that = this
333+
var resolveMap = {}
334+
var mergedVariables = {}
335+
var mergedQueries = {}
336+
Object.keys(this._transaction[mergeName]).forEach(function (method) {
337+
if (that._transaction[mergeName][method].length === 0) return
338+
var subQuery = that._transaction[mergeName][method].map(function (merge) {
339+
var reqId = 'merge' + Math.random().toString().split('.')[1].substr(0, 4)
340+
resolveMap[reqId] = merge.resolver
341+
var query = merge.query.replace(/\$([^\.\,\s\)]*)/g, function (_, m) {
342+
var matchingKey = Object.keys(merge.variables).filter(function (key) {
343+
return key === m || key.match(new RegExp('^' + m + '!'))
344+
})[0]
345+
var variable = reqId + '__' + matchingKey
346+
mergedVariables[method] = mergedVariables[method] || {}
347+
mergedVariables[method][variable] = merge.variables[matchingKey]
348+
return '$' + variable.split('!')[0]
349+
})
350+
return reqId + '_' + query.trim().match(/^[^\(]+/)[0] + ': ' + query
351+
}).join('\n')
352+
353+
mergedQueries[method] = mergedQueries[method] || []
354+
mergedQueries[method].push(method + " (@autodeclare) {\n" + subQuery + "\n }")
355+
})
356+
357+
Promise.all(Object.keys(mergedQueries).map(function (method) {
358+
var query = mergedQueries[method].join('\n')
359+
var variables = mergedVariables[method]
360+
return that._sender(query, query, null, variables)
361+
})).then(function (responses) {
362+
responses.forEach(function (response) {
363+
Object.keys(response).forEach(function (mergeKey) {
364+
var parsedKey = mergeKey.match(/^(merge\d+)\_(.*)/)
365+
var newResponse = {}
366+
newResponse[parsedKey[2]] = response[mergeKey]
367+
resolveMap[parsedKey[1]](newResponse)
368+
})
369+
})
370+
}).finally(function () {
371+
that._transaction[mergeName] = { query: [], mutation: [] }
372+
})
373+
// console.log(mergedQueries)
374+
// console.log(mergedVariables)
375+
// console.log(resolveMap)
376+
// return this._sender(mergedQuery, mergedQuery, null, mergedVariables).then(function (response) {
377+
// console.log(response)
378+
// })
379+
}
380+
306381
GraphQLClient.prototype.createHelpers = function (sender) {
307382
var that = this
308383
function helper(query) {
@@ -314,12 +389,11 @@
314389
that.__suffix = ""
315390
return result
316391
}
317-
var caller = sender(this.prefix + " " + query + " " + this.suffix)
392+
var caller = sender(this.prefix + " " + query + " " + this.suffix, query.trim(), this.type)
318393
if (arguments.length > 1 && arguments[1] != null) {
319394
return caller.apply(null, Array.prototype.slice.call(arguments, 1))
320-
} else {
321-
return caller
322395
}
396+
return caller
323397
}
324398

325399
var helpers = [
@@ -330,17 +404,16 @@
330404
helpers.forEach(function (m) {
331405
that[m.method] = function (query, variables, options) {
332406
if (that.options.alwaysAutodeclare === true || (options && options.declare === true)) {
333-
return helper.call({prefix: m.type + " (@autodeclare) {", suffix: "}"}, query, variables)
334-
} else {
335-
return helper.call({prefix: m.type, suffix: ""}, query, variables)
407+
return helper.call({type: m.type, prefix: m.type + " (@autodeclare) {", suffix: "}"}, query, variables)
336408
}
409+
return helper.call({type: m.type, prefix: m.type, suffix: ""}, query, variables)
337410
}
338411
that[m.method].run = function (query, options) {
339412
return that[m.method](query, options)({})
340413
}
341414
})
342415
this.run = function (query) {
343-
return sender(query, {})
416+
return sender(query, originalQuery, m.type, {})
344417
}
345418
}
346419

@@ -386,6 +459,29 @@
386459
return query
387460
}
388461

462+
// GraphQLClient.prototype.startTransaction = function () {
463+
// if (this.transaction) {
464+
// console.groupEnd()
465+
// console.error('[graphql]: transaction is already started')
466+
// return
467+
// }
468+
// if (this.options.debug) {
469+
// console.group('%c[graphql]: transaction started, following requests will be collected until end', 'font-weight: bold')
470+
// }
471+
// this.transaction = []
472+
// }
473+
474+
// GraphQLClient.prototype.endTransaction = function () {
475+
// if (!this.transaction) {
476+
// console.error('[graphql]: cannot end a transaction which is not started')
477+
// return
478+
// }
479+
// if (this.options.debug) {
480+
// console.groupEnd()
481+
// }
482+
// this.transaction = null
483+
// }
484+
389485
;(function (root, factory) {
390486
if (typeof define === 'function' && define.amd) {
391487
define(function () {

0 commit comments

Comments
 (0)