-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdeep-graphql.html
More file actions
147 lines (142 loc) · 4.63 KB
/
deep-graphql.html
File metadata and controls
147 lines (142 loc) · 4.63 KB
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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
<link rel="import" href="../polymer/polymer.html">
<link rel="import" href="../iron-ajax/iron-ajax.html">
<!-- TODO: Different method types needed? Not just post, get, etc... -->
<dom-module id="deep-graphql">
<template>
<style>
:host {
display: block;
}
</style>
<!-- TODO: How to make auto work with data input? It's triggering infinite loop. -->
<!-- auto="[[auto]]" -->
<iron-ajax
id="ajax"
url="[[url]]"
headers="[[headers]]"
handle-as="json"
params="[[__query(data)]]"
on-response="__formatData"
debounce-duration="[[debounceDuration]]"
reject-with-request
with-auth
bubbles
></iron-ajax>
</template>
<script>
/**
* `deep-graphql`
* Polymer integration with GraphQL
*
* @customElement
* @polymer
* @demo demo/index.html
*/
Polymer({
is: 'deep-graphql',
properties: {
/*
* Graphql data interface corresponding to { data: {...} }. This object
* should be bound to a JSON object that needs to be hydrated. The
* query will be extracted based on the JSON structure of the object.
*/
data: {
type: Object,
value() {
return {};
},
notify: true
},
/* Graphql service url */
url: {
type: String,
value: '/graphql'
},
/* Request headers. */
headers: Object,
/* Pass-through to iron-ajax. Automatically triggers requests. */
auto: {
type: Boolean,
value: false
}
},
/**
* Run query against the GraphQL service.
* @param {Object} [json = this.data] - JSON structure one would like receive. The query
* is computed based on the object structure to hydrate.
* @return {Promise} - Resolves upon completion of the query with the data
* object.
*/
query(json = this.data) {
this.$.ajax.params = this.__query(json || {});
return this.$.ajax.generateRequest().completes.then(() => {
// Success is handled by event handler attached to iron ajax
}, (err) => {
console.warn(`${this.localName}: GraphQL request failed for query: '${query}'.
Data will default to what was passed.`);
this.data = json || {};
}).then(() => {
return this.data;
});
},
mutate(obj) {
// TODO
},
/**
* Format the user-defined query such that it conforms to GraphQL query
* syntax.
* @private
* @param {Object} data - The object structure to hydrate.
* @return {Object} - Formatted query or an empty object.
*/
__query(data) {
if (!Object.keys(data || {}).length) return {};
return {query: this.__buildQuery(data)};
},
/**
* Recursively build the query from object to construct query.
* @private
* @param {*} subject - Primitive type instance used to determine whether
* it's needed in the query.
* @return {String} - The relevant query result.
*/
__buildQuery(subject) {
// TODO Attempt DP implementation to gain experience with that. Execution speed
// wont increase because of recursive subproblems not overlapping but would still
// be awesome.
if (typeof subject !== 'object') {
return '';
} else {
let query = '';
// An array is also considered an object using typeof
if (Array.isArray(subject)) {
if (subject.length) {
// Grab fields from an arbitrary entry
query = query.concat(this.__buildQuery(subject[0]));
}
} else {
query = query.concat('{ ');
for (const field in subject) {
if (subject.hasOwnProperty(field)) {
query =
query.concat(` ${field} `).concat(this.__buildQuery(subject[field]));
}
}
query = query.concat(' }');
}
return query;
}
},
/**
* Format the data for exposure through the public interface.
* @private
* @param {Event} e - Event triggered after ajax request completes.
* @return {Object} - Formatted data object or {}.
*/
__formatData(e) {
if (!e || !e.detail || !e.detail.response) return {};
this.data = e.detail.response.data || {};
}
});
</script>
</dom-module>