Skip to content
This repository was archived by the owner on Feb 11, 2021. It is now read-only.

Commit 7d097ee

Browse files
Add data sources to use SQL queries in ListViews
Using Database::itemDataSource(), one can now create a data source object that implements the IListDataSource interface. It can be used to conveniently display the results of an SQLite query in a WinJS.UI.ListView (or FlipView). Database::groupDataSource() creates an additional data source that can be used to group the items in the ListView. This can be a bit tricky, because the SQL queries used in both list views must be compatible -- most importantly, the items must be ordered exactly as they appear in groups, and they must have a groupKey property (that can be obtained from a column using the groupKeyColumnName parameter).
1 parent 7827467 commit 7d097ee

File tree

2 files changed

+161
-1
lines changed

2 files changed

+161
-1
lines changed

SQLite3JS/js/SQLite3.js

+101-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
(function () {
22
"use strict";
33

4-
var Statement, Database;
4+
var Statement, Database, ItemDataSource, GroupDataSource;
55

66
// Alternative typeof implementation yielding more meaningful results,
77
// see http://javascriptweblog.wordpress.com/2011/08/08/fixing-the-javascript-typeof-operator/
@@ -166,11 +166,111 @@
166166
prepare: function (sql, args) {
167167
return new Statement(this, sql, args);
168168
},
169+
itemDataSource: function (sql, args, keyColumnName, groupKeyColumnName) {
170+
if (type(args) === 'string') {
171+
groupKeyColumnName = keyColumnName;
172+
keyColumnName = args;
173+
args = undefined;
174+
}
175+
176+
return new ItemDataSource(this, sql, args, keyColumnName, groupKeyColumnName);
177+
},
178+
groupDataSource: function (sql, args, keyColumnName, sizeColumnName) {
179+
if (type(args) === 'string') {
180+
sizeColumnName = keyColumnName;
181+
keyColumnName = args;
182+
args = undefined;
183+
}
184+
185+
return new GroupDataSource(this, sql, args, keyColumnName, sizeColumnName);
186+
},
169187
close: function () {
170188
this.connection.close();
171189
}
172190
});
173191

192+
ItemDataSource = WinJS.Class.derive(WinJS.UI.VirtualizedDataSource,
193+
function (db, sql, args, keyColumnName, groupKeyColumnName) {
194+
var dataAdapter = {
195+
getCount: function () {
196+
var row = db.one('SELECT COUNT(*) AS cnt FROM (' + sql + ')', args);
197+
return WinJS.Promise.wrap(row.cnt);
198+
},
199+
itemsFromIndex: function (requestIndex, countBefore, countAfter) {
200+
var items,
201+
limit = countBefore + 1 + countAfter,
202+
offset = requestIndex - countBefore;
203+
204+
items = db.map(
205+
'SELECT * FROM (' + sql + ') LIMIT ' + limit + ' OFFSET ' + offset,
206+
function (row) {
207+
var item = {
208+
key: row[keyColumnName].toString(),
209+
data: row
210+
};
211+
if (groupKeyColumnName) {
212+
item.groupKey = row[groupKeyColumnName].toString();
213+
}
214+
return item;
215+
});
216+
217+
return WinJS.Promise.wrap({
218+
items: items,
219+
offset: countBefore,
220+
atEnd: items.length < limit
221+
});
222+
}
223+
};
224+
225+
this._baseDataSourceConstructor(dataAdapter);
226+
}
227+
);
228+
229+
GroupDataSource = WinJS.Class.derive(WinJS.UI.VirtualizedDataSource,
230+
function (db, sql, args, keyColumnName, sizeColumnName) {
231+
var groups,
232+
dataAdapter,
233+
keyIndexMap = {},
234+
groupIndex = 0,
235+
firstItemIndex = 0;
236+
237+
groups = db.map(sql, args, function (row) {
238+
var item = {
239+
key: row[keyColumnName].toString(),
240+
groupSize: row[sizeColumnName],
241+
firstItemIndexHint: firstItemIndex,
242+
data: row
243+
};
244+
245+
keyIndexMap[item.key] = groupIndex;
246+
groupIndex += 1;
247+
firstItemIndex += item.groupSize;
248+
249+
return item;
250+
});
251+
252+
dataAdapter = {
253+
getCount: function () {
254+
return WinJS.Promise.wrap(groups.length);
255+
},
256+
itemsFromIndex: function (requestIndex, countBefore, countAfter) {
257+
return WinJS.Promise.wrap({
258+
items: groups.slice(),
259+
offset: requestIndex,
260+
absoluteIndex: requestIndex,
261+
atStart: true,
262+
atEnd: true
263+
});
264+
},
265+
itemsFromKey: function (key, countBefore, countAfter) {
266+
return this.itemsFromIndex(keyIndexMap[key], countBefore, countAfter);
267+
}
268+
};
269+
270+
this._baseDataSourceConstructor(dataAdapter);
271+
}
272+
);
273+
174274
WinJS.Namespace.define('SQLite3JS', {
175275
Database: Database
176276
});

SQLite3JS/spec/SQLite3Spec.js

+60
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,66 @@
112112
});
113113
});
114114

115+
describe('Item Data Source', function () {
116+
beforeEach(function () {
117+
this.itemDataSource = db.itemDataSource('SELECT * FROM Item', 'id');
118+
});
119+
120+
it('should support getCount()', function () {
121+
waitsForPromise(
122+
this.itemDataSource.getCount().then(function (count) {
123+
expect(count).toEqual(3);
124+
})
125+
);
126+
});
127+
128+
it('should support itemFromIndex()', function () {
129+
waitsForPromise(
130+
this.itemDataSource.itemFromIndex(1).then(function (item) {
131+
expect(item.key).toEqual('2');
132+
expect(item.data.name).toEqual('Orange');
133+
})
134+
);
135+
});
136+
});
137+
138+
describe('Group Data Source', function () {
139+
beforeEach(function () {
140+
this.groupDataSource = db.groupDataSource(
141+
'SELECT LENGTH(name) AS key, COUNT(*) AS groupSize FROM Item GROUP BY key',
142+
'key',
143+
'groupSize');
144+
});
145+
146+
it('should support getCount()', function () {
147+
waitsForPromise(
148+
this.groupDataSource.getCount().then(function (count) {
149+
expect(count).toEqual(2);
150+
})
151+
);
152+
});
153+
154+
it('should support itemFromIndex()', function () {
155+
waitsForPromise(
156+
this.groupDataSource.itemFromIndex(1).then(function (item) {
157+
expect(item.key).toEqual('6');
158+
expect(item.groupSize).toEqual(2);
159+
expect(item.firstItemIndexHint).toEqual(1);
160+
})
161+
);
162+
});
163+
164+
it('should support itemFromKey()', function () {
165+
waitsForPromise(
166+
this.groupDataSource.itemFromKey('5').then(function (item) {
167+
expect(item.key).toEqual('5');
168+
expect(item.groupSize).toEqual(1);
169+
expect(item.firstItemIndexHint).toEqual(0);
170+
})
171+
);
172+
});
173+
});
174+
115175
it('should pass JSLint', function () {
116176
this.addMatchers({
117177
toPassJsLint: function () {

0 commit comments

Comments
 (0)