No backing script necessary.
<t:container {product}>
<table>
<thead>
<tr>
<td>Name</td>
<td>Price</td>
</tr>
</thead>
<tbody>
<tr {rows}>
<td>{name}</td>
<td>{price}</td>
</tr>
</tbody>
</table>
<p>Displaying {offset} to {offset+rows} of {count}.</p>
</t:container>
typeof product == "undefined"
==> http://localhost/
<< GET /product
SELECT count(*) FROM product
+ SELECT * FROM product ORDER BY 1 OFFSET 0 ROWS FETCH NEXT 100 ROWS ONLY
>> JSON {"count":...,"offset":...,"limit":...,"rows":[...]}
>> responseproduct = JSON.parse(responseBody)
Idea of putting instructions in a queue that is emptied on a time schedule.
Idea: the app developer can instantiate a framework-defined class to fetch a page of JavaScript objects corresponding persisted data (page has finite length, specified by the app developer, and is an array indexed by the result's in-page ordinal number). Changes to the JavaScript proxy objects are tracked (can be committed/fetched by function calls or on a time schedule). Changes to the page number are tracked as well. The framework would be able to convert the changes to the JavaScript objects into CRUD operations on a RESTful API.
var products = new CrudPage(50, "http://localhost:8080/api/products")
The CrudPage class has Observable properties corresponding each field of the JSON object that is expected in response to a GET request on the specified URL.
Setters of offset and limit will send a new GET request.
Proxy objects of the fetched rows are in the rows field.
Same as CrudPage but instead of limiting the result set by count, we fetch a predefined set of IDs. The proxy objects will be indexed by ID in a JavaScript object.
var userPreferences = CrudSet.of(["userName", "dob"], `http://localhost:8080/api/user/${uid}`)
Problem: when updating, the transaction should succeed only if there was no concurrent modification in the database between fetching and updating.
Solution:
Reponse to a READ request (multiple results)
{
"versionAlgorithm": "SHA-3-256",
"rows": [
{
"version": "d57f44aeb26cbe12577d46bde1f11dd189c30a59c3e07d8461f5aa2cdada90c7",
"id": 1000,
"content": {
"field1": 1,...
}
},...
]
}
Two clients request the same record. The record was not modified in between the two read requests. Both clients will get the same version code.
Next, one of these clients requests an UPDATE to this same record.
UPDATE request:
{
"versionAlgorithm": "SHA-3-256",
"version": "d57f44aeb26cbe12577d46bde1f11dd189c30a59c3e07d8461f5aa2cdada90c7",
"id": 1000,
"content": {
"field1": 20,...
}
}
Success. The version changes in the database.
The other client wants to UPDATE after this:
{
"versionAlgorithm": "SHA-3-256",
"version": "d57f44aeb26cbe12577d46bde1f11dd189c30a59c3e07d8461f5aa2cdada90c7",
"id": 1000,
"content": {
"field1": 101,...
}
}
Since this client did not notice the modification that happened concurrently, it sends the old version of the record.
Database checks version and notices mismatch. Sends error response. Refuses to do the modification.
Happy ending: the clients could not overwrite each other's changes.
Note: the structure described above is only for the request/response bodies, which is not reflected in the JavaScript objects (proxies, CrudPage properties, CrudSet properties, names appearing in a bracy template therefore stay the same as without concurrency awareness; e.g. things like {content}, {versionAlgorithm} are undefined.)
A lower level alternative for accessing a database. I'm not really a fan, I think that the construction of database queries belong to the backend's side but hey.
We need [Element Annotations] to make the pager/CRUD classes work in full declarative mode.