Ticket #4597: QueryReadStore.files.patch

File QueryReadStore.files.patch, 34.6 KB (added by wolfram, 5 years ago)

made the comboboxes really work

  • data/QueryReadStore.js

     
     1dojo.provide("dojox.data.QueryReadStore"); 
     2dojo.provide("dojox.data.QueryReadStore.InvalidItemError"); 
     3dojo.provide("dojox.data.QueryReadStore.InvalidAttributeError"); 
     4 
     5dojo.require("dojo.string"); 
     6dojo.require("dojo.data.util.simpleFetch"); 
     7 
     8dojo.declare("dojox.data.QueryReadStore", null, { 
     9        /* 
     10        //      summary: 
     11        //              This class provides a store that is mainly intended to be used 
     12        //              for loading data dynamically from the server, used i.e. for 
     13        //              retreiving chunks of data from huge data stores on the server (by server-side filtering!). 
     14        //              Upon calling the fetch() method of this store the data are requested from 
     15        //              the server if they are not yet loaded for paging (or cached). 
     16        // 
     17        //              For example used for a combobox which works on lots of data. It 
     18        //              can be used to retreive the data partially upon entering the 
     19        //              letters "ac" it returns only items like "action", "acting", etc. 
     20        // 
     21        //      examples: 
     22        //              // The parameter "query" contains the data that are sent to the server. 
     23        //              var store = new dojox.data.QueryReadStore({url:'/search.php'}); 
     24        //              store.fetch({query:{name:'a'}, queryOptions:{ignoreCase:false}}); 
     25        // 
     26        //              // Since "serverQuery" is given, it overrules and those data are 
     27        //              // sent to the server. 
     28        //              var store = new dojox.data.QueryReadStore({url:'/search.php'}); 
     29        //              store.fetch({serverQuery:{name:'a'}, queryOptions:{ignoreCase:false}}); 
     30        // 
     31        //      todo: 
     32        //              - there is a bug in the paging, when i set start:2, count:5 after an initial fetch() and doClientPaging:true 
     33        //                it returns 6 elemetns, though count=5, try it in QueryReadStore.html 
     34        //              - allow configuring if the paging shall takes place on the client or the server 
     35        //              - add optional caching 
     36        //              - when the first query searched for "a" and the next for a subset of 
     37        //                the first, i.e. "ab" then we actually dont need a server request, if 
     38        //                we have client paging, we just need to filter the items we already have 
     39        //                that might also be tooo much logic 
     40        */ 
     41         
     42        url:"", 
     43        requestMethod:"get", 
     44        //useCache:false, 
     45         
     46        // We use the name in the errors, once the name is fixed hardcode it, may be. 
     47        _className:"dojox.data.QueryReadStore", 
     48         
     49        // This will contain the items we have loaded from the server. 
     50        // The contents of this array is optimized to satisfy all read-api requirements 
     51        // and for using lesser storage, so the keys and their content need some explaination: 
     52        //              this._items[0].i - the item itself  
     53        //              this._items[0].r - a reference to the store, so we can identify the item 
     54        //                      securly. We set this reference right after receiving the item from the 
     55        //                      server. 
     56        _items:[], 
     57         
     58        // Store the last query that triggered xhr request to the server. 
     59        // So we can compare if the request changed and if we shall reload  
     60        // (this also depends on other factors, such as is caching used, etc). 
     61        _lastServerQuery:null, 
     62         
     63         
     64        // Store a timestamp of the last server request. Actually I introduced this 
     65        // for testing, so I can check if no unnecessary requests were issued for 
     66        // client-side-paging. But I am sure people will find uses for it. 
     67        lastRequestTimestamp:null, 
     68         
     69        // If this is false, every request is sent to the server. 
     70        // If it's true a second request with the same query will not issue another 
     71        // request, but use the already returned data. This assumes that the server 
     72        // does not do the paging. 
     73        doClientPaging:true, 
     74         
     75        constructor: function(/* Object */ params){ 
     76                this.url = params.url; 
     77                this.requestMethod = typeof params.requestMethod=="undefined" ? this.requestMethod : params.requestMethod; 
     78                this.doClientPaging = typeof params.doClientPaging=="undefined" ? this.doClientPaging : params.doClientPaging; 
     79                //this.useCache = typeof params.useCache=="undefined" ? this.useCache : params.useCache; 
     80        }, 
     81         
     82        getValue: function(     /* item */ item, /* attribute-name-string */ attribute, /* value? */ defaultValue){ 
     83                this._assertIsItem(item); 
     84                if (!this.hasAttribute(item, attribute)) { 
     85                        // read api says: return defaultValue "only if *item* does not have a value for *attribute*."  
     86                        // Is this the case here? The attribute doesn't exist, but a defaultValue, sounds reasonable. 
     87                        if (defaultValue) { 
     88                                return defaultValue; 
     89                        } 
     90                        //throw new Error(this._className+".getValue(): an invalid attribute for a given item was passed to the method 'getValue()'."); 
     91                        throw new dojox.data.QueryReadStore.InvalidAttributeError(this._className+".getValue(): Item does not have the attribute '"+attribute+"'."); 
     92                } 
     93                return item.i[attribute]; 
     94        }, 
     95         
     96        getValues: function(/* item */ item, /* attribute-name-string */ attribute){ 
     97                var ret = []; 
     98                if (this.hasAttribute(item, attribute)) { 
     99                        ret[0] = item.i[attribute]; 
     100                } 
     101                return ret; 
     102        }, 
     103         
     104        getAttributes: function(/* item */ item){ 
     105                this._assertIsItem(item); 
     106                var ret = []; 
     107                for (var i in item.i) { 
     108                        ret.push(i); 
     109                } 
     110                return ret; 
     111        }, 
     112 
     113        hasAttribute: function(/* item */ item, /* attribute-name-string */ attribute) { 
     114                //      summary:  
     115                //              See dojo.data.api.Read.hasAttribute() 
     116                return this.isItem(item) && typeof item.i[attribute]!="undefined"; 
     117        }, 
     118         
     119        containsValue: function(/* item */ item, /* attribute-name-string */ attribute, /* anything */ value){ 
     120                var values = this.getValues(item, attribute); 
     121                var len = values.length; 
     122                for (var i=0; i<len; i++) { 
     123                        if (values[i]==value) { 
     124                                return true; 
     125                        } 
     126                } 
     127                return false; 
     128        }, 
     129         
     130        isItem: function(/* anything */ something){ 
     131                // Some basic tests, that are quick and easy to do here. 
     132                // >>> var store = new dojox.data.QueryReadStore({}); 
     133                // >>> store.isItem(""); 
     134                // false 
     135                // 
     136                // >>> var store = new dojox.data.QueryReadStore({}); 
     137                // >>> store.isItem({}); 
     138                // false 
     139                // 
     140                // >>> var store = new dojox.data.QueryReadStore({}); 
     141                // >>> store.isItem(0); 
     142                // false 
     143                // 
     144                // >>> var store = new dojox.data.QueryReadStore({}); 
     145                // >>> store.isItem({name:"me", label:"me too"}); 
     146                // false 
     147                // 
     148                return typeof something.r!="undefined" && something.r==this; 
     149        }, 
     150         
     151        isItemLoaded: function(/* anything */ something) { 
     152                // Currently we dont have any state that tells if an item is loaded or not 
     153                // if the item exists its also loaded. 
     154                // This might change when we start working with refs inside items ... 
     155                return this.isItem(something); 
     156        }, 
     157 
     158        loadItem: function(/* object */ args){ 
     159                if (this.isItemLoaded(args.item)) { 
     160                        return; 
     161                } 
     162                // Actually we have nothing to do here, or at least I dont know what to do here ... 
     163        }, 
     164 
     165        getFeatures: function(){ 
     166                return { 
     167                        'dojo.data.api.Read': true 
     168                }; 
     169        }, 
     170 
     171        close: function(/*dojo.data.api.Request || keywordArgs || null */ request){ 
     172                // I have no idea if this is really needed ...  
     173        }, 
     174 
     175        getLabel: function(/* item */ item){ 
     176                // Override it to return whatever the label shall be, see Read-API. 
     177                return undefined; 
     178        }, 
     179 
     180        getLabelAttributes: function(/* item */ item){ 
     181                return null; 
     182        }, 
     183         
     184        _fetchItems: function(request, fetchHandler, errorHandler){ 
     185                //      summary: 
     186                //              The request contains the data as defined in the Read-API. 
     187                //              Additionally there is following keyword "serverQuery". 
     188                // 
     189                //      The *serverQuery* parameter, optional. 
     190                //              This parameter contains the data that will be sent to the server. 
     191                //              If this parameter is not given the parameter "query"'s 
     192                //              data are sent to the server. This is done for some reasons: 
     193                //              - to specify explicitly which data are sent to the server, they 
     194                //                might also be a mix of what is contained in "query", "queryOptions" 
     195                //                and the paging parameters "start" and "count" or may be even 
     196                //                completely different things. 
     197                //              - don't modify the request.query data, so the interface using this 
     198                //                store can rely on unmodified data, as the combobox dijit currently 
     199                //                does it, it compares if the query has changed 
     200                //              - request.query is required by the Read-API 
     201                // 
     202                //              I.e. the following examples might be sent via GET: 
     203                //                fetch({query:{name:"abc"}, queryOptions:{ignoreCase:true}}) 
     204                //                the URL will become:   /url.php?name=abc 
     205                // 
     206                //                fetch({serverQuery:{q:"abc", c:true}, query:{name:"abc"}, queryOptions:{ignoreCase:true}}) 
     207                //                the URL will become:   /url.php?q=abc&c=true 
     208                //                // The serverQuery-parameter has overruled the query-parameter 
     209                //                // but the query parameter stays untouched, but is not sent to the server! 
     210                //                // The serverQuery contains more data than the query, so they might differ! 
     211                // 
     212 
     213                var serverQuery = typeof request["serverQuery"]=="undefined" ? request.query : request.serverQuery; 
     214                // Compare the last query and the current query by simply json-encoding them, 
     215                // so we dont have to do any deep object compare ... is there some dojo.areObjectsEqual()??? 
     216                if (this.doClientPaging && this._lastServerQuery!==null && 
     217                        dojo.toJson(serverQuery)==dojo.toJson(this._lastServerQuery) 
     218                        ) { 
     219                        fetchHandler(this._items, request); 
     220                } else { 
     221                        var xhrFunc = this.requestMethod.toLowerCase()=="post" ? dojo.xhrPost : dojo.xhrGet; 
     222                        var xhrHandler = xhrFunc({url:this.url, handleAs:"json-comment-optional", content:serverQuery}); 
     223                        var self = this; 
     224                        xhrHandler.addCallback(function(data){ 
     225                                self._items = []; 
     226                                // Store a ref to "this" in each item, so we can simply check if an item 
     227                                // really origins form here (idea is from ItemFileReadStore, I just don't know 
     228                                // how efficient the real storage use, garbage collection effort, etc. is). 
     229                                for (var i in data.items) { 
     230                                        self._items.push({i:data.items[i], r:self}); 
     231                                } 
     232        // TODO actually we should do the same as dojo.data.ItemFileReadStore._getItemsFromLoadedData() to sanitize 
     233        // (does it really sanititze them) and store the data optimal. should we? for security reasons??? 
     234                                fetchHandler(self._items, request); 
     235                        }); 
     236                        xhrHandler.addErrback(function(error){ 
     237                                errorHandler(error, request); 
     238                        }); 
     239                        this.lastRequestTimestamp = new Date().getTime(); 
     240                        this._lastServerQuery = serverQuery; 
     241                } 
     242        }, 
     243         
     244        _assertIsItem: function(/* item */ item){ 
     245                //      summary: 
     246                //              It throws an error if item is not valid, so you can call it in every method that needs to 
     247                //              throw an error when item is invalid. 
     248                //      item:  
     249                //              The item to test for being contained by the store. 
     250                if(!this.isItem(item)){ 
     251                        throw new dojox.data.QueryReadStore.InvalidItemError(this._className+": a function was passed an item argument that was not an item"); 
     252                } 
     253        }, 
     254 
     255        _assertIsAttribute: function(/* attribute-name-string */ attribute){ 
     256                //      summary: 
     257                //              This function tests whether the item passed in is indeed a valid 'attribute' like type for the store. 
     258                //      attribute:  
     259                //              The attribute to test for being contained by the store. 
     260                if(typeof attribute !== "string"){  
     261                        throw new dojox.data.QueryReadStore.InvalidAttributeError(this._className+": '"+attribute+"' is not a valid attribute identifier."); 
     262                } 
     263        } 
     264}); 
     265dojo.extend(dojox.data.QueryReadStore, dojo.data.util.simpleFetch); 
     266 
     267dojo.declare("dojox.data.QueryReadStore.InvalidItemError", Error, {}); 
     268dojo.declare("dojox.data.QueryReadStore.InvalidAttributeError", Error, {}); 
     269 
  • data/tests/QueryReadStore.html

     
     1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" 
     2                "http://www.w3.org/TR/html4/strict.dtd"> 
     3<html> 
     4<head> 
     5 
     6        <style type="text/css"> 
     7                @import "../../../dojo/resources/dojo.css"; 
     8                @import "../../../dijit/themes/tundra/tundra.css"; 
     9                @import "../../../dijit/themes/tundra/tundra_rtl.css"; 
     10        </style> 
     11 
     12        <title>Query read store</title> 
     13 
     14        <script type="text/javascript" src="../../../dojo/dojo.js" djConfig="isDebug: true, parseOnLoad: true"></script> 
     15        <script type="text/javascript" src="../../../dojo/data/util/simpleFetch.js"></script> 
     16        <script type="text/javascript" src="../../../dojox/data/QueryReadStore.js"></script> 
     17        <script type="text/javascript"> 
     18                dojo.require("dijit.form.ComboBox"); 
     19                dojo.require("dojox.data.QueryReadStore"); 
     20                 
     21         
     22         
     23         
     24        dojo.provide("ComboBoxReadStore"); 
     25        dojo.declare("ComboBoxReadStore", dojox.data.QueryReadStore, { 
     26            fetch:function(request) { 
     27                // Copy the GET/POST parameters (request.query) we need into 
     28                // request.serverQuery. We actually want to have 
     29                // the query added to the URL like so:  /url.php?q=<searchString> 
     30                // The data in "queryOptions" are useless for our backend, 
     31                // we ignore them, they are not sent to the server. 
     32                // The combobox puts this into the request-parameter: 
     33                //      { 
     34                //          query: {name:<searchString>}, 
     35                //          queryOptions: {ignoreCase:true, deep:true}, 
     36                //          ... 
     37                //      } 
     38                // We generate request.serverQuery to be this, since those values will 
     39                // be sent to the server. 
     40                //      { 
     41                //          q:<searchString>} 
     42                //      } 
     43                // This results in a xhr request to the following URL (in case of GET): 
     44                //      /url.php?q=<searchString> 
     45                // 
     46 
     47                request.serverQuery = {q:request.query.name}; 
     48                // If we wanted to send the queryOptions too, we could simply do: 
     49                //  request.serverQuery = { 
     50                //          q:request.query.name, 
     51                //          ignoreCase:request.queryOptions.ignoreCase, 
     52                //          deep:request.queryOptions.deep 
     53                //      }; 
     54                // This would then result in this URL, for ignoreCase and deep 
     55                // assumed to be true: 
     56                //      /url.php?q=<searchString>&ignoreCase=true&deep=true 
     57                return this.inherited("fetch", arguments); 
     58            } 
     59        }); 
     60         
     61        dojo.provide("ServerPagingReadStore"); 
     62        dojo.declare("ServerPagingReadStore", dojox.data.QueryReadStore, { 
     63            fetch:function(request) { 
     64                request.serverQuery = {q:request.query.name, start:request.start, count:request.count}; 
     65                return this.inherited("fetch", arguments); 
     66            } 
     67        }); 
     68         
     69         
     70         
     71                var testStore = new ComboBoxReadStore({url:'stores/QueryReadStore.php'});; 
     72                function doSearch() { 
     73                 
     74                    var queryOptions = {}; 
     75                    if (dojo.byId("ignoreCaseEnabled").checked) { 
     76                    queryOptions.ignoreCase = dojo.query("#fetchForm")[0].ignoreCase[0].checked; 
     77            } 
     78                    if (dojo.byId("deepEnabled").checked) { 
     79                    queryOptions.deep = dojo.query("#fetchForm")[0].deep[0].checked; 
     80            } 
     81                     
     82                    var query = {}; 
     83                    query.name = dojo.byId("searchText").value; 
     84             
     85            var request = {query:query, queryOptions:queryOptions}; 
     86             
     87            request.start = dojo.query("#fetchForm")[0].pagingStart.value; 
     88            request.count = dojo.query("#fetchForm")[0].pagingCount.value; 
     89                 
     90                    var requestMethod = "get"; 
     91                    var radioButtons = dojo.query("#fetchForm")[0].requestMethod; 
     92                    for (var i=0; i<radioButtons.length; i++){ 
     93                        if (radioButtons[i].checked) { 
     94                            requestMethod = radioButtons[i].value; 
     95                        } 
     96                    } 
     97                testStore.requestMethod = requestMethod; 
     98            testStore.doClientPaging = dojo.query("#fetchForm")[0].doClientPaging.checked; 
     99            function onComplete(items) { 
     100                var s = "number of items: "+items.length+"<br /><br />"; 
     101                for (var i=0; i<items.length; i++) { 
     102                    s += i+": name: '"+testStore.getValue(items[i], "name")+"'<br />"; 
     103                } 
     104                //s += "<pre>"+dojo.toJson(items)+"</pre>"; 
     105                dojo.byId("fetchOutput").innerHTML = s; 
     106                        }; 
     107            request.onComplete = onComplete; 
     108            testStore.fetch(request); 
     109                } 
     110        </script> 
     111</head> 
     112<body class="tundra" style="margin:20px;"> 
     113        <div dojoType="ComboBoxReadStore" jsId="store" url="stores/QueryReadStore.php" requestMethod="get"></div> 
     114        <input dojoType="dijit.form.ComboBox" store="store" pageSize="5" /> 
     115        <br /><br /><hr /> 
     116     
     117    This ComboBox uses a customized QueryReadStore, it prepares the query-string for the URL that 
     118    way that the paging parameters "start" and "count" are also send.<br /> 
     119        <div dojoType="ServerPagingReadStore" jsId="serverPagingStore" url="stores/QueryReadStore.php" requestMethod="get" doClientPaging="false"></div> 
     120        <input dojoType="dijit.form.ComboBox" store="serverPagingStore" pageSize="5" /> 
     121    <br /> 
     122    <a href="javascript://" onclick="var d = dojo.byId('pagingCode'); d.style.display= d.style.display=='none'?'block':'none';">Click here to  see the code!</a> 
     123<div id="pagingCode" style="display:none;"> 
     124    The HTML might look like this, the important attribute: <em>doClientPaging="false"</em> this takes care that the same query is fired to the server 
     125    and its not assumed that the client (the store) does the paging on the old data. 
     126    <pre> 
     127&lt;div dojoType="ServerPagingReadStore" jsId="serverPagingStore" url="stores/QueryReadStore.php" requestMethod="get" doClientPaging="false"&gt;&lt;/div&gt; 
     128&lt;input dojoType="dijit.form.ComboBox" store="serverPagingStore" pageSize="10" /&gt; 
     129    </pre> 
     130    <pre>dojo.require("dojox.data.QueryReadStore"); 
     131     
     132    dojo.provide("ServerPagingReadStore"); 
     133    dojo.declare("ServerPagingReadStore", dojox.data.QueryReadStore, { 
     134        fetch:function(request) { 
     135            request.query = {q:request.query.name, start:request.start, count:request.count}; 
     136            return this.inherited("fetch", arguments); 
     137        } 
     138    });</pre> 
     139</div> 
     140        <br /><br /> 
     141         
     142        <hr /> 
     143         
     144        <style> 
     145             fieldset { 
     146                 border:1px solid black; 
     147                 display:inline; 
     148                 padding:10px; 
     149             } 
     150             div.disabled { 
     151                 opacity:0.1; 
     152             } 
     153        </style> 
     154        <form id="fetchForm"> 
     155                <fieldset title="requestMethod"> 
     156                    <legend>requestMethod</legend> 
     157            get <input type="radio" value="get" checked="checked" name="requestMethod" /> 
     158            post <input type="radio" value="post" name="requestMethod" /> 
     159                </fieldset> 
     160                 
     161                <fieldset title="queryOptions"> 
     162            <legend>queryOptions</legend> 
     163             
     164            <fieldset id="ignoreCaseFieldset"> 
     165                <legend><input type="checkbox" id="ignoreCaseEnabled" /> ignoreCase</legend> 
     166                <div class="disabled"> 
     167                    true <input type="radio" value="0" checked="checked" name="ignoreCase" /> 
     168                    false <input type="radio" value="1" name="ignoreCase" /> 
     169                </div> 
     170            </fieldset> 
     171            <fieldset id="deepFieldset"> 
     172                <legend><input type="checkbox" id="deepEnabled" /> deep</legend> 
     173                <div class="disabled"> 
     174                    true <input type="radio" value="0" name="deep" /> 
     175                    false <input type="radio" value="1" name="deep" checked="checked" /> 
     176                </div> 
     177            </fieldset> 
     178                </fieldset> 
     179                <fieldset title="paging"> 
     180            <legend>paging</legend> 
     181            start: <input id="pagingStart" value="0" size="3" /> 
     182            count: <input id="pagingCount" value="10" size="3"  /> 
     183            <br /><br /> 
     184            do client paging: <input id="doClientPaging" type="checkbox" checked="checked" /> 
     185        </fieldset> 
     186                <script> 
     187                    var fieldsets = ["ignoreCaseFieldset", "deepFieldset"]; 
     188                    for (var i=0; i<fieldsets.length; i++) { 
     189                        dojo.connect(dojo.byId(fieldsets[i]), "onchange", toggleFieldset); 
     190                    } 
     191                    function toggleFieldset(el) { 
     192                        var divs = dojo.query("div", el.target.parentNode.parentNode); 
     193                        if (divs.length) { 
     194                    var div = divs[0]; 
     195                    if (el.target.checked) { 
     196                        dojo.removeClass(div, "disabled"); 
     197                    } else { 
     198                        dojo.addClass(div, "disabled"); 
     199                    } 
     200                } 
     201                    } 
     202                </script> 
     203                 
     204                <br /><br /> 
     205                <input id="searchText" type="text" value="a"> 
     206                <input id="searchButton" type="button" value="store.fetch()" onclick="doSearch()" /> 
     207        </form> 
     208    <div id="fetchOutput" style="background-color:#FFDDDD; margin-top:1em; float:left;"></div> 
     209</body> 
     210</html> 
  • data/tests/stores/QueryReadStore.js

     
     1dojo.provide("dojox.data.tests.stores.QueryReadStore"); 
     2dojo.require("dojox.data.QueryReadStore"); 
     3 
     4dojo.require("dojox.testing.DocTest"); 
     5 
     6dojox.data.tests.stores.QueryReadStore.getStore = function(){ 
     7        return new dojox.data.QueryReadStore({ 
     8                        url: dojo.moduleUrl("dojox.data.tests", "stores/QueryReadStore.php").toString(), 
     9                        doClientPaging:true // "true" is actually also the default, but make sure :-). 
     10                }); 
     11}; 
     12 
     13tests.register("dojox.data.tests.stores.QueryReadStore",  
     14        [ 
     15                function testDocTests(t) { 
     16                        //      summary: 
     17                        //              Run all the doc comments. 
     18                        var doctest = new dojox.testing.DocTest(); 
     19                        doctest.run("dojox.data.QueryReadStore"); 
     20                        t.assertTrue(doctest.errors.length==0); 
     21                }, 
     22                 
     23                function testReadApi_getValue(t){ 
     24                        //      summary:  
     25                        //      description: 
     26                        var store = dojox.data.tests.stores.QueryReadStore.getStore(); 
     27                         
     28                        var d = new doh.Deferred(); 
     29                        function onComplete(items, request){ 
     30                                var item = items[0]; 
     31                                // The good cases. 
     32                                t.assertEqual("Alabama", store.getValue(item, "name")); 
     33                                t.assertEqual("<img src='images/Alabama.jpg'/>Alabama", store.getValue(item, "label")); 
     34                                t.assertEqual("AL", store.getValue(item, "abbreviation")); 
     35                                // Test the defaultValue cases (the third paramter). 
     36                                t.assertEqual("default value", store.getValue(item, "NAME", "default value")); 
     37                                // TODO Test for null somehow ... 
     38                                // Read api says: Returns null if and only if null was explicitly set as the attribute value. 
     39                                 
     40                                // Test for not-existing attributes without defaultValues and invalid items. 
     41                                t.assertError(dojox.data.QueryReadStore.InvalidAttributeError, store, "getValue", [item, "NOT THERE"]); 
     42                                t.assertError(dojox.data.QueryReadStore.InvalidItemError, store, "getValue", ["not an item", "NOT THERE"]); 
     43                                 
     44                                d.callback(true); 
     45                        } 
     46                        store.fetch({query:{q:"Alabama"}, onComplete: onComplete}); 
     47                        return d; //Object 
     48                }, 
     49 
     50                function testReadApi_getValues(t){ 
     51                        //      summary:  
     52                        //      description: 
     53                        var store = dojox.data.tests.stores.QueryReadStore.getStore(); 
     54                         
     55                        var d = new doh.Deferred(); 
     56                        function onComplete(items, request){ 
     57                                var item = items[0]; 
     58                                // The good cases. 
     59                                t.assertEqual(["Alabama"], store.getValues(item, "name")); 
     60                                t.assertEqual(["<img src='images/Alabama.jpg'/>Alabama"], store.getValues(item, "label")); 
     61                                t.assertEqual(["AL"], store.getValues(item, "abbreviation")); 
     62                                // TODO Test for null somehow ... 
     63                                // Read api says: Returns null if and only if null was explicitly set as the attribute value. 
     64 
     65                                // Test for not-existing attributes without defaultValues and invalid items. 
     66                                // TODO 
     67                                //t.assertError(dojox.data.QueryReadStore.InvalidAttributeError, store, "getValues", [item, "NOT THERE"]); 
     68                                //t.assertError(dojox.data.QueryReadStore.InvalidItemError, store, "getValues", ["not an item", "NOT THERE"]); 
     69                                 
     70                                d.callback(true); 
     71                        } 
     72                        store.fetch({query:{q:"Alabama"}, onComplete: onComplete}); 
     73                        return d; //Object 
     74                }, 
     75                 
     76                function testReadApi_getAttributes(t){ 
     77                        //      summary:  
     78                        //      description: 
     79                        var store = dojox.data.tests.stores.QueryReadStore.getStore(); 
     80                         
     81                        var d = new doh.Deferred(); 
     82                        function onComplete(items, request){ 
     83                                var item = items[0]; 
     84                                // The good case(s). 
     85                                t.assertEqual(['name', 'label', 'abbreviation'], store.getAttributes(item)); 
     86                                t.assertError(dojox.data.QueryReadStore.InvalidItemError, store, "getAttributes", [{}]); 
     87                                 
     88                                d.callback(true); 
     89                        } 
     90                        store.fetch({query:{q:"Alabama"}, onComplete: onComplete}); 
     91                        return d; //Object 
     92                }, 
     93 
     94                function testReadApi_hasAttribute(t){ 
     95                        //      summary:  
     96                        //      description: 
     97                        var store = dojox.data.tests.stores.QueryReadStore.getStore(); 
     98                         
     99                        var d = new doh.Deferred(); 
     100                        function onComplete(items, request){ 
     101                                var item = items[0]; 
     102                                // The positive cases. 
     103                                t.assertEqual(true, store.hasAttribute(item, "name")); 
     104                                t.assertEqual(true, store.hasAttribute(item, "label")); 
     105                                t.assertEqual(true, store.hasAttribute(item, "abbreviation")); 
     106                                // Make sure attribute case doesnt matter. 
     107                                t.assertEqual(false, store.hasAttribute(item, "NAME")); 
     108                                t.assertEqual(false, store.hasAttribute(item, "Name")); 
     109                                t.assertEqual(false, store.hasAttribute(item, "Label")); 
     110                                // Pass in an invalid item. 
     111                                t.assertEqual(false, store.hasAttribute({}, "abbreviation")); 
     112                                // pass in something that looks like the item with the attribute. 
     113                                t.assertEqual(false, store.hasAttribute({name:"yo"}, "name")); 
     114                                 
     115                                d.callback(true); 
     116                        } 
     117                        store.fetch({query:{q:"Alaska"}, onComplete: onComplete}); 
     118                        return d; //Object 
     119                }, 
     120 
     121                function testReadApi_containsValue(t){ 
     122                        //      summary:  
     123                        //      description: 
     124                        t.assertTrue(false); 
     125                }, 
     126 
     127                function testReadApi_isItem(t){ 
     128                        //      summary:  
     129                        //      description: 
     130                        var store = dojox.data.tests.stores.QueryReadStore.getStore(); 
     131                         
     132                        var d = new doh.Deferred(); 
     133                        function onComplete(items, request){ 
     134                                // The good case. 
     135                                t.assertEqual(true, store.isItem(items[0])); 
     136                                // Try a pure object. 
     137                                t.assertEqual(false, store.isItem({})); 
     138                                // Try to look like an item. 
     139                                t.assertEqual(false, store.isItem({name:"Alaska", label:"Alaska", abbreviation:"AK"})); 
     140                                d.callback(true); 
     141                        } 
     142                        store.fetch({query:{q:"Alaska"}, onComplete: onComplete}); 
     143                        return d; //Object 
     144                }, 
     145 
     146                function testReadApi_isItemLoaded(t){ 
     147                        //      summary:  
     148                        //      description: 
     149                        var store = dojox.data.tests.stores.QueryReadStore.getStore(); 
     150                         
     151                        var d = new doh.Deferred(); 
     152                        function onComplete(items, request){ 
     153                                var item = items[0]; 
     154                                // The good case(s). 
     155                                t.assertTrue(store.isItemLoaded(item)); 
     156                                 
     157                                d.callback(true); 
     158                        } 
     159                        store.fetch({query:{q:"Alabama"}, onComplete: onComplete}); 
     160                        return d; //Object 
     161                }, 
     162 
     163                //function testReadApi_loadItem(t){ 
     164                //      //      summary:  
     165                //      //      description: 
     166                //      t.assertTrue(false); 
     167                //}, 
     168 
     169                function testReadApi_fetch_all(t){ 
     170                        //      summary:  
     171                        //              Simple test of fetching all items. 
     172                        //      description: 
     173                        //              Simple test of fetching all items. 
     174                        var store = dojox.data.tests.stores.QueryReadStore.getStore(); 
     175 
     176                        var d = new doh.Deferred(); 
     177                        function onComplete(items, request) { 
     178                                t.assertEqual(8, items.length); 
     179                                d.callback(true); 
     180                        } 
     181                        function onError(error, request) { 
     182                                d.errback(error); 
     183                        } 
     184                        store.fetch({query:{q:"a"}, onComplete: onComplete, onError: onError}); 
     185                        return d; //Object 
     186                }, 
     187                 
     188                function testReadApi_fetch_one(t){ 
     189                        //      summary:  
     190                        //      description: 
     191                        var store = dojox.data.tests.stores.QueryReadStore.getStore(); 
     192                         
     193                        var d = new doh.Deferred(); 
     194                        function onComplete(items, request){ 
     195                                t.assertEqual(1, items.length); 
     196                                d.callback(true); 
     197                        } 
     198                        function onError(error, request) { 
     199                                d.errback(error); 
     200                        } 
     201                        store.fetch({query:{q:"Alaska"}, onComplete: onComplete, onError: onError}); 
     202                        return d; //Object 
     203                }, 
     204 
     205                function testReadApi_fetch_client_paging(t){ 
     206                        //      summary: 
     207                        //              Lets test that paging on the same request does not trigger 
     208                        //              server requests. 
     209                        //      description: 
     210                        var store = dojox.data.tests.stores.QueryReadStore.getStore(); 
     211 
     212                        var lastRequestTimestamp = null; 
     213                        var firstItems = []; 
     214                        var d = new doh.Deferred(); 
     215                        function onComplete(items, request) { 
     216                                t.assertEqual(5, items.length); 
     217                                lastRequestTimestamp = store.lastRequestTimestamp; 
     218                                firstItems = items; 
     219                                 
     220                                // Do the next request AFTER the previous one, so we are sure its sequential. 
     221                                // We need to be sure so we can compare to the data from the first request. 
     222                                function onComplete1(items, request) { 
     223                                        t.assertEqual(5, items.length); 
     224                                        t.assertEqual(lastRequestTimestamp, store.lastRequestTimestamp); 
     225                                        t.assertEqual(firstItems[1], items[0]); 
     226                                        d.callback(true); 
     227                                } 
     228                                req.start = 1; 
     229                                req.onComplete = onComplete1; 
     230                                store.fetch(req); 
     231                        } 
     232                        function onError(error, request) { 
     233                                d.errback(error); 
     234                        } 
     235                        var req = {query:{q:"a"}, start:0, count:5, 
     236                                                onComplete: onComplete, onError: onError}; 
     237                        store.fetch(req); 
     238                        return d; //Object 
     239                }, 
     240                 
     241                function testReadApi_fetch_serverQuery(t) { 
     242                        // TODO verify serverQuery vs. query  
     243                        t.assertTrue(false); 
     244                }, 
     245                 
     246                function testReadApi_getFeatures(t) { 
     247                        var store = dojox.data.tests.stores.QueryReadStore.getStore(); 
     248                        var features = store.getFeatures(); 
     249                        t.assertTrue(features["dojo.data.api.Read"]); 
     250                } 
     251        ] 
     252); 
  • data/tests/stores/QueryReadStore.php

     
     1<?php 
     2 
     3header("Content-Type", "text/json"); 
     4 
     5$allItems = array( 
     6    array('name'=>"Alabama", 'label'=>"<img src='images/Alabama.jpg'/>Alabama", 'abbreviation'=>"AL"), 
     7    array('name'=>"Alaska", 'label'=>"Alaska", 'abbreviation'=>"AK"), 
     8    array('name'=>"American Samoa", 'label'=>"American Samoa", 'abbreviation'=>"AS"), 
     9    array('name'=>"Arizona", 'label'=>"Arizona", 'abbreviation'=>"AZ"), 
     10    array('name'=>"Arkansas", 'label'=>"Arkansas", 'abbreviation'=>"AR"), 
     11    array('name'=>"Armed Forces Europe", 'label'=>"Armed Forces Europe", 'abbreviation'=>"AE"), 
     12    array('name'=>"Armed Forces Pacific", 'label'=>"Armed Forces Pacific", 'abbreviation'=>"AP"), 
     13    array('name'=>"Armed Forces the Americas", 'label'=>"Armed Forces the Americas", 'abbreviation'=>"AA"), 
     14    array('name'=>"California", 'label'=>"California", 'abbreviation'=>"CA"), 
     15    array('name'=>"Colorado", 'label'=>"Colorado", 'abbreviation'=>"CO"), 
     16    array('name'=>"Connecticut", 'label'=>"Connecticut", 'abbreviation'=>"CT"), 
     17    array('name'=>"Delaware", 'label'=>"Delaware", 'abbreviation'=>"DE"), 
     18    array('name'=>"District of Columbia", 'label'=>"District of Columbia", 'abbreviation'=>"DC"), 
     19    array('name'=>"Federated States of Micronesia", 'label'=>"Federated States of Micronesia", 'abbreviation'=>"FM"), 
     20    array('name'=>"Florida", 'label'=>"Florida", 'abbreviation'=>"FL"), 
     21    array('name'=>"Georgia", 'label'=>"Georgia", 'abbreviation'=>"GA"), 
     22    array('name'=>"Guam", 'label'=>"Guam", 'abbreviation'=>"GU"), 
     23    array('name'=>"Hawaii", 'label'=>"Hawaii", 'abbreviation'=>"HI"), 
     24    array('name'=>"Idaho", 'label'=>"Idaho", 'abbreviation'=>"ID"), 
     25    array('name'=>"Illinois", 'label'=>"Illinois", 'abbreviation'=>"IL"), 
     26    array('name'=>"Indiana", 'label'=>"Indiana", 'abbreviation'=>"IN"), 
     27    array('name'=>"Iowa", 'label'=>"Iowa", 'abbreviation'=>"IA"), 
     28    array('name'=>"Kansas", 'label'=>"Kansas", 'abbreviation'=>"KS"), 
     29    array('name'=>"Kentucky", 'label'=>"Kentucky", 'abbreviation'=>"KY"), 
     30    array('name'=>"Louisiana", 'label'=>"Louisiana", 'abbreviation'=>"LA"), 
     31    array('name'=>"Maine", 'label'=>"Maine", 'abbreviation'=>"ME"), 
     32    array('name'=>"Marshall Islands", 'label'=>"Marshall Islands", 'abbreviation'=>"MH"), 
     33    array('name'=>"Maryland", 'label'=>"Maryland", 'abbreviation'=>"MD"), 
     34    array('name'=>"Massachusetts", 'label'=>"Massachusetts", 'abbreviation'=>"MA"), 
     35    array('name'=>"Michigan", 'label'=>"Michigan", 'abbreviation'=>"MI"), 
     36    array('name'=>"Minnesota", 'label'=>"Minnesota", 'abbreviation'=>"MN"), 
     37    array('name'=>"Mississippi", 'label'=>"Mississippi", 'abbreviation'=>"MS"), 
     38    array('name'=>"Missouri", 'label'=>"Missouri", 'abbreviation'=>"MO"), 
     39    array('name'=>"Montana", 'label'=>"Montana", 'abbreviation'=>"MT"), 
     40    array('name'=>"Nebraska", 'label'=>"Nebraska", 'abbreviation'=>"NE"), 
     41    array('name'=>"Nevada", 'label'=>"Nevada", 'abbreviation'=>"NV"), 
     42    array('name'=>"New Hampshire", 'label'=>"New Hampshire", 'abbreviation'=>"NH"), 
     43    array('name'=>"New Jersey", 'label'=>"New Jersey", 'abbreviation'=>"NJ"), 
     44    array('name'=>"New Mexico", 'label'=>"New Mexico", 'abbreviation'=>"NM"), 
     45    array('name'=>"New York", 'label'=>"New York", 'abbreviation'=>"NY"), 
     46    array('name'=>"North Carolina", 'label'=>"North Carolina", 'abbreviation'=>"NC"), 
     47    array('name'=>"North Dakota", 'label'=>"North Dakota", 'abbreviation'=>"ND"), 
     48    array('name'=>"Northern Mariana Islands", 'label'=>"Northern Mariana Islands", 'abbreviation'=>"MP"), 
     49    array('name'=>"Ohio", 'label'=>"Ohio", 'abbreviation'=>"OH"), 
     50    array('name'=>"Oklahoma", 'label'=>"Oklahoma", 'abbreviation'=>"OK"), 
     51    array('name'=>"Oregon", 'label'=>"Oregon", 'abbreviation'=>"OR"), 
     52    array('name'=>"Pennsylvania", 'label'=>"Pennsylvania", 'abbreviation'=>"PA"), 
     53    array('name'=>"Puerto Rico", 'label'=>"Puerto Rico", 'abbreviation'=>"PR"), 
     54    array('name'=>"Rhode Island", 'label'=>"Rhode Island", 'abbreviation'=>"RI"), 
     55    array('name'=>"South Carolina", 'label'=>"South Carolina", 'abbreviation'=>"SC"), 
     56    array('name'=>"South Dakota", 'label'=>"South Dakota", 'abbreviation'=>"SD"), 
     57    array('name'=>"Tennessee", 'label'=>"Tennessee", 'abbreviation'=>"TN"), 
     58    array('name'=>"Texas", 'label'=>"Texas", 'abbreviation'=>"TX"), 
     59    array('name'=>"Utah", 'label'=>"Utah", 'abbreviation'=>"UT"), 
     60    array('name'=>"Vermont", 'label'=>"Vermont", 'abbreviation'=>"VT"), 
     61    array('name'=> "Virgin Islands, U.S.", 'label'=>"Virgin Islands, U.S.", 'abbreviation'=>"VI"), 
     62    array('name'=>"Virginia", 'label'=>"Virginia", 'abbreviation'=>"VA"), 
     63    array('name'=>"Washington", 'label'=>"Washington", 'abbreviation'=>"WA"), 
     64    array('name'=>"West Virginia", 'label'=>"West Virginia", 'abbreviation'=>"WV"), 
     65    array('name'=>"Wisconsin", 'label'=>"Wisconsin", 'abbreviation'=>"WI"), 
     66    array('name'=>"Wyoming", 'label'=>"Wyoming", 'abbreviation'=>"WY"), 
     67//    array('id'=>, 'name'=>''), 
     68); 
     69 
     70$q = ""; 
     71if (array_key_exists("q", $_REQUEST)) { 
     72    $q = $_REQUEST['q']; 
     73} 
     74if (strlen($q) && $q[strlen($q)-1]=="*") { 
     75    $q = substr($q, 0, strlen($q)-1); 
     76} 
     77$ret = array(); 
     78foreach ($allItems as $item) { 
     79    if (!$q || strpos(strtolower($item['name']), strtolower($q))===0) { 
     80        $ret[] = $item; 
     81    } 
     82} 
     83 
     84// Handle paging, if given. 
     85if (array_key_exists("start", $_REQUEST)) { 
     86    $ret = array_slice($ret, $_REQUEST['start']); 
     87} 
     88if (array_key_exists("count", $_REQUEST)) { 
     89    $ret = array_slice($ret, 0, $_REQUEST['count']); 
     90} 
     91 
     92print '/*'.json_encode(array('items'=>$ret)).'*/';