| 1318 |
alexandre_ |
1 |
/*
|
|
|
2 |
Copyright (c) 2004-2006, The Dojo Foundation
|
|
|
3 |
All Rights Reserved.
|
|
|
4 |
|
|
|
5 |
Licensed under the Academic Free License version 2.1 or above OR the
|
|
|
6 |
modified BSD license. For more information on Dojo licensing, see:
|
|
|
7 |
|
|
|
8 |
http://dojotoolkit.org/community/licensing.shtml
|
|
|
9 |
*/
|
|
|
10 |
|
| 1422 |
alexandre_ |
11 |
|
|
|
12 |
|
| 1318 |
alexandre_ |
13 |
dojo.provide("dojo.data.core.RemoteStore");
|
|
|
14 |
dojo.require("dojo.data.core.Read");
|
|
|
15 |
dojo.require("dojo.data.core.Write");
|
|
|
16 |
dojo.require("dojo.data.core.Result");
|
|
|
17 |
dojo.require("dojo.experimental");
|
|
|
18 |
dojo.require("dojo.Deferred");
|
|
|
19 |
dojo.require("dojo.lang.declare");
|
|
|
20 |
dojo.require("dojo.json");
|
|
|
21 |
dojo.require("dojo.io.*");
|
|
|
22 |
dojo.experimental("dojo.data.core.RemoteStore");
|
|
|
23 |
dojo.lang.declare("dojo.data.core.RemoteStore", [dojo.data.core.Read, dojo.data.core.Write], {_datatypeMap:{}, _jsonRegistry:dojo.json.jsonRegistry, initializer:function (kwArgs) {
|
|
|
24 |
if (!kwArgs) {
|
|
|
25 |
kwArgs = {};
|
|
|
26 |
}
|
|
|
27 |
this._serverQueryUrl = kwArgs.queryUrl || "";
|
|
|
28 |
this._serverSaveUrl = kwArgs.saveUrl || "";
|
|
|
29 |
this._deleted = {};
|
|
|
30 |
this._changed = {};
|
|
|
31 |
this._added = {};
|
|
|
32 |
this._results = {};
|
|
|
33 |
this._data = {};
|
|
|
34 |
this._numItems = 0;
|
|
|
35 |
}, _setupQueryRequest:function (result, requestKw) {
|
|
|
36 |
result.query = result.query || "";
|
|
|
37 |
requestKw.url = this._serverQueryUrl + encodeURIComponent(result.query);
|
|
|
38 |
requestKw.method = "get";
|
|
|
39 |
requestKw.mimetype = "text/json";
|
|
|
40 |
}, _resultToQueryMetadata:function (serverResponseData) {
|
|
|
41 |
return serverResponseData;
|
|
|
42 |
}, _resultToQueryData:function (serverResponseData) {
|
|
|
43 |
return serverResponseData.data;
|
|
|
44 |
}, _remoteToLocalValues:function (attributes) {
|
|
|
45 |
for (var key in attributes) {
|
|
|
46 |
var values = attributes[key];
|
|
|
47 |
for (var i = 0; i < values.length; i++) {
|
|
|
48 |
var value = values[i];
|
|
|
49 |
var type = value.datatype || value.type;
|
|
|
50 |
if (type) {
|
|
|
51 |
var localValue = value.value;
|
|
|
52 |
if (this._datatypeMap[type]) {
|
|
|
53 |
localValue = this._datatypeMap[type](value);
|
|
|
54 |
}
|
|
|
55 |
values[i] = localValue;
|
|
|
56 |
}
|
|
|
57 |
}
|
|
|
58 |
}
|
|
|
59 |
return attributes;
|
|
|
60 |
}, _queryToQueryKey:function (query) {
|
|
|
61 |
if (typeof query == "string") {
|
|
|
62 |
return query;
|
|
|
63 |
} else {
|
|
|
64 |
return dojo.json.serialize(query);
|
|
|
65 |
}
|
|
|
66 |
}, _assertIsItem:function (item) {
|
|
|
67 |
if (!this.isItem(item)) {
|
|
|
68 |
throw new Error("dojo.data.RemoteStore: a function was passed an item argument that was not an item");
|
|
|
69 |
}
|
|
|
70 |
}, get:function (item, attribute, defaultValue) {
|
|
|
71 |
var valueArray = this.getValues(item, attribute);
|
|
|
72 |
if (valueArray.length == 0) {
|
|
|
73 |
return defaultValue;
|
|
|
74 |
}
|
|
|
75 |
return valueArray[0];
|
|
|
76 |
}, getValues:function (item, attribute) {
|
|
|
77 |
var itemIdentity = this.getIdentity(item);
|
|
|
78 |
this._assertIsItem(itemIdentity);
|
|
|
79 |
var changes = this._changed[itemIdentity];
|
|
|
80 |
if (changes) {
|
|
|
81 |
var newvalues = changes[attribute];
|
|
|
82 |
if (newvalues !== undefined) {
|
|
|
83 |
return newvalues;
|
|
|
84 |
} else {
|
|
|
85 |
return [];
|
|
|
86 |
}
|
|
|
87 |
}
|
|
|
88 |
return this._data[itemIdentity][0][attribute];
|
|
|
89 |
}, getAttributes:function (item) {
|
|
|
90 |
var itemIdentity = this.getIdentity(item);
|
|
|
91 |
if (!itemIdentity) {
|
|
|
92 |
return undefined;
|
|
|
93 |
}
|
|
|
94 |
var atts = [];
|
|
|
95 |
var attrDict = this._data[itemIdentity][0];
|
|
|
96 |
for (var att in attrDict) {
|
|
|
97 |
atts.push(att);
|
|
|
98 |
}
|
|
|
99 |
return atts;
|
|
|
100 |
}, hasAttribute:function (item, attribute) {
|
|
|
101 |
var valueArray = this.getValues(item, attribute);
|
|
|
102 |
return valueArray.length ? true : false;
|
|
|
103 |
}, containsValue:function (item, attribute, value) {
|
|
|
104 |
var valueArray = this.getValues(item, attribute);
|
|
|
105 |
for (var i = 0; i < valueArray.length; i++) {
|
|
|
106 |
if (valueArray[i] == value) {
|
|
|
107 |
return true;
|
|
|
108 |
}
|
|
|
109 |
}
|
|
|
110 |
return false;
|
|
|
111 |
}, isItem:function (something) {
|
|
|
112 |
if (!something) {
|
|
|
113 |
return false;
|
|
|
114 |
}
|
|
|
115 |
var itemIdentity = something;
|
|
|
116 |
if (this._deleted[itemIdentity]) {
|
|
|
117 |
return false;
|
|
|
118 |
}
|
|
|
119 |
if (this._data[itemIdentity]) {
|
|
|
120 |
return true;
|
|
|
121 |
}
|
|
|
122 |
if (this._added[itemIdentity]) {
|
|
|
123 |
return true;
|
|
|
124 |
}
|
|
|
125 |
return false;
|
|
|
126 |
}, find:function (keywordArgs) {
|
|
|
127 |
var result = null;
|
|
|
128 |
if (keywordArgs instanceof dojo.data.core.Result) {
|
|
|
129 |
result = keywordArgs;
|
|
|
130 |
result.store = this;
|
|
|
131 |
} else {
|
|
|
132 |
result = new dojo.data.core.Result(keywordArgs, this);
|
|
|
133 |
}
|
|
|
134 |
var query = result.query;
|
|
|
135 |
var self = this;
|
|
|
136 |
var bindfunc = function (type, data, evt) {
|
|
|
137 |
var scope = result.scope || dj_global;
|
|
|
138 |
if (type == "load") {
|
|
|
139 |
result.resultMetadata = self._resultToQueryMetadata(data);
|
|
|
140 |
var dataDict = self._resultToQueryData(data);
|
|
|
141 |
if (result.onbegin) {
|
|
|
142 |
result.onbegin.call(scope, result);
|
|
|
143 |
}
|
|
|
144 |
var count = 0;
|
|
|
145 |
var resultData = [];
|
|
|
146 |
var newItemCount = 0;
|
|
|
147 |
for (var key in dataDict) {
|
|
|
148 |
if (result._aborted) {
|
|
|
149 |
break;
|
|
|
150 |
}
|
|
|
151 |
if (!self._deleted[key]) {
|
|
|
152 |
var values = dataDict[key];
|
|
|
153 |
var attributeDict = self._remoteToLocalValues(values);
|
|
|
154 |
var existingValue = self._data[key];
|
|
|
155 |
var refCount = 1;
|
|
|
156 |
if (existingValue) {
|
|
|
157 |
refCount = ++existingValue[1];
|
|
|
158 |
} else {
|
|
|
159 |
newItemCount++;
|
|
|
160 |
}
|
|
|
161 |
self._data[key] = [attributeDict, refCount];
|
|
|
162 |
resultData.push(key);
|
|
|
163 |
count++;
|
|
|
164 |
if (result.onnext) {
|
|
|
165 |
result.onnext.call(scope, key, result);
|
|
|
166 |
}
|
|
|
167 |
}
|
|
|
168 |
}
|
|
|
169 |
self._results[self._queryToQueryKey(query)] = resultData;
|
|
|
170 |
self._numItems += newItemCount;
|
|
|
171 |
result.length = count;
|
|
|
172 |
if (result.saveResult) {
|
|
|
173 |
result.items = resultData;
|
|
|
174 |
}
|
|
|
175 |
if (!result._aborted && result.oncompleted) {
|
|
|
176 |
result.oncompleted.call(scope, result);
|
|
|
177 |
}
|
|
|
178 |
} else {
|
|
|
179 |
if (type == "error" || type == "timeout") {
|
|
|
180 |
dojo.debug("find error: " + dojo.json.serialize(data));
|
|
|
181 |
if (result.onerror) {
|
|
|
182 |
result.onerror.call(scope, data);
|
|
|
183 |
}
|
|
|
184 |
}
|
|
|
185 |
}
|
|
|
186 |
};
|
|
|
187 |
var bindKw = keywordArgs.bindArgs || {};
|
|
|
188 |
bindKw.sync = result.sync;
|
|
|
189 |
bindKw.handle = bindfunc;
|
|
|
190 |
this._setupQueryRequest(result, bindKw);
|
|
|
191 |
var request = dojo.io.bind(bindKw);
|
|
|
192 |
result._abortFunc = request.abort;
|
|
|
193 |
return result;
|
|
|
194 |
}, getIdentity:function (item) {
|
|
|
195 |
if (!this.isItem(item)) {
|
|
|
196 |
return null;
|
|
|
197 |
}
|
|
|
198 |
return (item.id ? item.id : item);
|
|
|
199 |
}, newItem:function (attributes, keywordArgs) {
|
|
|
200 |
var itemIdentity = keywordArgs["identity"];
|
|
|
201 |
if (this._deleted[itemIdentity]) {
|
|
|
202 |
delete this._deleted[itemIdentity];
|
|
|
203 |
} else {
|
|
|
204 |
this._added[itemIdentity] = 1;
|
|
|
205 |
}
|
|
|
206 |
if (attributes) {
|
|
|
207 |
for (var attribute in attributes) {
|
|
|
208 |
var valueOrArrayOfValues = attributes[attribute];
|
|
|
209 |
if (dojo.lang.isArray(valueOrArrayOfValues)) {
|
|
|
210 |
this.setValues(itemIdentity, attribute, valueOrArrayOfValues);
|
|
|
211 |
} else {
|
|
|
212 |
this.set(itemIdentity, attribute, valueOrArrayOfValues);
|
|
|
213 |
}
|
|
|
214 |
}
|
|
|
215 |
}
|
|
|
216 |
return {id:itemIdentity};
|
|
|
217 |
}, deleteItem:function (item) {
|
|
|
218 |
var identity = this.getIdentity(item);
|
|
|
219 |
if (!identity) {
|
|
|
220 |
return false;
|
|
|
221 |
}
|
|
|
222 |
if (this._added[identity]) {
|
|
|
223 |
delete this._added[identity];
|
|
|
224 |
} else {
|
|
|
225 |
this._deleted[identity] = 1;
|
|
|
226 |
}
|
|
|
227 |
if (this._changed[identity]) {
|
|
|
228 |
delete this._changed[identity];
|
|
|
229 |
}
|
|
|
230 |
return true;
|
|
|
231 |
}, setValues:function (item, attribute, values) {
|
|
|
232 |
var identity = this.getIdentity(item);
|
|
|
233 |
if (!identity) {
|
|
|
234 |
return undefined;
|
|
|
235 |
}
|
|
|
236 |
var changes = this._changed[identity];
|
|
|
237 |
if (!changes) {
|
|
|
238 |
changes = {};
|
|
|
239 |
this._changed[identity] = changes;
|
|
|
240 |
}
|
|
|
241 |
changes[attribute] = values;
|
|
|
242 |
return true;
|
|
|
243 |
}, set:function (item, attribute, value) {
|
|
|
244 |
return this.setValues(item, attribute, [value]);
|
|
|
245 |
}, unsetAttribute:function (item, attribute) {
|
|
|
246 |
return this.setValues(item, attribute, []);
|
|
|
247 |
}, _initChanges:function () {
|
|
|
248 |
this._deleted = {};
|
|
|
249 |
this._changed = {};
|
|
|
250 |
this._added = {};
|
|
|
251 |
}, _setupSaveRequest:function (saveKeywordArgs, requestKw) {
|
|
|
252 |
requestKw.url = this._serverSaveUrl;
|
|
|
253 |
requestKw.method = "post";
|
|
|
254 |
requestKw.mimetype = "text/plain";
|
|
|
255 |
var deleted = [];
|
|
|
256 |
for (var key in this._deleted) {
|
|
|
257 |
deleted.push(key);
|
|
|
258 |
}
|
|
|
259 |
var saveStruct = {"changed":this._changed, "deleted":deleted};
|
|
|
260 |
var oldRegistry = dojo.json.jsonRegistry;
|
|
|
261 |
dojo.json.jsonRegistry = this._jsonRegistry;
|
|
|
262 |
var jsonString = dojo.json.serialize(saveStruct);
|
|
|
263 |
dojo.json.jsonRegistry = oldRegistry;
|
|
|
264 |
requestKw.postContent = jsonString;
|
|
|
265 |
}, save:function (keywordArgs) {
|
|
|
266 |
keywordArgs = keywordArgs || {};
|
|
|
267 |
var result = new dojo.Deferred();
|
|
|
268 |
var self = this;
|
|
|
269 |
var bindfunc = function (type, data, evt) {
|
|
|
270 |
if (type == "load") {
|
|
|
271 |
if (result.fired == 1) {
|
|
|
272 |
return;
|
|
|
273 |
}
|
|
|
274 |
var key = null;
|
|
|
275 |
for (key in self._added) {
|
|
|
276 |
if (!self._data[key]) {
|
|
|
277 |
self._data[key] = [{}, 1];
|
|
|
278 |
}
|
|
|
279 |
}
|
|
|
280 |
for (key in self._changed) {
|
|
|
281 |
var existing = self._data[key];
|
|
|
282 |
var changes = self._changed[key];
|
|
|
283 |
if (existing) {
|
|
|
284 |
existing[0] = changes;
|
|
|
285 |
} else {
|
|
|
286 |
self._data[key] = [changes, 1];
|
|
|
287 |
}
|
|
|
288 |
}
|
|
|
289 |
for (key in self._deleted) {
|
|
|
290 |
if (self._data[key]) {
|
|
|
291 |
delete self._data[key];
|
|
|
292 |
}
|
|
|
293 |
}
|
|
|
294 |
self._initChanges();
|
|
|
295 |
result.callback(true);
|
|
|
296 |
} else {
|
|
|
297 |
if (type == "error" || type == "timeout") {
|
|
|
298 |
result.errback(data);
|
|
|
299 |
}
|
|
|
300 |
}
|
|
|
301 |
};
|
|
|
302 |
var bindKw = {sync:keywordArgs["sync"], handle:bindfunc};
|
|
|
303 |
this._setupSaveRequest(keywordArgs, bindKw);
|
|
|
304 |
var request = dojo.io.bind(bindKw);
|
|
|
305 |
result.canceller = function (deferred) {
|
|
|
306 |
request.abort();
|
|
|
307 |
};
|
|
|
308 |
return result;
|
|
|
309 |
}, revert:function () {
|
|
|
310 |
this._initChanges();
|
|
|
311 |
return true;
|
|
|
312 |
}, isDirty:function (item) {
|
|
|
313 |
if (item) {
|
|
|
314 |
var identity = item.id || item;
|
|
|
315 |
return this._deleted[identity] || this._changed[identity];
|
|
|
316 |
} else {
|
|
|
317 |
var key = null;
|
|
|
318 |
for (key in this._changed) {
|
|
|
319 |
return true;
|
|
|
320 |
}
|
|
|
321 |
for (key in this._deleted) {
|
|
|
322 |
return true;
|
|
|
323 |
}
|
|
|
324 |
for (key in this._added) {
|
|
|
325 |
return true;
|
|
|
326 |
}
|
|
|
327 |
return false;
|
|
|
328 |
}
|
|
|
329 |
}, createReference:function (idstring) {
|
|
|
330 |
return {id:idstring};
|
|
|
331 |
}, getSize:function () {
|
|
|
332 |
return this._numItems;
|
|
|
333 |
}, forgetResults:function (query) {
|
|
|
334 |
var queryKey = this._queryToQueryKey(query);
|
|
|
335 |
var results = this._results[queryKey];
|
|
|
336 |
if (!results) {
|
|
|
337 |
return false;
|
|
|
338 |
}
|
|
|
339 |
var removed = 0;
|
|
|
340 |
for (var i = 0; i < results.length; i++) {
|
|
|
341 |
var key = results[i];
|
|
|
342 |
var existingValue = this._data[key];
|
|
|
343 |
if (existingValue[1] <= 1) {
|
|
|
344 |
delete this._data[key];
|
|
|
345 |
removed++;
|
|
|
346 |
} else {
|
|
|
347 |
existingValue[1] = --existingValue[1];
|
|
|
348 |
}
|
|
|
349 |
}
|
|
|
350 |
delete this._results[queryKey];
|
|
|
351 |
this._numItems -= removed;
|
|
|
352 |
return true;
|
|
|
353 |
}});
|
|
|
354 |
|