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 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386
|
/*!
\page u1db-qt-tutorial-5.html
\title U1Db-Qt Index Tutorial
This tutorial is designed to demonstrate a variety of essential U1Db-Qt functionality and usage, including:
\list 1
\li Utilizing the U1db-Qt Index element
\li Various approaches to define U1db-Qt Document elements when using the Index element
\li Partnering the U1db-Qt Index element and a QML ListView element
\endlist
\section1 Storing Data
\section2 The Database Element
\section3 Creating a Database
A Database is very simple to create. It only needs an id and a path where the file will be created. A Database is a model, which can be used by elements, such as the ListView further in this example.
\code
U1db.Database {
id: aDatabase
path: "aDatabase4"
}
\endcode
\section1 The Document Element
\section2 Declaring Documents (at Runtime)
A Document can be instantiated at runtime, or generated dynamically. The examples below demonstrate the former.
A very basic Document could include its unique 'id' and 'docId' properties. While it is not mandatory to define these properties, in some cases they can be convenient references. More advanced applications would likely find these very useful, and in some cases may be an absolute necessity to achieve the objectives of the program.
This example of a very simple Document will not initially do anything, until more properties are added and defined:
\code
U1db.Document {
id: aDocument1
docId: 'helloworld1'
}
\endcode
A basic but still practical Document definition contains several essential properties. In addition to 'id' and 'docId' (discussed above), the 'database', 'create', and 'defaults' properties are also very important, and are introduced below.
The 'database' property ensures that the Document is attached to an already defined (or possibly soon to be defined one) identified by its id (in this case 'aDatabase'). For example:
\code
U1db.Document {
id: aDocument1
database: aDatabase
docId: 'helloworld1'
}
\endcode
Should the Database not already contain a Document with the same docId ('hellowworld1' in this example) when a 'create' property is present and set to true it will be generated. For example:
\code
U1db.Document {
id: aDocument1
database: aDatabase
docId: 'helloworld1'
create: true
}
\endcode
However, the Document still requires some data to be useful, which is what the 'defaults' property provides. The value of 'defaults' is a map of data that will be stored in the database (again when the create property is et to true). It contain key:value pairs, where the value can be a string, number, or nested object (e.g. additional fields, lists). For example:
\code
U1db.Document {
id: aDocument1
database: aDatabase
docId: 'helloworld1'
create: true
defaults:{"hello": { "world": { "message":"Hello World", "id": 1 } } }
}
\endcode
As mentioned above, lists can also be nested in Document data. Lists provide a convenient method for producing multiple instances of the same key (AKA 'field' or 'sub-field'). The example code below shows valid use of the 'message' and 'id' sub-fields multiple times within the same object.
\code
U1db.Document {
id: aDocument2
database: aDatabase
docId: 'helloworld2'
create: true
defaults:{"hello": { "world": [
{ "message":"Hello World", "id": 2 },
{ "message":"Hello World", "id": 2.5 }
] } }
}
\endcode
When the default Javascript Object Notation itself is formatted with appropriate line breaks and indentation, it becomes easier to visualize an embedded list, containing sub-fields 'message' and 'id' (and their respective values):
\code
{"hello":
{ "world":
[
{ "message":"Hello World", "id": 2 },
{ "message":"Hello World", "id": 2.5 }
]
}
}
\endcode
In dot notation these sub-fields are represented by 'hello.world.message' and 'hello.world.id' respectively. Later in this tutorial these will be utilized within the 'expression' property of U1Db-Qt's Index element, in close collaboration with a QML ListView's delegates.
Normally when a docId already exists in a database, and when the set flag is set to true, the value in 'defaults' will be ignored (and the existing data in the database will remain untouched). Sometimes a developer needs to easily overwrite the data in an existing document. The 'contents' property can be used for just that purpose. When 'contents' is defined, its value will replace existing data in the database, for the document identified by the docId. In addition, 'contents' can be used to add new documents, in the same way as the 'create: true' + 'defaults' combination does; in other words, if the document defined by 'docId' does not exist it will be created.
\code
U1db.Document {
id: aDocument3
database: aDatabase
docId: 'helloworld3'
contents:{"hello": { "world": [
{ "message":"Hello World", "id": 3 },
{ "message":"Hello World", "id": 3.33 },
{ "message":"Hello World", "id": 3.66 }
] } }
}
\endcode
If 'defaults' exists, 'create' is set to 'true' (or 'false' for that matter) and 'contents' is also defined, it is the latter that takes precidence. In other words, 'create' and 'defaults' will be ignored. The following example demonstrates this scenario:
\code
U1db.Document {
id: aDocument3
database: aDatabase
docId: 'helloworld3'
create: true
default:{"hello": { "world": [{ "message":"Hello World", "id": 3 }] } }
contents:{"hello": { "world": [
{ "message":"Hello World", "id": 3 },
{ "message":"Hello World", "id": 3.33 },
{ "message":"Hello World", "id": 3.66 }
] } }
}
\endcode
This snippet simply represents the absence of the 'create' property, which is synonymous with 'create: false'. The Document can still be recognized within the application, but until applicable properties (such as those outlined above) are added and/or modified then nothing will be added or modified in the database, and this instance may have very little practical value.
\code
U1db.Document {
id: aDocument4
database: aDatabase
docId: 'helloworld4'
defaults:{"hello": { "world": { "message":"Hello World", "id": 4 } } }
}
\endcode
\section3 Samples of Stored Documents
The data stored in the database after defining the above Document elements (and then running the application, will consist of the following:
\table
\header
\li docId
\li content
\row
\li 'helloworld1'
\li
\code
{
"hello": {
"world": {
"id": 1,
"message": "Hello World"
}
}
}
\endcode
\row
\li 'helloworld2'
\li
\code
{
"hello": {
"world": [
{
"id": 2,
"message": "Hello World"
},
{
"id": 2.5,
"message": "Hello World"
}
]
}
}
\endcode
\row
\li 'helloworld3'
\li
\code
{
"hello": {
"world": [
{
"id": 3,
"message": "Hello World"
},
{
"id": 3.33,
"message": "Hello World"
},
{
"id": 3.66,
"message": "Hello World"
}
]
}
}
\endcode
\endtable
\section1 Retrieving Data
To retrieve the Documents that were declared earlier requires two additional elements: Index and Query.
\section2 The Index Element
\section3 Creating and Index Element
The Index element requires both a unique 'id' and a pointer to a 'database' in order to begin becoming useful, as demonstrated here:
\code
U1db.Index{
database: aDatabase
id: by_helloworld
}
\endcode
In the future, the Index element will support on disk storage of appropriate results / data. At the present time only in memory indexing is done, but once the storing capability is implemented, defining and identifying it is as simple as using the 'name' property (which will be stored in the database along with the relvent data that goes with it). The snippet below shows the use of the 'name' property:
\code
U1db.Index{
database: aDatabase
id: by_helloworld
//name: "by-helloworld"
}
\endcode
The Index element describes, using dot notation, the fields and sub-fields where the developer expects to find information. That information is defined in a list, and added as the value for the 'expression' property. The list can contain one or more entries, as exemplified here (the property is commented out due to its current status):
\code
U1db.Index{
database: aDatabase
id: by_helloworld
//name: "by-helloworld"
expression: ["hello.world.id","hello.world.message"]
}
\endcode
\section2 The QueryElement
\section3 Creating a Query Element
The Query element has two responsibilities: a bridge from Database+Index to other parts of the application, as well as further filtering of data in the database (in addition to what Index provides).
In order to fulfil its duties as a bridge to an Index (and Database), the 'index' property must point to an Index element, identified by its 'id'. For example:
\code
U1db.Query{
id: aQuery
index: by_helloworld
}
\endcode
While Index helps to filter data based on 'where' it is located (e.g. field.sub-field), Query helps determine the additional set of criteria for 'what' is being searched for. The intent of the 'query' property is to provide the mechanism for defnining the search criteria, but at the time of writing that functionality is not yet available. However, once the implementation is in place, using it is only requires defining the property's value (e.g. "Hello World"). Wild card searches using '*' are supported, which is the default query (i.e. if 'query' is not set it is assumed to be '*'). For example (the property is commented out due to its current status):
\code
U1db.Query{
id: aQuery
index: by_helloworld
//query: "*"
}
\endcode
When the 'query' property becomes available, only wildcard search definitions for "starts with" will be suppoprted. Thus the following would be supported:
\code
U1db.Query{
id: aQuery
index: by_helloworld
//query: "Hello*"
}
\endcode
But this would not:
\code
U1db.Query{
id: aQuery
index: by_helloworld
//query: "*World"
}
\endcode
Note: again, the 'query' property is commented out in the above two snippets due to its current status
\section1 Using Data
\section2 Data and the Application UI
\section3 Using Data With Models and Views
This simple snippet represents how to attach a ListModel to a ListView. In this instance the model 'aQuery' is representative of the Query + Index combination defined earlier:
\code
ListView {
width: units.gu(45)
height: units.gu(80)
model: aQuery
}
\endcode
\section4 Data and Delegates
How a model and ListView + delegates work together is a common QML concept, and not specific to U1Db-Qt. However, the asynchronous nature of this relationship is important to understand. When using QML ListView, delegates will be created based on particular properties such as the size of the application window, ListView, and delegate itself (amongst other factors). Each delegate can then represent a Document retrieved from the Database based on the record's index. This example demonstrates some of the property definitions that contribute to determining the number of delegates a ListView will contain:
\code
ListView {
width: units.gu(45)
height: units.gu(80)
model: aQuery
delegate: Text {
x: 66; y: 77
}
}
\endcode
When the number of Documents is less than or equal to the number of delegates then there is a one to one mapping of index to delegate (e.g. the first delegate will represent the Document with an index = 0; the second, index = 1; and so on).
When there are more Documents than delegates the ListView will request a new index depending on the situation (e.g. a user scrolls up or down). For example, if a ListView has 10 delegates, but 32 Documents to handle, when a user initially scrolls the first delegate will change from representing the Document with index = 0 to the Document that might have index = 8; the second, from index = 1 to index = 9; ...; the 10th delegate from index = 9 to index = 17. A second scrolling gesture the first index may change to 15, and the final index 24. And so on. Scrolling in the opposite direction will have a similar effect, but the Document index numbers for each delegate will obviously start to decline (towards their original values).
The following snippet, which modifies the above delegate definition, could demonstrate this effect if there were enough Documents to do so (i.e. some number greater than the number of delegates):
\code
ListView {
width: units.gu(45)
height: units.gu(80)
model: aQuery
delegate: Text {
x: 66; y: 77
text: index
}
}
\endcode
The object called 'contents' contains one or more properties. This example demonstrates the retrieval of data based on the U1db.Index defined earlier (id: by-helloworld). In this instance the Index contained two expressions simultaniously, "hello.world.id" and "hello.world.message"
\code
ListView {
width: units.gu(45)
height: units.gu(80)
model: aQuery
delegate: Text {
x: 66; y: 77
text: "(" + index + ") '" + contents.message + " " + contents.id + "'"
}
}
\endcode
*/
|