ScrewtopDB method
db().ScrewtopDB(initial)144 methods, 32 factory functions, 1 concepts, 45 REST endpoints. Generated from the screwtopdb-docs database.
db().ScrewtopDB(initial)addTopics({ text, instance: 'new', ...tags }) -> topicIdA name is not a key. Several distinct topic nodes may carry the same name, and
`topicByName` returns every one of them the caller can see -- each with its own
`topicId`. That is what instancing means in v2: identity is the node id, not an
ordinal.
Mint a distinct node by passing a spec with `instance: 'new'`. Both arities work,
and every key in the spec other than `text` and `instance` becomes a tag on the
new node:
db().addTopics({ text: 'blog-article', instance: 'new', status: 'draft' }).end();
db().addTopics({ text: 'blog-article', instance: 'new' }, 'status', 'draft').end();
Capture the returned `topicId` -- it is the only durable handle to that node:
db().addTopics({ text: 'blog-article', instance: 'new' }, 'status', 'draft')
.fn(function(ts) { articleId = ts[0].topicId; })
.end();
Read one node with `topicById(articleId)`, or narrow the by-name set with the
`hasTag` option -- `topicByName('blog-article', { hasTag: 'items' })` keeps only
the nodes carrying that tag, which is the usual way to pick the container out of a
set of same-named nodes. Delete one node with `deleteTopics(articleId)`.
Writes by an ambiguous name are refused rather than guessed: once a name has more
than one node, `addTopics('blog-article', tag, value)` is rejected. Pin the write
with the id instead -- `addTopics(articleId, tag, value)`.
There are no instance NUMBERS. The v1 model -- instance 0 as a shared public copy,
1 and higher as per-user copies, numbered monotonically and never reused -- went
away with the v1 engine, and with it the `instance` option, topicByNameAndInstance,
deleteInstance, and GET/DELETE /:app/instances.json/:text/:instance. The
`apiVersion` option is accepted and ignored, because the behaviour it used to
select is now unconditional.
db().topicByName(name, { via: ... })The **via** option turns a reader step (topicByName, topicById, findTopics) into a multi-level graph traversal. Each hop follows tag values to the referenced topics, optionally filtering along the way. The result set is replaced by the topics reached at the final hop.
**Shapes:**
- **String**: `via: "friends"` — a single outbound hop on the tag named "friends" (the whole string is one tag name; it is NOT split on dots).
- **Object**: `via: { tag: "friends", with: { age: { $gt: 18 } } }` — single hop with a filter.
- **Array**: `via: [{ tag: "friends" }, { tag: "employer", with: { region: "US" } }]` — explicit multi-hop list.
- **Inbound**: add `inbound: true` to a hop to traverse the reverse edge ("who references this topic?"): `via: { tag: "friends", inbound: true }`.
**Filtering with `with`:** a hop may carry a `with` object that keeps only destinations matching the given outbound tag:value pairs. Keys AND together. The filter key is `with` (NOT `filter`). Per-value operators:
- plain string — exact match
- `$not: X` — negation
- `$contains: "X"` — substring match
- `$gt` / `$gte` / `$lt` / `$lte: "X"` — comparison (numeric or lexicographic)
- `$none: X` — passes only when NO value on the tag matches X
- `$or: [ { tag: val }, ... ]` — OR across AND-clauses
**Returning edge values (`as: "values"`):** add `as: "values"` to the FINAL hop to return the traversed edge’s values instead of the destination topics.
**Shaping the result (`include`):** the `include` option applies only to the TERMINAL topics; intermediate hops always carry a full include so `with` filters can see every edge. `include` accepts CSV ("inbound,outbound") or an array (["inbound","outbound"]).
See also the related option **recursevia** for unbounded recursive traversal of a single tag name.
db().addTopics('AcmeViaOpt','members','alice').end()
db().topicByName('AcmeViaOpt', { via: 'members' })
.end(function(ts){ console.log(ts.map(function(t){return t.text;})); })
["alice"]
The via option (accepted by topicByName, topicById, findTopics, topics) declares a multi-hop graph traversal from the starting topic. Each hop follows an outbound tag and treats each value's text as a destination topic name.
Forms:
{via: "departments"} — single hop, no filter.{via: {tag: "departments", with: {region: "US"}}} — single hop with filter.{via: [{tag: "departments", with: {region: "US"}}, {tag: "members", with: {status: "active"}}]} — multi-hop.The optional with filters destinations by requiring matching outbound tag:value pairs. AND across keys. Operators inside with values: $not, $contains, $gt/$gte/$lt/$lte, $or, $none. Implemented at screwtopdbapi.js:2958-3032.
topicByName · findTopics · topics · topicById
db().appId(arg)Set or get the application ID to be used in subsequent query sequence steps.
ScrewtopDB applications have both a name and an ID. The application's creator specifies the application name
when the app is created with the ScrewtopDB Application Dashboard.
The app ID is assigned by the ScrewtopDB software. Retrieval by ID is slightly more efficient than
retrieval by name.
| Name | Type | Required | Description |
|---|---|---|---|
arg |
string | number | function(id) |
✓ | If this argument is a string or number then it is interpreted as the appID to set. If this argument is a function, it is invoked and passed as its single argument the currently set app ID. The return value of the function is ignored. |
db()
.appId(123)
.appId(function(id) {
alert("App ID is " + id + ".");
})
.end()
console.log(typeof db().appId);
function
console.log(typeof db().appId);
function
db().appName(arg)Set or get the application name to be used in subsequent query sequence steps.
ScrewtopDB applications have both a name and an ID. The application's creator specifies the application name
when the app is created with the ScrewtopDB Application Dashboard.
The app ID is assigned by the ScrewtopDB software. Retrieval by ID is slightly more efficient than
retrieval by name.
| Name | Type | Required | Description |
|---|---|---|---|
arg |
string | number | function(name) |
✓ | If this argument is a string or number then it is interpreted as the app name to set. If this argument is a function, it is invoked and passed as its single argument the currently set app name. The return value of the function is ignored. |
db()
.appName('myappname')
.appName(function(name) {
alert("App name is " + name + ".");
})
.end()
console.log(typeof db().appName);
function
console.log(typeof db().appName);
function
db().authentication(app, user, pswd)Set authentication information for use in later server interactions
Users must always log in to add or make changes to application database contents. Depending on
options set for the application, logging in may also be necessary to read database contents.
Authentication information is sent in plaintext and the session identifier assigned to the session
is afterward included in all requests. Thus, only secure connections (those starting with https://)
should be used for authenticated sessions. (This is the default for both authenticated and unauthenticated
requests, so generally you needn't be concerned unless you have specified an alternate URL for interaction
with ScrewtopDb.)
Note that when authentication information is set using this method, session timeouts are disabled.
This is an alternative to the login method. No server communication is performed by this method.
Use authentication when you know the user's credentials are valid to avoid an unnecessary server
interaction. Use login when it is necessary to confirm the validity of the user's credentials immediately,
or a session timeout must be set, or an app login is desired.
| Name | Type | Required | Description |
|---|---|---|---|
appIdOrName |
string |
✓ | The application with which to open the session. |
user |
string |
✓ | The username |
pswd |
string |
✓ | The password associated with the username |
db()
.authentication('<appname>', '<username>', '<password>')
.end();
console.log(typeof db().authentication);
function
console.log(typeof db().authentication);
function
db().login(appIdOrName, user, pswd, sessionTimeout, appLogin)Authenticate a user and create a session for further interaction.
Users must be authenticated to add or make changes to application database contents. Depending on
options set for the application, logging in may also be necessary to read database contents.
Authentication information is sent in plaintext and the session identifier assigned to the session
is afterward included in all requests. Thus, only secure connections (those starting with https://)
should be used for authenticated sessions. (This is the default for both authenticated and unauthenticated
requests, so generally you needn't be concerned unless you have specified an alternate URL for interaction
with ScrewtopDb.)
| Name | Type | Required | Description |
|---|---|---|---|
appIdOrName |
string |
✓ | The application with which to open the session. |
user |
string |
✓ | The username |
pswd |
string |
✓ | The password associated with the username |
sessionTimeout |
number |
Optional. The idle timeout in seconds desired for the session. The default is 10 minutes. The maximum allowed session timeout is 1 hour (3600 seconds.) |
|
appLogin |
boolean |
Optional. If true and the user is the responsible user, the session is created as the application itself, rather than the user logging in. This allows the responsible user to create, modify, and delete topics owned by the application and access and change application attributes. |
logout · authentication · appName · appId · session · offline
console.log(typeof db().login);
function
console.log(typeof db().login);
function
db().logout()End a ScrewtopDb session
console.log(typeof db().logout);
function
console.log(typeof db().logout);
function
db().setSession(session)Manually set the current session state from a previously obtained session object, bypassing the
normal login flow.
Sets the sessionId, appId, appName, username, userTopicId, and version from the provided session object.
Clears the password.
| Name | Type | Required | Description |
|---|---|---|---|
session |
object |
✓ | An object with properties: sessionId, appId,appName, username, userTopicId, version. |
// Save a session from one chain and restore it in another
var savedSession;
db()
.login('myApp', 'user', 'pass')
.session(function(sess) { savedSession = sess; })
.end();
// Later, in a different chain:
db()
.setSession(savedSession)
.topicByName('myTopic')
.end();
console.log(typeof db().setSession);
function
console.log(typeof db().setSession);
function
db().setVersion(ver)Set the API version number used for subsequent requests.
Updates the version at both the chain-local and global level. The version affects version-dependent
behavior such as tag text matching (e.g. how `./` and `../` prefixes are expanded).
| Name | Type | Required | Description |
|---|---|---|---|
ver |
number |
✓ | The API version number (e.g. 0 or 1). |
db.setVersion(1);
db().setVersion(2).end(function(){ console.log('ok'); })
ok
db().setVersion(2).end(function(){ console.log('ok'); })
ok
db().addTags(newTagText, newValueText, optionsObj)Add tag and value to each of the topics in the current result set.
| Name | Type | Required | Description |
|---|---|---|---|
newTagText |
string |
✓ | The new tag text |
newValueText |
string |
✓ | The new value text |
optionsObj |
object |
Options passed to the server that determine how the request is to be processed. Options are: - echoTopic - True to have the server include the value topic in its response. Note that the value topic returned includes only inbound tags. The default is true. If this option is false, the result set is replaced with an empty array. - private - True to have tags and values created by this operation be marked as private. Private tags and values are not accessible to users other than the owner. The default is false. - appUpdated - If false, causes the lastModified application attribute not to be updated as it would normally be. |
addTopics · addValues · updateValue · deleteTopics · deleteTags · deleteValues
db()
.addTopics('persons', 'friends', 'Raquel')
.addTags('coworkers', 'Billy', {echoTopic: false})
.topicByName('persons')
.tag('coworkers')
.addValues('Zenaida', {echoTopic: false})
.topicByName('persons')
.push()
.tag('friends')
.log('friends:')
.values().text().log()
.pop()
.tag('coworkers')
.log('coworkers:')
.values().text().log()
.end();
friends:
[
"Raquel"
]
coworkers:
[
"Billy",
"Zenaida"
]
db().addTopics('Alice', 'city', 'SF').end()
db().topicByName('Alice').addTags('age').end(function(){
db().topicByName('Alice').tags().end(function(ts){
console.log(ts.map(function(t){return t.text;}).sort());
});
})
["age","city"]
db().addTopics('addTags_t','seed','x').end()
db().topicByName('addTags_t').addTags('newtag').end(function(){ console.log('ok'); })
ok
console.log(typeof db().addTags);
function
db().addTopics(newData, newTagText, newValueText, optionsObj)Add a new topic to the screwtopDb database.
If the topic already exists, the tags and values are merged into the existing topic.
| Name | Type | Required | Description |
|---|---|---|---|
newData |
array|object|string |
✓ | This argument can be any of the following - An array of topics (objects containing tags members that contain values members, all of which contain text members). See example 1. - a single topic. See example 2. - an object (possibly with nested sub-objects) to be translated into a topic hierarchy array. See example 3. - a string that is the topic text. In this case, the second and third arguments must contain the tag text and value text, respectively. See example 4. |
newTagText |
string |
The tag text. Required when the first parameter is a string. | |
newValueText |
string |
The value text. Required when the first parameter is a string. | |
optionsObj |
object |
Options passed to the server that determine how the request is to be processed. Options are: - echoTopic - True to have the server include the new topic in its response. The default is true. If this option is false, the result set is replaced with an empty array. - private - True to have the topics, tags and values created by this operation be marked as private. Private topics, tags, and values are not accessible to users other than the owner. The default is false. - appUpdated - If false, causes the lastModified application attribute not to be updated as it would normally be. - addTagOwner - NOT IMPLEMENTED in v2, and will not be. It controlled a v1 convention in which tag ownership was expressed as a prefix on the tag NAME ( alice:notes), the server prefixing the creating user's name automatically;passing false let a privileged caller create a tag owned by someone else. v2 replaced name-prefix ownership with real access control -- owner and acl are carried on the edge itself and enforced by allowTag/allowValue -- sothere is no prefix to suppress. Passing this option has no effect. |
|
newData |
array|object|string |
✓ | Topic data: an array of topic objects, a single topic object, a JS object to translate to topic hierarchy, or a topic-name string (in which case newTagText and newValueText are required). |
newTagText |
string |
Tag text. Required when newData is a string. | |
newValueText |
string |
Value text. Required when newData is a string. | |
optionsObj |
object |
Options bag. See option-echoTopic, option-allowDuplicateValues, option-private. |
| Name | Type | Default | Description |
|---|---|---|---|
echoTopic |
boolean |
true |
If false the result set is replaced with an empty array; the new topic is not echoed back. |
allowDuplicateValues |
boolean |
false |
If true tags created by this operation allow duplicate values. |
private |
boolean |
false |
If true topics, tags and values created by this operation are private to the owner. |
addTags · addValue · updateValue · deleteTopic · deleteTag · deleteValue · updateTopic · addValues
//
// Insert an array of topics. Same-named topics merge.
//
var dbobjs = [];
dbobjs.push({ text: 'persons', tags: [{ text: 'friends', values: [{ text: 'Bill' }] }] });
dbobjs.push({ text: 'persons', tags: [{ text: 'friends', values: [{ text: 'Connie' }] }] });
db()
.addTopics(dbobjs, {echoTopic: true})
.topicByName('persons')
.values()
.text()
.log()
.end()
["Bill","Connie"]
//
// Insert a single topic.
//
var dbobj = {
text: 'persons',
tags: [{
text: 'friends',
values: [{ text: 'Bill' }, { text: 'Jeremy' }, { text: 'Shanika' }]
}]
};
db()
.addTopics(dbobj)
.topicByName('persons')
.values()
.text()
.log()
.end()
["Bill","Jeremy","Shanika"]
//
// Insert topics auto-generated from a plain Javascript object. Note that
// there are no tags/values members; the structure is translated. The inner
// 'personal data' object has no text field, so it gets an auto-generated
// unique topic name.
//
db()
.addTopics({
text: 'persons',
friends: [
'Dave',
{ text: 'Carrie', 'personal data': { city: 'New Orleans', spouse: 'Mitchell' } }
]
})
.topicByName('persons')
.tag('friends')
.values()
.each(function(friend) { alert(friend.text); })
.topicByName('Carrie')
.tagValues('personal data')
.topics()
.values()
.text()
.log()
.end();
Dave
Carrie
[
"New Orleans",
"Mitchell"
]
//
// The simplest way to add topics.
//
db()
.addTopics('persons', 'friends', 'Bill')
.addTopics('persons', 'friends', 'Carl')
.topicByName('persons')
.log('The values in the topic:')
.values()
.text()
.log()
.end();
The values in the topic:
[
"Bill",
"Carl"
]
db().addTopics('addTopics_t','tag1','val1').end(function(t){ console.log(t.length); })
1
db().addTopics('Alice', 'city', 'San Francisco')
.topicByName('Alice').values().text()
.end(function(t) { console.log(t); })
["San Francisco"]
db().addTopics([{ text: 'persons', tags: [
{ text: 'friends', values: [{text:'Bill'},{text:'Connie'}] }
]}]).topicByName('persons').values().text()
.end(function(t) { console.log(t); })
["Bill","Connie"]
db().addToValue(topicText, tagText, val, notifyId, sourceId)Atomically increase a numeric value.
The single value (or the first value if the tag contains multiple values) in the specified tag within
the specified topic is increased by a specified amount in a single operation, eliminating the possibility of a buried update.
The updated value is returned.
If the tag does not exist, it and the value (set to one) are created and the increase amount is returned.
The returned object replaces the current result set.
| Name | Type | Required | Description |
|---|---|---|---|
topicText |
string |
✓ | The topic text of the topic containing the value to be increased |
tagText |
string |
✓ | The text of the tag within the topic that contains the value to be increased. |
val |
integer |
✓ | The amount by which to increase the value |
notifyId |
string |
✓ | An identifier that designates the asynchronous notification subscribers to which a copy of the updated value should be transmitted. |
sourceId |
string |
✓ | An identifier to be included in asynchronous notifications intended to identify the client from which the update originated. |
addTopics · addTags · addValues · deleteTopics · deleteTags · deleteValues · decrementValue · incrementValue · subtractFromValue · setValue · vote · unvote · userVotes
db().addTopics('cnt','n','5').end()
db().addToValue('cnt','n',3).end(function(){
db().topicByName('cnt').tagValues('n').end(function(vs){ console.log(vs[0].text); });
})
8
console.log(typeof db().addToValue);
function
db().addValues(newValueText, optionsObj)Add a value to each of the tags in the current result set.
| Name | Type | Required | Description |
|---|---|---|---|
newValueText |
string |
✓ | The new value text |
optionsObj |
object |
Optional options bag (e.g. allowDuplicateValues, private). |
addTopics · addTags · updateValue · deleteTopics · deleteTags · deleteValues
db()
.addTopics('persons', 'friends', 'Raquel')
.addTags('coworkers', 'Billy', {echoTopic: false})
.topicByName('persons')
.tag('coworkers')
.addValues('Zenaida', {echoTopic: false})
.topicByName('persons')
.push()
.tag('friends')
.log('friends:')
.values().text().log()
.pop()
.tag('coworkers')
.log('coworkers:')
.values().text().log()
.end();
friends:
[
"Raquel"
]
coworkers:
[
"Billy",
"Zenaida"
]
db().addTopics('Alice', 'skill', 'js').end()
db().topicByName('Alice').tag('skill').addValues('py').end(function(){
db().topicByName('Alice').tagValues('skill').end(function(vs){
console.log(vs.map(function(v){return v.text;}).sort());
});
})
["js","py"]
db().addTopics('addValues_t','vtag','v1').end()
db().topicByName('addValues_t').tag('vtag').addValues('v2').end(function(){ console.log('ok'); })
ok
db().createValue(topicText, tagText, newValueText, options)Create or update a value.
Update the text of a value if it exists. Create the value (and topic and tag if necessary) if it does not exist.
This method cane be used to maintain a single value in a topic's tag, creating the topic and/or tag if necessary
the first time it is invoked, eliminating the need to first check if a value exists before attempting to update
it.
This method does not update the local cache. Thus, invalidation of the cache is necessary if the new value is
to be retrieved after an update using this method. The updateValue method might be a
better choice in this case.
This method does not alter the result set.
| Name | Type | Required | Description |
|---|---|---|---|
topicText |
string |
✓ | The topic in which to replace or create the value. |
tagText |
string |
✓ | The tag in wbhich to replace or create the value. |
newValueText |
string |
✓ | The new text to replace the existing value text, if any. |
options |
object |
Optional. The only valid options for this method are appupdated and private. If appupdated is false, this causes the lastModified application attribute not to be updated as it would normally be. If private is true, the value created or updated will be private. If private is false, the value will be public, even if it was previously private. |
addTopics · addTags · addValues · updateValue · deleteTopics · deleteTags · deleteValues
db()
.createValue('Jane', 'friend', 'Raquel')
.topicByName('Jane')
.tagValues('friend')
.text()
.log()
.invalidateCache()
.createValue('Jane', 'friend', 'Raquella')
.topicByName('Jane')
.tagValues('friend')
.text()
.log()
.end();
[
"Raquel"
]
[
"Raquella"
]
db().addTopics('cnt','color','red').end()
db().createValue('cnt','size','large').end(function(){
db().topicByName('cnt').tagValues('size').end(function(vs){
console.log(vs.map(function(v){return v.text;}));
});
})
["large"]
console.log(typeof db().createValue);
function
db().decrementValue(topicText, tagText, notifyId, sourceId)Atomically decrement a numeric value.
The single value (or the first value if the tag contains multiple values) in the specified tag within
the specified topic is decremented in a single operation, eliminating the possibility of a buried update.
The value is not allowed to fall below zero.
The updated value is returned. If the value was zero before the attempt to decrement it, the value is unchanged,
but -1 is returned to indicate that no actual decrement of the value occurred.
If the tag does not exist, it and the value (set to zero) are created and -1 is returned.
The returned object replaces the current result set.
| Name | Type | Required | Description |
|---|---|---|---|
topicText |
string |
✓ | The topic text of the topic containing the value to be decremented |
tagText |
string |
✓ | The tag text of the value to be decremented. |
notifyId |
string |
✓ | An identifier that designates the asynchronous notification subscribers to which a copy of the updated value should be transmitted. |
sourceId |
string |
✓ | An identifier to be included in asynchronous notifications intended to identify the client from which the update originated. |
addTopics · addTags · addValues · deleteTopics · deleteTags · deleteValues · incrementValue · vote · unvote · userVotes
function show(r) { console.log(r.data.value); }
db()
.incrementValue('counter', 'n').fn(show)
.incrementValue('counter', 'n').fn(show)
.decrementValue('counter', 'n').fn(show)
.decrementValue('counter', 'n').fn(show)
.end();
1
2
1
0
db().addTopics('cnt','n','5').end()
db().decrementValue('cnt','n').end(function(){
db().topicByName('cnt').tagValues('n').end(function(vs){ console.log(vs[0].text); });
})
4
console.log(typeof db().decrementValue);
function
db().deleteInstance(topicText, instance)REMOVED in v2, along with the instance numbers it took. The method is still on the
chain, and its result-set form still looks for `topic.instance`, but v2 frames carry
no such field and the server answers DELETE /:app/instances.json/:text/:instance
with HTTP 409 -- so the call silently does nothing.
Delete one node with `deleteTopics(topicId)`. `topicByName(name)`, optionally with
`hasTag`, enumerates the ids. See Topic Instancing (concept).
console.log(typeof db().deleteInstance);
function
db().deleteTags(tagIds, options)Delete tags in the result set from the ScrewtopDB database
Tags are deleted using a cascade delete operation. This means that the tag and all the
values contained in the tags are deleted. Then any topics
named by the deleted values are deleted if they contain no inbound tags (i.e. they are not referenced
by any remaining topic.) This process continues until there are no unreferenced topics left that were
reachable via outbound tags from the starting topics.
If you want to retain topics referenced only by topics you intend to delete, add a tag to a topic that
will not be deleted with a value referring to the topic you wish to retain. Often, the user topic is a
convenient topic in which to place such a tag.
Topics will not be deleted if they contain a tag owned by a user other than the deleting user. Instead,
all tags owned by the deleting user will be deleted from the topic. An exception to this rule is made for
unique topics. Unique topics owned by the deleting user are deleted regardless of whether they contain
tags owned by another user.
Note that if you delete all the tags of a topic, the topic will automatically be deleted as well.
The argument may also be a FUNCTION returning an id or an array of ids. Chain
arguments are evaluated when the chain is BUILT, so an id captured by an earlier
`.fn()` in the same chain is still undefined by the time a plain argument is read;
a function is called when the step RUNS, which is when the id exists. A function
that returns nothing deletes nothing.
| Name | Type | Required | Description |
|---|---|---|---|
tagIds |
string|array |
Optional. If this parameter is present, it is assumed to contain a tag ID or an array of tag IDs to be deleted and is used instead of the current result set as the source of tag IDs to delete. |
|
options |
object |
Optional. The only valid option for this method is appupdated. If false, this causes the lastModified application attribute not to be updated as it would normally be. |
db().addTopics({text:'persons',friends:[{text:'Andy',gender:'male'},{text:'Mary',gender:'female',spouse:'Bill'},{text:'Bill',gender:'male',spouse:'Mary'}],coworkers:[{text:'Frank',gender:'male'},{text:'Wendy',gender:'female'}]}).end()
db()
.topicByName('persons')
.push()
.tags()
.text()
.log()
.pop()
.tag('friends')
.deleteTags()
.topicByName('persons')
.tags()
.text()
.log()
.end();
[
"friends",
"coworkers"
]
[
"coworkers"
]
db().addTopics('Alice','city','SF').end()
db().topicByName('Alice').tag('city').deleteTags().end(function(){
db().topicByName('Alice').tags().end(function(ts){ console.log(ts.length); });
})
0
db().addTopics('deleteTags_t','x','1').end()
db().topicByName('deleteTags_t').tag('x').deleteTags().end(function(){
db().topicByName('deleteTags_t').tags().end(function(ts){
console.log(ts.filter(function(t){return t && t.tagType !== 'inbound';}).length);
});
})
0
db().deleteTopics(topicIds, options)Delete topics in the result set from the ScrewtopDB database
Topics are deleted using a cascade delete operation. This means that the topics, all the
tags contained in the topics, and all the values contained in the tags are deleted. Then any topics
named by the deleted values are deleted if they contain no inbound tags (i.e. they are not referenced
by any remaining topic.) This process continues until there are no unreferenced topics left that were
reachable via outbound tags from the starting topics.
If you want to retain topics referenced only by topics you intend to delete, add a tag to a topic that
will not be deleted with a value referring to the topic you wish to retain. Often, the user topic is a
convenient topic in which to place such a tag.
Topics will not be deleted if they contain a tag owned by a user other than the deleting user. Instead,
all tags owned by the deleting user will be deleted from the topic. An exception to this rule is made for
unique topics. Unique topics owned by the deleting user are deleted regardless of whether they contain
tags owned by another user.
With no `topicIds` argument the ids come from the result set: each element
contributes its `topicId`, and an element that IS a bare topic id (a ULID, as
left by `.fn(function(ts) { return ts[0].topicId; })`) is taken as that id --
the same address form the `topicIds` argument accepts. Elements carrying no
topic id contribute nothing, so a result set holding tags, values or plain
strings deletes nothing rather than issuing a delete for a missing id.
The argument may also be a FUNCTION returning an id or an array of ids. Chain
arguments are evaluated when the chain is BUILT, so an id captured by an earlier
`.fn()` in the same chain is still undefined by the time a plain argument is read;
a function is called when the step RUNS, which is when the id exists. A function
that returns nothing deletes nothing.
| Name | Type | Required | Description |
|---|---|---|---|
topicIds |
string|array |
Optional. If this parameter is present, it is assumed to contain a topic ID or an array of topic IDs to be deleted and is used instead of the current result set as the source of topic IDs to delete. |
|
options |
object |
Optional. The only valid option for this method is appupdated. If false, his causes the lastModified application attribute not to be updated as it would normally be. |
db().addTopics({text:'persons',friends:[{text:'Andy',gender:'male'},{text:'Mary',gender:'female',spouse:'Bill'},{text:'Bill',gender:'male',spouse:'Mary'}],coworkers:[{text:'Frank',gender:'male'},{text:'Wendy',gender:'female'}]}).end()
db()
.topicByName('persons')
.tags()
.text()
.log()
.topicByName('persons')
.deleteTopics()
.topicByName('persons')
.fn(function(ts) { console.log('after delete: ' + ts.length); })
.end();
[
"friends",
"coworkers"
]
after delete: 0
db().addTopics('Junk','x','1').end()
db().topicByName('Junk').deleteTopics().end(function(){
db().topicByName('Junk').end(function(ts){ console.log(ts.length); });
})
0
db().addTopics('deleteTopics_t','x','1').end()
db().topicByName('deleteTopics_t').deleteTopics().end(function(){
db().topicByName('deleteTopics_t').end(function(ts){ console.log(ts.length); });
})
0
db().deleteValues(valueIds, options)Delete values in the result set from the ScrewtopDB database
Values are deleted using a cascade delete operation. This means that the
values are deleted and then any topics
named by the deleted values are deleted if they contain no inbound tags (i.e. they are not referenced
by any remaining topic.) This process continues until there are no unreferenced topics left that were
reachable via outbound tags from the starting topics.
If you want to retain topics referenced only by topics you intend to delete, add a tag to a topic that
will not be deleted with a value referring to the topic you wish to retain. Often, the user topic is a
convenient topic in which to place such a tag.
Topics will not be deleted if they contain a tag owned by a user other than the deleting user. Instead,
all tags owned by the deleting user will be deleted from the topic. An exception to this rule is made for
unique topics. Unique topics owned by the deleting user are deleted regardless of whether they contain
tags owned by another user.
Note that if you delete all the values of a tag, the tag will automatically be deleted as well.
The current result set is unaffected by this method.
| Name | Type | Required | Description |
|---|---|---|---|
valueIds |
string|array |
Optional. If this parameter is present, it is assumed to contain a value ID or an array of value IDs to be deleted and is used instead of the current result set as the source of value IDs to delete. |
|
options |
object |
Optional. The only valid option for this method is appupdated. If false, this causes the application attribute not to be updated as it would normally be. |
db().addTopics({text:'persons',friends:[{text:'Andy',gender:'male'},{text:'Mary',gender:'female',spouse:'Bill'},{text:'Bill',gender:'male',spouse:'Mary'}],coworkers:[{text:'Frank',gender:'male'},{text:'Wendy',gender:'female'}]}).end()
db()
.topicByName('persons')
.push()
.values()
.text()
.log()
.pop()
.tag('friends')
.values()
.deleteValues()
.topicByName('persons')
.values()
.text()
.log()
.end();
[
"Andy",
"Mary",
"Bill",
"Frank",
"Wendy"
]
[
"Frank",
"Wendy"
]
db().addTopics('Alice','city','SF').end()
db().topicByName('Alice').tagValues('city').deleteValues().end(function(){
db().topicByName('Alice').tagValues('city').end(function(vs){ console.log(vs.length); });
})
0
db().addTopics('deleteValues_t','x','v').end()
db().topicByName('deleteValues_t').tagValues('x').deleteValues().end(function(){
db().topicByName('deleteValues_t').tagValues('x').end(function(vs){ console.log(vs.length); });
})
0
db().findTopics(topicText, options)Fetch topics whose name matches a regular expression -- not a shell glob. The pattern matches anywhere in the name, so 'milk' finds 'shopping milk list'; anchor it with ^ and/or $ to pin the match to the start or end of the name. Note that 'user:*' is NOT a glob: read as a regex it means "user" followed by zero or more colons, so it matches every name containing "user" -- write '^user:' instead.
The topics fetched are passed to the following query sequence step as an array. If no topics were
found, an empty array is passed.
This function will initiate a request to the ScrewtopDB server regardless of whether the topics are already in cache.
| Name | Type | Required | Description |
|---|---|---|---|
topicText |
string |
✓ | The name (i.e. the topicText) of the topic to fetch |
options |
object |
Optional. An object containing option names and values to be passed with the request. Any combination of the following options may be included: - include - Specify any combination of: "outbound" to include outbound tags, "inbound" to include inbound tags, "allTopics" to include all topics containing the topicText parameter as a tag, and "allValues" to include all values in tags named with the topicText parameter. The default is "outbound". - via - Multi-level graph traversal. Either a string (e.g. "friends.name") for simple hops, or anobject/array describing one or more hops with per-hop filters. Each hop may specify a tag name, filter expression, and direction ( { inbound: true } for reverse-direction traversal). Filter expressions support the operators$eq, $contains, $not, $none, $gt, $lt,$or, $and, and $regex. The result set is replaced by the topics reached at thefinal hop. See via option for full syntax. - recursevia - Recursively adds topics to the result array (which would otherwise contain a single topic) that are encountered by retrieving the topics of values found in tags matching the value of the recursevia option. Applies only to outbound tags. (The legacy name recurseVia is also accepted.)- instance - NOT IMPLEMENTED in v2, and will not be. It selected an instance by ORDINAL, a v1 model where instance 0 was the shared public copy and 1+ were per-user copies. v2 instancing is identity-based rather than ordinal: a distinct same-named node is minted with instance:'new' and addressed thereafter by its ULID. There isno ordinal to select by; to read one specific instance, address it by id. - apiVersion - Accepted and ignored by the v2 server, because the behaviour it selected is now unconditional: a name resolves to EVERY node carrying it (topicByName hydrates each and returns them as a list), so a response already describes all visible instances. There is no single-instance mode to fall back to. Expect data to be alist; do not assume it holds exactly one topic, though for names never explicitly instanced it always will. - excludeValueText True to exclude the text member of value objects. This is used to reduce the amount of data returned when the value text is not needed. - elide True to omit tag-value text from the response for tags whose values are themselves topic references (i.e. pure linking tags), reducing payload size. Value objects still include topicId and valueId. - fromcache True to return a cached copy of the topic if available, skipping the server request entirely. Useful for patterns that want to consult the cache without triggering network I/O. - valueFilter A comma-separated list of strings. If any of the strings matches a value in the topic, that value will be returned. Values whose text does not match one of the valueFilter strings provided are not returned. - tagFilter A comma-separated list of tag names; only the matching tags are returned (the topic itself is returned even when none match). A name may be owner-qualified, IW style: owner/name keeps only that owner's tag, ./name the caller's own, <appName>/name any owner's. A value written as a regular expression (e.g. ^(question|answer)$) is matched as a regex instead.- page The zero-based number of the data page to return or a comma-separated two-element list where the first element is the zero-based page number to return and the second element is the number of elements per page. Note that totalCount, pageSize, and pageNumber members are returned in the returned topic. |
db().addTopics('member:alice','login count','5').addTopics('member:bob','login count','3').end()
db()
.findTopics('member:')
.fn(function(topics) {
console.log(topics.map(function(t){return t.text;}).sort());
})
.end();
["member:alice","member:bob"]
db().addTopics('alpha-1','x','1').addTopics('alpha-2','x','2').end()
db().findTopics('alpha').end(function(ts){ console.log(ts.map(function(t){return t.text;}).filter(function(t){return /^alpha-/.test(t);}).sort()); })
["alpha-1","alpha-2"]
db().addTopics('findTopics_t_zebra','x','1').addTopics('findTopics_t_zelda','x','2').end()
db().findTopics('findTopics_t_z').end(function(ts){
console.log(ts.filter(function(t){return /^findTopics_t_z/.test(t.text);}).length);
})
2
findTopicsByTag(tagName, valueText)List topics that carry a specific tag:value combination. Returns an array of stub
objects {text, topicInstance, topicId} -- one per source topic node that has
tagName=valueText. Follow up with topicById(topicId) for the full topic. The
`topicInstance` field is a v1 vestige and is always 0 in v2; `topicId` is the handle
that actually addresses the node.
Use this instead of findTopics(regex) when you want "topics where tag = value" (the
schema-correct enumeration). findTopics(regex) is a substring/regex search of topic
names with a default page size of 100 -- a different operation. Implemented by
walking the inbound tagName slot on the topic named valueText, so it is correct even
when several distinct nodes share the source name.
| Name | Type | Required | Description |
|---|---|---|---|
tagName |
string |
✓ | Tag name to match. |
valueText |
string |
✓ | Tag value to match. |
db().addTopics('Alice','role','admin')
.addTopics('Bob','role','admin')
.addTopics('Carol','role','user').end()
db().findTopicsByTag('role','admin')
.end(function(stubs){
console.log(stubs.map(function(s){return s.text;}).sort());
})
["Alice","Bob"]
db().ftsBuildIndex()Trigger a full (re)build of the native FTS index for the current app. Issues POST `/:app/fts.json`.
Result set becomes `[{ count, durationMs }]`. Usually only needed the first time FTS is used against an
app, or after a mass import that bypassed the normal topic-creation path.
db().addTopics('Alpha','x','1').end()
db().ftsBuildIndex().end(function(){ console.log('ok'); })
ok
db().ftsSearch(query, options)Run a native full-text search over the current app's topics. The result set is replaced with an array of hit
objects of the form `{ topic_id, topicId, text, rank }`, which composes directly with
topics or topicById to fetch the full topic records.
Uses the server's LevelDB-backed FTS5 index. The index is maintained incrementally as topics/tags/values are
added or modified. If the index is missing or stale for an app, call ftsBuildIndex
first. Check availability with ftsStatus.
| Name | Type | Required | Description |
|---|---|---|---|
query |
string |
✓ | FTS5-style query. Tokens are AND-ed together by default. Use the mode option to switch to OR. A trailing * enables prefix matching on the final token. |
options |
object |
Optional. Members: - limit - maximum hits to return (server default applies if omitted). - mode - "AND" (default) or "OR" combining of tokens. - impl - "native" (default) to use the LevelDB-backed index, or "sqlite" to route through the legacy SQLite add-on. |
|
query |
string |
✓ | FTS5-style query. Tokens are AND-ed together by default. Use the mode option to switch to OR. A trailing * enables prefix matching on the final token. |
opts |
object |
Optional: { limit, mode } where mode is "AND" or "OR". |
db()
.appName('<appname>')
.ftsSearch('hello world', { limit: 20 })
.topics()
.each(function(t) { console.log(t.topicText(), t.rank); })
.end();
db().addTopics('ftsSearch_t_apple','x','1').addTopics('ftsSearch_t_apricot','x','2').end()
db().ftsSearch('ftsSearch_t').end(function(rs){
console.log(rs.filter(function(t){return /^ftsSearch_t/.test(t.text);}).length >= 2);
})
true
db().addTopics('Apollo Mission', 'year', '1969')
.addTopics('Apollo Theater', 'city', 'Harlem').end()
db().ftsSearch('apollo')
.end(function(rs) {
console.log(rs.map(function(t) { return t.text; }).sort());
})
["Apollo Mission","Apollo Theater"]
db().ftsStatus()Report whether the native FTS index is available for the current app, and summarize corpus statistics. The result
set is replaced with a single-element array `[{ available, N, dlSum, loaded, impl }]` where
`N` is the document count and `dlSum` is the total token count.
db().ftsStatus().each(function(s) {
if (!s.available) db().ftsBuildIndex().end();
}).end();
db().ftsStatus().end(function(s){ console.log(typeof s); })
object
db().incrementValue(topicText, tagText, notifyId, sourceId)Atomically increment a numeric value.
The single value (or the first value if the tag contains multiple values) in the specified tag within
the specified topic is incremented in a single operation, eliminating the possibility of a buried update.
The updated value is returned.
If the tag does not exist, it and the value (set to one) are created and 1 is returned.
The returned object replaces the current result set.
| Name | Type | Required | Description |
|---|---|---|---|
topicText |
string |
✓ | The topic text of the topic containing the value to be decremented |
tagText |
string |
✓ | The tag text of the value to be incremented. |
notifyId |
string |
✓ | An identifier that designates the asynchronous notification subscribers to which a copy of the updated value should be transmitted. |
sourceId |
string |
✓ | An identifier to be included in asynchronous notifications intended to identify the client from which the update originated. |
addTopics · addTags · addValues · addToValue · subtractFromValue · setValue · deleteTopics · deleteTags · deleteValues · decrementValue · vote · unvote · userVotes
function show(r) { console.log(r.data.value); }
db()
.incrementValue('counter', 'n').fn(show)
.incrementValue('counter', 'n').fn(show)
.decrementValue('counter', 'n').fn(show)
.decrementValue('counter', 'n').fn(show)
.end();
1
2
1
0
db().addTopics('cnt','n','1').end()
db().incrementValue('cnt','n').end(function(){
db().topicByName('cnt').tagValues('n').end(function(vs){ console.log(vs[0].text); });
})
2
console.log(typeof db().incrementValue);
function
db().moveTag(insertBeforeTagId, valueId)Relocate a tag within its topic's tag list.
Moving is a modification: the caller must be allowed to modify the topic (its owner, an ACL grant, the app's responsible user, or the super-admin) or must own the tag being moved. Otherwise the server refuses with 403.
This method replaces the current result set with the updated topic.
Note that this method is ineffective in deferredWrite mode.
| Name | Type | Required | Description |
|---|---|---|---|
insertBeforeTagId |
string |
✓ | The tag ID before which to insert the tag being moved. |
tagId |
string |
✓ | The tag ID of the value to be moved. |
console.log(typeof db().moveTag);
function
console.log(typeof db().moveTag);
function
db().moveValue(insertBeforeValueId, valueId, optionsObj)Relocate a value within its tag's value list.
Moving is a modification: the caller must be allowed to modify the value (its owner, an ACL grant, the app's responsible user, or the super-admin) or must own the tag it is in. Otherwise the server refuses with 403.
This method replaces the current result set with the updated topic.
Note that this method is ineffective in deferredWrite mode.
| Name | Type | Required | Description |
|---|---|---|---|
insertBeforeValueId |
string |
✓ | The value ID before which to insert the value being moved. |
valueId |
string |
✓ | The value ID of the value to be moved. |
console.log(typeof db().moveValue);
function
console.log(typeof db().moveValue);
function
db().notify(notificationId, obj)Publish an arbitrary payload to all SSE subscribers of a given notificationId within the current app. Use this to
fan out application-level events (not bound to topic changes) to connected clients.
| Name | Type | Required | Description |
|---|---|---|---|
notificationId |
string |
✓ | The SSE channel identifier. Subscribers opened an EventSource at /:app/events/<notificationId>. |
obj |
any |
✓ | JSON-serializable payload. |
console.log(typeof db().notify);
function
db().setValue(topicText, tagText, val, notifyId, sourceId)Atomically set a numeric value.
The single value (or the first value if the tag contains multiple values) in the specified tag within
the specified topic is set to the value specified in a single operation, eliminating the possibility of a buried update.
The updated value is returned.
If the tag does not exist, it and the value (set to one) are created and the specified value is returned.
The returned object replaces the current result set.
| Name | Type | Required | Description |
|---|---|---|---|
topicText |
string |
✓ | The topic text of the topic containing the value to be decreased |
tagText |
string |
✓ | The tag text of the value to set. |
val |
integer |
✓ | The amount by which to increase the value |
notifyId |
string |
✓ | An identifier that designates the asynchronous notification subscribers to which a copy of the updated value should be transmitted. |
sourceId |
string |
✓ | An identifier to be included in asynchronous notifications intended to identify the client from which the update originated. |
addTopics · addTags · addValues · deleteTopics · deleteTags · deleteValues · decrementValue · incrementValue · addToValue · subtractFromValue · vote · unvote · userVotes
db().addTopics('cnt','n','1').end()
db().setValue('cnt','n','9').end(function(){
db().topicByName('cnt').tagValues('n').end(function(vs){ console.log(vs[0].text); });
})
9
console.log(typeof db().setValue);
function
db().subtractFromValue(topicText, tagText, val, notifyId, sourceId)Atomically decrease a numeric value.
The single value (or the first value if the tag contains multiple values) in the specified tag within
the specified topic is decreased by a specified amount in a single operation, eliminating the possibility of a buried update.
The updated value is returned.
If the tag does not exist, it and the value (set to one) are created and the negative amount is returned.
The returned object replaces the current result set.
| Name | Type | Required | Description |
|---|---|---|---|
topicText |
string |
✓ | The topic text of the topic containing the value to be decreased |
tagText |
string |
✓ | The tag text of the value to subtract from. |
val |
integer |
✓ | The amount by which to increase the value |
notifyId |
string |
✓ | An identifier that designates the asynchronous notification subscribers to which a copy of the updated value should be transmitted. |
sourceId |
string |
✓ | An identifier to be included in asynchronous notifications intended to identify the client from which the update originated. |
addTopics · addTags · addValues · deleteTopics · deleteTags · deleteValues · decrementValue · incrementValue · addToValue · setValue · vote · unvote · userVotes
db().addTopics('cnt','n','10').end()
db().subtractFromValue('cnt','n',4).end(function(){
db().topicByName('cnt').tagValues('n').end(function(vs){ console.log(vs[0].text); });
})
6
console.log(typeof db().subtractFromValue);
function
db().topicById(topicId, options)Fetch a topic given its ID.
This step passes its result set (an array of topic objects) to the next step.
Typically, there will be zero or one element in the array.
An options object may be included that specifies any combination of the following options:
- **include** - Specify any combination of: "outbound" to include outbound tags, "inbound" to include inbound tags, "allTopics"
to include all topics containing the topicText parameter as a tag, and "allValues" to include all values in tags named with
the topicText parameter. The default is "outbound".
- **via** - Multi-level graph traversal. Either a string (e.g. `"friends.name"`) for simple hops, or an
object/array describing one or more hops with per-hop filters. Each hop may specify a tag name, filter expression, and
direction (`{ inbound: true }` for reverse-direction traversal). Filter expressions support the operators
`$eq`, `$contains`, `$not`, `$none`, `$gt`, `$lt`,
`$or`, `$and`, and `$regex`. The result set is replaced by the topics reached at the
final hop. See via option for full syntax.
- **recursevia** - Recursively adds topics to the result array (which would otherwise contain a single topic) that
are encountered by retrieving the topics of values found in tags matching the value of the recursevia option. Applies
only to outbound tags. (The legacy name `recurseVia` is also accepted.)
- **instance** - NOT IMPLEMENTED in v2, and will not be. It selected an instance by ORDINAL, a v1 model where
instance 0 was the shared public copy and 1+ were per-user copies. v2 instancing is identity-based rather than
ordinal: a distinct same-named node is minted with `instance:'new'` and addressed thereafter by its ULID. There is
no ordinal to select by; to read one specific instance, address it by id.
- **apiVersion** - Accepted and ignored by the v2 server, because the behaviour it selected is now unconditional: a
name resolves to EVERY node carrying it (topicByName hydrates each and returns them as a list), so a response
already describes all visible instances. There is no single-instance mode to fall back to. Expect `data` to be a
list; do not assume it holds exactly one topic, though for names never explicitly instanced it always will.
Ths function will initiate a request to the ScrewtopDB server if the topic requested is not in cache with the options
specified.
| Name | Type | Required | Description |
|---|---|---|---|
topicId |
string |
✓ | The topicId of the topic to fetch |
options |
object |
Optional. An object containing option names and values to be passed with the request. |
db().addTopics('Alice', 'city', 'SF').end()
db().topicByName('Alice').end(function(ts){
db().topicById(ts[0].topicId).end(function(ts2){ console.log(ts2[0].text); });
})
Alice
db().addTopics('topicById_t','x','v').end()
db().topicByName('topicById_t').end(function(ts){
db().topicById(ts[0].topicId).end(function(ts2){ console.log(ts2[0].text); });
})
topicById_t
db().topicByName(topicText, options)Fetch a topic given its name (i.e. its topicText).
The topic fetched is passed to the following query sequence step as a single element array. If the topic was not
found, an empty array is passed.
This function will initiate a request to the ScrewtopDB server if the topic requested is not in cache with the options
specified.
| Name | Type | Required | Description |
|---|---|---|---|
topicText |
string|function |
✓ | The name (topicText) of the topic to fetch. May also be a function returning the name, or an array of names. |
options |
object |
Optional. Options bag passed with the request (via, with, hasTag, include, recursevia, apiVersion, valueFilter, tagFilter, page). | |
topicText |
string |
✓ | The name (topicText) of the topic to fetch. |
options |
object |
Optional bag with via, hasTag, recurseVia, include, fromcache, apiVersion, valueFilter, tagFilter, page. |
| Name | Type | Default | Description |
|---|---|---|---|
via |
String|Object|Array |
undefined |
Multi-hop graph traversal. Follows outbound tag values from the starting topic. Accepts a string (single tag), an object {tag, with}, or an array of objects for multi-hop. The optional "with" property filters destinations by matching outbound tag:value pairs (AND across keys; supports $not, $contains, $gt/$lt, $or, $none). |
include |
string |
outbound |
Comma-separated combination of: outbound, inbound, allTopics, allValues. |
recursevia |
string |
undefined |
Recursively follow outbound tags matching the given name; returns the full set. |
fromcache |
boolean |
false |
If true, only consult the local cache; do not contact the server. |
apiVersion |
number |
ignored |
Accepted and ignored by the v2 server. The behaviour it used to select is now unconditional: a name resolves to EVERY node carrying it, so a response already describes all visible instances. Expect a list; do not assume it holds exactly one topic, though for names never explicitly instanced it always will. |
hasTag |
String |
undefined |
A tag name. Keeps only topics carrying an outbound tag with exactly this name. topicByName returns the full set of same-named topics, so hasTag selects the ones playing a given role — e.g. the container instance among same-named topics, or whether a shared value topic also acts as a container. Combines with via (filters the traversal's starting topics). v2 server only; the v1 engine ignores it. |
db().addTopics({text:'persons',friends:[{text:'Andy',gender:'male'},{text:'Mary',gender:'female',spouse:'Bill'},{text:'Bill',gender:'male',spouse:'Mary'}],coworkers:[{text:'Frank',gender:'male'},{text:'Wendy',gender:'female'}]}).end()
db()
.topicByName('persons')
.fn(function(topics) {
console.log(topics[0].text + ' has ' + topics[0].tags.length + ' tags');
})
.end();
persons has 2 tags
db().addTopics('Alice', 'city', 'SF').end()
db().topicByName('Alice').end(function(ts){ console.log(ts[0].text); })
Alice
db().addTopics('Alice', 'city', 'Berkeley').end()
db().topicByName('Alice').end(function(ts) { console.log(ts[0].text); })
Alice
db().addTopics('Alice', 'employer', 'Acme')
.addTopics('Acme', 'city', 'Oakland').end()
db().topicByName('Alice', { via: 'employer' })
.tag('city').values().text()
.end(function(v) { console.log(v); })
["Oakland"]
db().addTopics('release-1.0', 'tickets', 'fix login timeout')
.addTopics('fix login timeout', 'owner', 'Ann').end()
// 'fix login timeout' is both a ticket VALUE under release-1.0 and a topic
// in its own right. hasTag asks: does this topic carry the 'owner' role?
db().topicByName('fix login timeout', { hasTag: 'owner' })
.fn(function(ts) { console.log('with owner: ' + ts.length); })
.topicByName('release-1.0', { hasTag: 'owner' })
.fn(function(ts) { console.log('with owner: ' + ts.length); })
.end();
with owner: 1
with owner: 0
db().topicByNameAndInstance(topicText, instance, options)REMOVED in v2. It addressed an instance by ORDINAL, and ordinals no longer exist:
a name resolves to a set of distinct nodes identified by `topicId`, not to a
numbered series. The method is still on the chain, but the server answers
GET /:app/instances.json/:text/:instance with HTTP 409 and the call yields an
empty result set.
Use `topicById(topicId)` to fetch one specific node, or `topicByName(name)` for the
whole same-named set -- the `hasTag` option narrows that set to the nodes playing a
given role. See Topic Instancing (concept).
| Name | Type | Required | Description |
|---|---|---|---|
topicText |
string |
✓ | The name of the topic to fetch. |
instance |
integer |
REMOVED in v2. There is no ordinal to pass; address a node by its topicId. | |
options |
object |
Optional. Same options as topicByName. |
db().addTopics('Color','rgb','red').end()
db().topicByName('Color').fn(function(ts){ return ts; }).end(function(ts){ db().topicById(ts[0].topicId).end(function(t){ console.log(t[0].text); }); })
Color
console.log(typeof db().topicByNameAndInstance);
function
db().topics(arg1, arg2)Add a query step to fetch the topics identified by the topicId properties of the current result set.
This step passes its result set (an array of values) to the next step.
The options parameter may specify one or more include specifications. The possible specifications are:
- **outbound** - These are the tags that were explicitly specified by the user who added the tag or created the topic.
- **inbound** - Inbound tags are the reverse of outbound tags. The values of the inbound tags of topic A are the topics
that contain an outbound tag containing a value referencing topic A.
- **allvalues** - The allvalues specification, when applied to a tag topic (i.e. the topic created for the tag when the
tag is first used), returns the tag named values whose value array contains all the values contained in the tag
in all topics in which it occurs.
- **alltopics** - The alltopics specification, when applied to a tag topic (i.e. the topic created automatically for
the tag when it is first used), returns in the topics tag all the topics that contain the tag.
Note that the parameters of this method are accepted in any order. This to allow either parameter to be included without requiring
the other.
| Name | Type | Required | Description |
|---|---|---|---|
arg1 |
string |
Optional. The member name of the topic ID in the result set elements. The default is topicId. | |
arg2 |
object |
Optional. The options to be passed in the server request. This is an object that may contain the following members: - depth - How deep in the topic hierarchy the request to go. A value of 1 indicates the topic level only. 2 indicates that tags should be included, and 3 indicates that tags and values both should be included. The default is 3. - include - Specifies the tag types to be included. Possible values are "inbound", "outbound", "alltopics", and "allvalues". Multiple values may be specified by separating the values with commas. For example: "inbound,outbound". The default is "outbound". - page - Specifies the page number to return and and optionally the page size. Page numbers begin at zero. Page size is calculated by the number of leaf nodes returned. With a depth of 3, this equates to the number of values returned. The default page size is 1000. If both values are specified, they are separated with a comma. For example, { page: "0,200" } would return the first 200 values. The default is "0,1000". |
db().addTopics({text:'persons',friends:[{text:'Andy',gender:'male'},{text:'Mary',gender:'female',spouse:'Bill'},{text:'Bill',gender:'male',spouse:'Mary'}],coworkers:[{text:'Frank',gender:'male'},{text:'Wendy',gender:'female'}]}).end()
db()
.topicByName('persons')
.tags()
.topics({ include: 'alltopics' })
.values()
.text()
.distinct()
.log()
.end();
[
"persons"
]
console.log(typeof db().topics);
function
console.log(typeof db().topics);
function
db().unvote(v, topicId, func)Retract a prior vote on a topic
See userVotes for a description of voting in ScrewtopDb.
Users must be authenticated to unvote. A user can only retract their own votes. The existing vote type
must match the vote type specified in this method.
| Name | Type | Required | Description |
|---|---|---|---|
topicId |
int |
Optional. The topic ID of the topic whose vote is to be retracted. If not present, the first topic in the current result set becomes the vote target |
|
func |
function |
Optional. Callback invoked with the result. | |
v |
string|int |
✓ | The value/option whose vote is to be retracted. |
addTopics · addTags · addValues · deleteTopics · deleteTags · deleteValues · decrementValue · incrementValue · unvote · userVotes
See the example for userVotes.
console.log(typeof db().unvote);
function
db().updateTopic(newTopicText, topicId, options)Modify a topic's text
Only unique topics and topics which have only tags owned by the authenticated user may be updated. Note that this includes
private topics as well.
| Name | Type | Required | Description |
|---|---|---|---|
newTopicText |
string |
✓ | The new text for the topic. |
topicId |
string |
Optional. The topic id of the topic to update. Defaults to the topic in the current result set. | |
options |
object |
Optional options bag. |
addTopics · addTags · addValues · deleteTopics · deleteTags · deleteValues
db().addTopics('Alice', 'city', 'SF').end()
db().topicByName('Alice').updateTopic('Alicia').end(function(){
db().topicByName('Alicia').end(function(ts){ console.log(ts[0].text); });
})
Alicia
db().addTopics('updateTopic_t','x','y').end()
var newName='updateTopic_t_renamed'; db().topicByName('updateTopic_t').updateTopic(newName).end(function(){
db().topicByName(newName).end(function(ts){ console.log(ts[0].text === newName); });
})
true
db().updateValue(newValueText, valueId, optionsObj)Update the text of a value.
This method replaces the current result set with the updated value.
| Name | Type | Required | Description |
|---|---|---|---|
newValueText |
string |
✓ | The new text to replace the existing value text. |
valueId |
string |
Optional. The ID of the value to be updated. If this parameter is not present, the first value found in the current result set is updated. |
addTopics · addTags · addValues · deleteTopics · deleteTags · deleteValues
db()
.addTopics('persons', 'friends', 'Raquel')
.topicByName('persons')
.tagValues('friends')
.text()
.log()
.topicByName('persons')
.tagValues('friends')
.updateValue('Raquella')
.topicByName('persons')
.tagValues('friends')
.text()
.log()
.end();
[
"Raquel"
]
[
"Raquella"
]
db().addTopics('Alice', 'city', 'SF').end()
db().topicByName('Alice').tagValues('city').updateValue('LA').end(function(){
db().topicByName('Alice').tagValues('city').end(function(vs){ console.log(vs[0].text); });
})
LA
db().addTopics('updateValue_t','x','old').end()
db().topicByName('updateValue_t').tagValues('x').updateValue('new').end(function(vs){ console.log(vs[0].text); })
new
console.log(typeof db().updateValue);
function
db().userVotes()Return the user votes array.
Any ScrewtopDb topic may receive votes. A vote may be designated as up, down, or none.
These are designated as 1, 0, and -1 votes, respectively.
Separate counts are maintained for each vote type. A user may vote only once on a topic, but users may
retract their votes and cast a new vote if they wish.
Each user's votes are recorded in their votes user attribute. The attribute contains an array of arrays where the inner
array elements are the topicId and the vote type (-1, 0, or 1).
Each topic that has received votes includes a tally member that in turn contains the members up,
down, none, score, and, if the current user voted for the topic, a voted member.
The first three members are the integer counts of the vote type for that topic. The voted member indicates
how the current user voted on the topic, -1, 0, or 1.
The score member contains an integer between 0 and 10,000,000. It is calculated using the Wilson score
interval. (The lower bound value of which is normally between 0 and 1. The score value is obtained by multiplying the
lower bound by 10 million to allow integer math to be used.) This is intended to be used to sort voted topics for
display based on their relative up- and down-votes.
To include an age component in the score so that newer topics get higher scores than older topics,
divide the score by a value related to the age of the topic. (This is shown in the example.)
addTopics · addTags · addValues · deleteTopics · deleteTags · deleteValues · decrementValue · incrementValue · vote · unvote
db()
.addTopics('proposal', 'content', 'proposal text')
.topicByName('proposal')
.vote(1, function(result) {
alert('upvotes: ' + result.tally.up);
})
.userVotes()
.fn(function(votes) {
alert('topics voted on: ' + votes.length);
})
.end();
upvotes: 1
topics voted on: 1
console.log(typeof db().userVotes);
function
db().valueById(valueId, options)Fetch a value given its ID.
This step passes its result set (an array of topic objects) to the next step.
Typically, there will be zero or one element in the array.
An options object may be included that specifies any combination of the following options:
- **excludeValueText** True to exclude the value text from the response. The default is false.
Ths function always initiates a request to the ScrewtopDB server even if the topic requested is in cache.
| Name | Type | Required | Description |
|---|---|---|---|
valueId |
string |
✓ | The valueId of the value to fetch |
options |
object |
Optional. An object containing option names and values to be passed with the request. |
db().addTopics('Alice', 'city', 'SF').end()
db().topicByName('Alice').values().end(function(vs){
if (!vs || !vs[0]) { console.log('none'); return; }
db().valueById(vs[0].valueId).end(function(vs2){ console.log(vs2 && vs2[0] && vs2[0].text); });
})
SF
db().addTopics('valueById_t','xtag','xval').end()
db().topicByName('valueById_t').values().end(function(vs){
var hit=vs.find(function(v){return v.text==='xval';});
if (!hit) { console.log('none'); return; }
db().valueById(hit.valueId).end(function(vs2){ console.log(vs2 && vs2[0] ? vs2[0].text : 'none'); });
})
xval
db().vote(v, topicId, func)Cast a vote on a topic
See userVotes for a description of voting in ScrewtopDb.
Users must be authenticated to vote.
| Name | Type | Required | Description |
|---|---|---|---|
topicId |
int |
Optional. The topic id of the topic being voted on. | |
func |
function |
Optional. Callback invoked with the result. | |
v |
string|int |
✓ | The value/option to vote for. |
addTopics · addTags · addValues · deleteTopics · deleteTags · deleteValues · decrementValue · incrementValue · unvote · userVotes
See the example for userVotes.
console.log(typeof db().vote);
function
db().collect(func)Replace the result set with the collection or results returned when the supplied function is called
for each member of the current result set.
db().addTopics({text:'persons',friends:[{text:'Andy',gender:'male'},{text:'Mary',gender:'female',spouse:'Bill'},{text:'Bill',gender:'male',spouse:'Mary'}],coworkers:[{text:'Frank',gender:'male'},{text:'Wendy',gender:'female'}]}).end()
db()
.topicByName('persons')
.tags()
// Get the lengths of the tag text members.
.collect(function(tag) {
return tag.text.length;
})
.log()
.end();
[7,9]
console.log(typeof db().collect);
function
db().detect(func)Replace the result set with the first match in the result set based on a supplied match string,
regular expression, or comparison function. If no match is found, the result is set to an empty array.
db().addTopics({text:'persons',friends:[{text:'Andy',gender:'male'},{text:'Mary',gender:'female',spouse:'Bill'},{text:'Bill',gender:'male',spouse:'Mary'}],coworkers:[{text:'Frank',gender:'male'},{text:'Wendy',gender:'female'}]}).end()
db()
.topicByName('persons')
.tags()
// Detect the first tag ending with an s.
.detect(/^.+s$/)
.text()
.log()
.end();
[
"friends"
]
db().setValues([1,2,3]).detect(function(x){return x>1;}).end(function(arr){ console.log(arr); })
[2]
db().distinct()Eliminate duplicate elements in the current result set.
This is most useful when duplicate values have been returned from a topics()
request with options including "alltopics" or "allvalues" and the set of distinct topics or values
(i.e. no duplicates) is desired.
db(['a','b','c','c','a','d'])
.log()
.distinct()
.log()
.end();
[
"a",
"b",
"c",
"c",
"a",
"d"
]
[
"a",
"b",
"c",
"d"
]
db().setValues([1,2,2,3,3,3]).distinct().end(function(arr){ console.log(arr); })
[1,2,3]
db().endingWith(suffix)Filter the current result set to only items whose `.text` property ends with the given suffix.
The comparison is case-insensitive. Items whose text exactly equals the suffix (same length) are excluded;
the text must be strictly longer than the suffix.
Internally delegates to select with a predicate function.
| Name | Type | Required | Description |
|---|---|---|---|
suffix |
string |
✓ | The suffix to match against each item's text property. |
db()
.topicByName('myTopic')
.tags()
.endingWith('/comments')
.log()
.end();
db().addTopics('user.alice','x','1').addTopics('user.bob','x','2').end()
db().findTopics('user').endingWith('alice')
.end(function(ts){ console.log(ts.map(function(t){return t.text;}).sort()); })
["user.alice"]
db().minimizeTopics()Transform the current result set of topic objects into a single minimized plain-object representation.
For each topic that has tags, creates a key equal to the topic's text, whose value is an object mapping
tag text to arrays of value text strings. The result is a single-element array containing the minimized object.
topicByName · topics · collect
db().addTopics({text:'myTopic', title:'My Title', comments:['comment1','comment2']}).end()
db()
.topicByName('myTopic')
.minimizeTopics()
.log()
.end();
[
{
"myTopic": {
"title": ["My Title"],
"comments": ["comment1", "comment2"]
}
}
]
db().addTopics('Alice','city','SF').end()
db().topicByName('Alice').minimizeTopics().end(function(arr){ console.log(arr.length); })
1
db().reject(func)Remove topics, tags, or values from the result set based on a supplied match string,
regular expression, or comparison function.
db().addTopics({text:'persons',friends:[{text:'Andy',gender:'male'},{text:'Mary',gender:'female',spouse:'Bill'},{text:'Bill',gender:'male',spouse:'Mary'}],coworkers:[{text:'Frank',gender:'male'},{text:'Wendy',gender:'female'}]}).end()
db()
.topicByName('persons')
.tags()
// reject also accepts a string or a function — see select.
.reject(/co.+/)
.text()
.log()
.end();
[
"friends"
]
db().setValues([1,2,3,4]).reject(function(x){return x>2;}).end(function(arr){ console.log(arr); })
[1,2]
db().select(func)Select topics, tags, or values from the result set based on a supplied match string,
regular expression, or comparison function.
db().addTopics({text:'persons',friends:[{text:'Andy',gender:'male'},{text:'Mary',gender:'female',spouse:'Bill'},{text:'Bill',gender:'male',spouse:'Mary'}],coworkers:[{text:'Frank',gender:'male'},{text:'Wendy',gender:'female'}]}).end()
db()
.topicByName('persons')
.tags()
// select also accepts a string or a function — see reject.
.select(/co.+/)
.text()
.log()
.end();
[
"coworkers"
]
db().setValues([1,2,3,4]).select(function(x){return x>2;}).end(function(arr){ console.log(arr); })
[3,4]
db().setValues(newValues)Replace the current result set with the provided value or array of values.
If `newValues` is an array, it is used directly as the new result set. Otherwise it is wrapped
in a single-element array.
| Name | Type | Required | Description |
|---|---|---|---|
newValues |
array or any |
✓ | The new result set. If not an array, will be wrapped in one. |
db()
.setValues([1, 2, 3])
.log()
.end();
[1,2,3]
db().setValues([1,2,3]).end(function(arr){ console.log(arr); })
[1,2,3]
db().tag(tagText)Extract tags from the current result set that match a specified pattern.
The tagText argument may be one of the following:
- **owner/tagtext** - where owner is the usernamer of the tag owner and tagtext is the
text of the tag.
- **./tagtext** - ./ is replaced by the current logged-in user, if any, or the username
set as the default username with the options() method.
- **../tagtext** - ../ is replaced by the app name of the current application.
This step passes its result set (an array of tag objects) to the following step.
There will be zero or one element in the array.
| Name | Type | Required | Description |
|---|---|---|---|
tagText |
string |
✓ | The text of the tag to fetch. Supports ./tag (current-user prefix), ../tag (app-name prefix), and owner/tag forms. |
tags · valuesForTag · select · tagsEndingWith
db().addTopics({text:'persons',friends:[{text:'Andy',gender:'male'},{text:'Mary',gender:'female',spouse:'Bill'},{text:'Bill',gender:'male',spouse:'Mary'}],coworkers:[{text:'Frank',gender:'male'},{text:'Wendy',gender:'female'}]}).end()
db()
.topicByName('persons')
.tag('coworkers')
.values()
.text()
.log()
.end();
[
"Frank",
"Wendy"
]
db().addTopics('Alice', 'city', 'SF').end()
db().topicByName('Alice').tag('city').end(function(ts){ console.log(ts && ts[0] ? ts[0].text : 'none'); })
city
db().addTopics('tag_t','xtag','v').end()
db().topicByName('tag_t').tag('xtag').end(function(ts){
console.log(ts && ts[0] ? ts[0].text : 'none');
})
xtag
db().tagById(tagId)Select the subset of the current query result set having text with a specified suffix.
This step passes its result set (an array of selected objects) to the next step.
| Name | Type | Required | Description |
|---|---|---|---|
suffix |
string |
✓ | The string that must suffix the text of all objects to be selected. |
db().addTopics('persons','friends','Andy').addTopics('persons','coworkers','Frank').end()
db().topicByName('persons').tags().end(function(tags) {
var firstId = tags[0].tagId;
// tagById filters the result set to elements with a matching tagId.
db().topicByName('persons').tags()
.tagById(firstId)
.text()
.log()
.end();
});
[
"friends"
]
console.log(typeof db().tagById);
function
db().tags()Extract all tags from all topics in the current result set.
This step passes its result set (array of tag objects) to the following step.
db().addTopics({text:'persons',friends:[{text:'Andy',gender:'male'},{text:'Mary',gender:'female',spouse:'Bill'},{text:'Bill',gender:'male',spouse:'Mary'}],coworkers:[{text:'Frank',gender:'male'},{text:'Wendy',gender:'female'}]}).end()
db()
.topicByName('persons')
.tags()
.text()
.log()
.end();
[
"friends",
"coworkers"
]
db().addTopics('Alice', 'city', 'SF').end()
db().topicByName('Alice').tags().end(function(ts){ console.log(ts.filter(function(t){return t && t.text;}).map(function(t){return t.text;}).sort()); })
["city"]
db().addTopics('tags_t','xtag','v').end()
db().topicByName('tags_t').tags().end(function(ts){
console.log(ts.filter(function(t){return t && t.text==='xtag' && t.tagType !== 'inbound';}).length);
})
1
db().tagValues(tagText)Extract the values for a tag in the current result set given a tag text pattern.
This step passes its result set (an array of value objects) to the following step.
There will be zero or more elements in the array.
The tagText argument may be one of the following:
- **owner/tagtext** - where owner is the usernamer of the tag owner and tagtext is the
text of the tag.
- **./tagtext** - ./ is replaced by the current logged-in user, if any, or the username
set as the default username with the options() method.
- **../tagtext** - ../ is replaced by the app name of the current application.
| Name | Type | Required | Description |
|---|---|---|---|
tagText |
string |
✓ | The text of the tag whose values are to be selected. |
db().addTopics({text:'persons',friends:[{text:'Andy',gender:'male'},{text:'Mary',gender:'female',spouse:'Bill'},{text:'Bill',gender:'male',spouse:'Mary'}],coworkers:[{text:'Frank',gender:'male'},{text:'Wendy',gender:'female'}]}).end()
db()
.topicByName('persons')
.tagValues('coworkers')
.text()
.log()
.end();
[
"Frank",
"Wendy"
]
db().addTopics('Alice', 'city', 'SF').end()
db().topicByName('Alice').tagValues('city').end(function(vs){ console.log(vs && vs[0] && vs[0].text); })
SF
db().addTopics('tagValues_t','xtag','xval').end()
db().topicByName('tagValues_t').tagValues('xtag').end(function(vs){
console.log(vs && vs[0] ? vs[0].text : 'none');
})
xval
db().values()Extract the values of the tags in the current result set.
This step passes its result set (an array of values) to the next step. If the current result set contains topics,
the values of all tags in all topics will be selected. If the current result set contains tags, then all the values
of all tags wiull be selected. If the current result set contains values, the result set will be
passed to the following step unchanged.
db().addTopics({text:'persons',friends:[{text:'Andy',gender:'male'},{text:'Mary',gender:'female',spouse:'Bill'},{text:'Bill',gender:'male',spouse:'Mary'}],coworkers:[{text:'Frank',gender:'male'},{text:'Wendy',gender:'female'}]}).end()
db()
.topicByName('persons')
.values()
.text()
.log()
.end();
[
"Andy",
"Mary",
"Bill",
"Frank",
"Wendy"
]
db().addTopics('Alice', 'city', 'SF').end()
db().topicByName('Alice').values().end(function(vs){ console.log(vs && vs[0] && vs[0].text); })
SF
db().addTopics('values_t','xtag','xval').end()
db().topicByName('values_t').values().end(function(vs){
var hit=vs.find(function(v){return v.text==='xval';});
console.log(hit ? hit.text : 'none');
})
xval
db().each(func)Invoke a user-supplied function for each element in the result set, passing the following arguments:
- The current result set element
- An environment object whose contents are retained across successive function calls. This
object can be used to accumulate information across function invocations.
- The zero-based integer index of the current result set element.
- The result set array
This method passes the input result set on to the following query sequence step unchanged (unless it is
modified by the user-supplied function.)
| Name | Type | Required | Description |
|---|---|---|---|
func |
function |
✓ | the function to be called repeatedly, once for each object in the result set. If the function returns true, loop execution will cease, and the function will not be called again. |
db(['a', 'b', 'c', 'd', 'e', 'f'])
// See if 'c' is in the list, and if so, where.
.each(function(elem, env, index, all) {
if (elem == 'c') {
alert('c found at index ' + index + '.');
return true;
}
})
// concatenate the array elements into comma-separated value string.
.each(function(elem, env, index, all) {
if (!db.isDefined(env.csv)) env.csv = elem;
else env.csv += ',' + elem;
// If we're at the end, display the result.
if (index + 1 == all.length) {
alert(env.csv);
}
})
.end();
c found at index 2.
a,b,c,d,e,f
var out=[]; db().setValues([1,2,3]).each(function(x){out.push(x*2);}).end(function(){ console.log(out); })
[2,4,6]
var out=[]; db().setValues([1,2,3]).each(function(x){ out.push(x*2); }).end(function(){ console.log(out); })
[2,4,6]
db().fc(func)Invoke a user-supplied function that invokes a callback function, optionally passing to it
the current result set.
The function must expect the callback function as the last argument.
If arguments other than the function are provided, they are passed to the function before the
callback argument. If the string "RS" is passed as an argument, it is replaced by the
current result set when the function is invoked. A callback function is automatically
provided as the last argument.
If the callback function returns a result, the result replaces the current result set.
| Name | Type | Required | Description |
|---|---|---|---|
userfunc |
function |
✓ | The function to be invoked. |
arg |
... |
Arguments to be passed to the function. If the string "RS" is passed as an argument, it is replaced by the current result set when the function is invoked. |
db([22,33,44])
.push()
.fc(function(a, b, cb) { cb(a + b.indexOf(33)); }, "index: ", "RS")
.log()
.end();
[
"index: 1"
]
console.log(typeof db().fc);
function
console.log(typeof db().fc);
function
db().first(func)Select the first element of the result set and optionally pass it to a user-supplied function.
This step passes its result (an array of zero or one element) to the following step in the query sedquence.
db().addTopics({text:'persons',friends:[{text:'Andy',gender:'male'},{text:'Mary',gender:'female',spouse:'Bill'},{text:'Bill',gender:'male',spouse:'Mary'}],coworkers:[{text:'Frank',gender:'male'},{text:'Wendy',gender:'female'}]}).end()
db()
.topicByName('persons')
.tags()
.first(function(tag) {
alert(tag.text + ': ' + tag.valueTextArray());
})
.text()
.log()
.end();
friends: Andy,Mary,Bill
[
"friends"
]
db().setValues([1,2,3]).first().end(function(arr){ console.log(arr); })
[1]
db().fn(userfunc, arg)Invoke a user-supplied function, passing to it the current result set.
If this function returns a result, the result replaces the current result set.
| Name | Type | Required | Description |
|---|---|---|---|
userfunc |
function |
✓ | The function to be invoked. |
arg |
any |
An argument to be passed to the function. If this parameter is present, it is the first parameter passed to the function and the current result set is the second parameter. |
db().addTopics({text:'persons',friends:[{text:'Andy',gender:'male'},{text:'Mary',gender:'female',spouse:'Bill'},{text:'Bill',gender:'male',spouse:'Mary'}],coworkers:[{text:'Frank',gender:'male'},{text:'Wendy',gender:'female'}]}).end()
db()
.topicByName('persons')
.tags()
.fn(function(tags) {
var names = [];
db.forEach(tags, function(tag) {
db.forEach(tag.values, function(val) {
alert(tag.text + ': ' + val.text);
names.push(val.text);
});
});
return names;
})
.log()
.end();
friends: Andy
friends: Mary
friends: Bill
coworkers: Frank
coworkers: Wendy
[
"Andy",
"Mary",
"Bill",
"Frank",
"Wendy"
]
db().setValues([1,2,3]).fn(function(arr){ return arr.map(function(x){return x+10;}); }).end(function(out){ console.log(out); })
[11,12,13]
db().ifAny(func, elsefunc)Perform an action if the result set contains one or more elements.
The actions that may be performed include stopping the currently executing query sequence, aborting all
query sequences, or invoking a user-supplied function.
| Name | Type | Required | Description |
|---|---|---|---|
elsefunc |
function|string |
Optional. Action when the result set IS empty (the else branch). Same forms as func. | |
func |
function|string |
✓ | Action when the result set is non-empty: a function called with the full result set array (a returned value replaces the set), or the string "stop"/"abort" to terminate the sequence. |
db().addTopics({text:'persons',friends:[{text:'Andy',gender:'male'},{text:'Mary',gender:'female',spouse:'Bill'},{text:'Bill',gender:'male',spouse:'Mary'}],coworkers:[{text:'Frank',gender:'male'},{text:'Wendy',gender:'female'}]}).end()
db()
.topicByName('persons')
.tags()
.ifNone('stop')
.ifMany(function(tags) {
return tags[0]; // a bare return becomes a single-element result set
})
.ifAny(function(tags) {
alert(tags[0].text);
})
.end();
friends
var hit=false; db().setValues([1]).ifAny(function(){ hit=true; }).end(function(){ console.log(hit); })
true
db().ifMany(func, elsefunc)Perform an action if the result set contains more than one element.
The actions that may be performed include stopping the currently executing query sequence, aborting all
query sequences, or invoking a user-supplied function.
| Name | Type | Required | Description |
|---|---|---|---|
elsefunc |
function|string |
✓ | A function to be invoked if the current result set length not greater than one or one of the strings 'stop' or 'abort'. If a function is provided and it returns a value, that value replaces the current result set. The function is passed the current result set as its single argument. The string 'stop' terminates execution of the current query sequence. The string 'abort' terminates execution of all query sequences. |
func |
function|string |
✓ | Action when the result set has more than one element. Same forms as ifAny's func. |
db().addTopics({text:'persons',friends:[{text:'Andy',gender:'male'},{text:'Mary',gender:'female',spouse:'Bill'},{text:'Bill',gender:'male',spouse:'Mary'}],coworkers:[{text:'Frank',gender:'male'},{text:'Wendy',gender:'female'}]}).end()
db()
.topicByName('persons')
.tags()
.ifNone('stop')
.ifMany(function(tags) {
return tags[0]; // a bare return becomes a single-element result set
})
.ifOne(function(tag) {
// Note: unlike ifAny, ifOne passes the single ELEMENT, not the array.
alert(tag.text);
})
.end();
friends
var hit=false; db().setValues([1,2,3]).ifMany(function(){ hit=true; }).end(function(){ console.log(hit); })
true
db().ifNone(func, elsefunc)Perform an action if the result set is empty.
The actions that may be performed include stopping the currently executing query sequence, aborting all
query sequences, or invoking a user-supplied function.
| Name | Type | Required | Description |
|---|---|---|---|
elsefunc |
function|string |
✓ | A function to be invoked if the current result set is not empty or one of the strings 'stop' or 'abort'. If a function is provided and it returns a value, that value replaces the current result set. The string 'stop' terminates execution of the current query sequence. The string 'abort' terminates execution of all query sequences. |
func |
function|string |
✓ | Action when the result set is empty. Same forms as ifAny's func. |
db()
.topicByName('bogus')
.ifNone(function() {
alert('not found');
db.abortAll();
})
.log()
.end();
not found
var hit=false; db().setValues([]).ifNone(function(){ hit=true; }).end(function(){ console.log(hit); })
true
db().ifOne(func, elsefunc)Perform an action if the result set contains one and only one element.
The actions that may be performed include stopping the currently executing query sequence, aborting all
query sequences, or invoking a user-supplied function.
| Name | Type | Required | Description |
|---|---|---|---|
elsefunc |
function|string |
✓ | A function to be invoked if the current result set length is not one or one of the strings 'stop' or 'abort'. If a function is provided and it returns a value, that value replaces the current result set. The function is passed the current result set element as its single argument. The string 'stop' terminates execution of the current query sequence. The string 'abort' terminates execution of all query sequences. |
func |
function|string |
✓ | Action when the result set has exactly one element. NOTE: unlike ifAny (which receives the full result-set array), ifOne invokes func with the single ELEMENT as its first argument; the full result set is passed as the second argument. |
db().addTopics({text:'persons',friends:[{text:'Andy',gender:'male'},{text:'Mary',gender:'female',spouse:'Bill'},{text:'Bill',gender:'male',spouse:'Mary'}],coworkers:[{text:'Frank',gender:'male'},{text:'Wendy',gender:'female'}]}).end()
db()
.topicByName('persons')
.tags()
.ifNone('stop')
.ifMany(function(tags) {
return tags[0]; // a bare return becomes a single-element result set
})
.ifOne(function(tag) {
// Note: unlike ifAny, ifOne passes the single ELEMENT, not the array.
alert(tag.text);
})
.end();
friends
var hit=false; db().setValues([1]).ifOne(function(){ hit=true; }).end(function(){ console.log(hit); })
true
db().last(func)Select the last element of the result set and optionally pass it to a user-supplied function.
This step passes its result (an array of zero or one element) to the following step in the query sequence.
db().addTopics({text:'persons',friends:[{text:'Andy',gender:'male'},{text:'Mary',gender:'female',spouse:'Bill'},{text:'Bill',gender:'male',spouse:'Mary'}],coworkers:[{text:'Frank',gender:'male'},{text:'Wendy',gender:'female'}]}).end()
db()
.topicByName('persons')
.tags()
.last(function(tag) {
alert(tag.text + ': ' + tag.valueTextArray());
})
.text()
.log()
.end();
coworkers: Frank,Wendy
[
"coworkers"
]
db().setValues([1,2,3]).last().end(function(arr){ console.log(arr); })
[3]
db().ps(pfunc)Invoke a user-supplied function that returns a promise. Execute the next step when the promise is resolved.
If the promise returns a result, the result replaces the current result set.
The promise may contain a ScrewtopDB query sequence. In this case the end method typically calls the promise's
resolve callback.
| Name | Type | Required | Description |
|---|---|---|---|
userfunc |
function |
✓ | The function to be invoked that returns a promise. |
arg |
any |
An argument to be passed to the function. If this parameter is present, it is the first parameter passed to the function and the current result set is the second parameter. |
db().addTopics({text:'persons',friends:[{text:'Andy',gender:'male'},{text:'Mary',gender:'female',spouse:'Bill'},{text:'Bill',gender:'male',spouse:'Mary'}],coworkers:[{text:'Frank',gender:'male'},{text:'Wendy',gender:'female'}]}).end()
db()
.topicByName('persons')
.tags()
.ps(function(tags) {
return new Promise(function(resolve, reject) {
var names = [];
db.forEach(tags, function(tag) {
db.forEach(tag.values, function(val) {
alert(tag.text + ': ' + val.text);
names.push(val.text);
});
});
resolve(names);
});
})
.log()
.end();
friends: Andy
friends: Mary
friends: Bill
coworkers: Frank
coworkers: Wendy
[
"Andy",
"Mary",
"Bill",
"Frank",
"Wendy"
]
console.log(typeof db().ps);
function
console.log(typeof db().ps);
function
db().reverse()Reverse the order of the elements in the current result set.
db(['a','b','c','d','e','f'])
.log()
.reverse()
.log()
.end();
[
"a",
"b",
"c",
"d",
"e",
"f"
]
[
"f",
"e",
"d",
"c"
"b"
"a"
]
db().setValues([1,2,3]).reverse().end(function(arr){ console.log(arr); })
[3,2,1]
db().sort(func)Sort the elements of the result set.
By default, the text members of the result set elements are sorted in ascending order. If the result set
contains strings, the strings are sorted in ascending order.
If a function argument is provided, the result of the function is used to sort the elements.
| Name | Type | Required | Description |
|---|---|---|---|
func |
function |
Optional comparator (a, b) returning -1, 0, or 1. If omitted, sorts by the text property, case-insensitive ascending. |
db().addTopics({text:'persons',friends:[{text:'Andy',gender:'male'},{text:'Mary',gender:'female',spouse:'Bill'},{text:'Bill',gender:'male',spouse:'Mary'}],coworkers:[{text:'Frank',gender:'male'},{text:'Wendy',gender:'female'}]}).end()
db()
.topicByName('persons')
.tags()
.values()
// Sort by the text member (case-insensitive ascending).
.sort()
.text()
.log()
.end();
[
"Andy",
"Bill",
"Frank",
"Mary",
"Wendy"
]
// Numbers sort numerically; strings and topic objects sort by text.
db().setValues([3, 1, 2]).sort().end(function(arr){ console.log(arr); })
[1,2,3]
db().setValues([{text:'c'},{text:'a'},{text:'b'}]).sort().text().end(function(arr){ console.log(arr); })
["a","b","c"]
db().text(arg1, arg2)Extract the text properties from the current result set.
This step passes a new result set consisting of text strings to the following step.
Notes
- The order of arguments to this method is not enforced (i.e. the arguments may be passed in any order.)
- If the result set is an array of test strings, the strings are processed as if they were the values of text
properties.
| Name | Type | Required | Description |
|---|---|---|---|
arg1 |
string |
Optional. The member/property name from which to extract text. Default is "text". | |
strip |
boolean |
✓ | True to strip any UUIDs that are suffixed to the extracted strings |
db().addTopics({text:'persons',friends:[{text:'Andy',gender:'male'},{text:'Mary',gender:'female',spouse:'Bill'},{text:'Bill',gender:'male',spouse:'Mary'}],coworkers:[{text:'Frank',gender:'male'},{text:'Wendy',gender:'female'}]}).end()
db()
// db.uniquify appends a GUID suffix; text(true) strips it back off.
.addTopics('persons', 'acquaintances', db.uniquify('Jaquie'))
.topicByName('persons')
.tag('acquaintances')
.values()
.text(true)
.log()
.end();
[
"Jaquie"
]
db().setValues([{text:'a'},{text:'b'}]).text().end(function(arr){ console.log(arr); })
["a","b"]
db().setValues([{text:'a'},{text:'b'}]).text().end(function(arr){ console.log(arr); })
["a","b"]
db().abort()Abort all query sequences in execution.
This method terminates execution of the current sequence, as well as any enclosing sequences. It does not
terminate execution of sequences initiated using the fork or go methods.
db().fn(function(){ console.log('first'); }).end()
first
db().fn(function(){ console.log('first'); }).end()
first
db().beginServerExecution()Send the sequence steps beginning with the next step to the server for execution.
The steps beginning with the next step and ending with the step before the next endServerExecution
are sent to the server for execution. The result is returned as if the sequence steps had been executed locally.
This facility is provided to allow avoiding passing large volumes of data back to the client for processing when that processing
could be executed on the server where no network traffic is generated.
Not all methods are candidates for execution on the server in this way. Only those methods that do not expect function arguments
may be executed on the server. Methods that produce console output such as log are, of course, useless for
debugging in server-side execution. The best way to prepare server-side sequences is to debug them in the client first.
// Note that this example, unlike most examples in this document, while it will execute, will
// not return any values.
db()
.beginServerExecution()
.topicByName('a-topic-with-many-tags-and-values')
.tag('./a-tag-with-many-values')
.values()
.select("text = /phrase-to-find-in-values/")
.endServerExecution()
.log()
.end();
db().beginServerExecution().endServerExecution().end(function(){ console.log('ok'); })
ok
db().delay(ms)Delay execution of the current query sequence for a specified number of milliseconds.
Execution of this method will allow other query sequences to execute, just as the method
waitForCompletion and requests to the server do.
waitForCompletion · fork · go
See example of fork.
var t0=Date.now(); db().delay(50).end(function(){ console.log(Date.now()-t0 >= 40); })
true
var t0=Date.now(); db().delay(50).end(function(){ console.log(Date.now()-t0 >= 40); })
true
db().end(f)Initiates execution of the query, beginning at the first step.
Note that a new query may be constructed and executed within a function invoked by methods including
each and func. When this occurs, the nested sequence's steps
are executed immediately. The parent is resumed after the sub-sequence has completed. The result set
of the parent query sequence is unaffected by the execution of any sub-sequences unless the argument to
this function is true or the function returns a value.
This method is the most common way to initiate query sequence execution.
| Name | Type | Required | Description |
|---|---|---|---|
func |
function | boolean |
✓ | A function to be called after the last step of the query completes. If this function returns a value, it is passed to the next step in the enclosing query sequence, if any. If this parameter is the boolean value true, then the result set is passed to the next step in the enclosing query sequence, if any. |
console.log(typeof db().end);
function
db().endServerExecution()Marks the end of sequence steps executed on the server.
See beginServerExecution.
db().beginServerExecution().endServerExecution().end(function(){ console.log('ok'); })
ok
db().go(func)Defer execution of a nested query sequence until the enclosing sequence has completed.
A seldom-used alternative to the end method.
| Name | Type | Required | Description |
|---|---|---|---|
func |
function | boolean |
✓ | A function to be called after the last step of the query completes. |
console.log(typeof db().go);
function
console.log(typeof db().go);
function
db().resume(func)Resume a query sequence whose execution was suspended with wait.
See wait for more information about the wait/resume feature.
Note that no other methods should be chained to the resume method, including end.
Note also that resume may be invoked on a screwtopDb sequence or on the screwtopDb object directly as
is done in the example below.
.func(function() {
alert("Setting timeout.");
setTimeout(function() {
alert("Timeout expired.")
db.resume(); // db().resume() also acceptable.
}, 2000);
})
.wait(function () {
alert('Waiting...');
})
.log('Waiting done.')
.end();
Setting timeout.
Waiting...
Timeout expired.
Waiting done.
console.log(typeof db().resume);
function
db().serverExecute(script)Send a pre-built chain expression (as a string) to the server's `/:app/scripts.json` endpoint for
execution in the server's own ScrewtopDB interpreter. The response data replaces the current result set.
Most apps should use the beginServerExecution / endServerExecution
pair instead — those build the script string automatically from the wrapped chain steps. Use serverExecute directly
only when you need to construct the script text yourself.
| Name | Type | Required | Description |
|---|---|---|---|
script |
string |
✓ | A serialized chain expression such as "topicByName('x').tag('y').values()". Function bodies are not serialized and will be rejected by the server. |
console.log(typeof db().serverExecute);
function
db().wait(func)Suspend query sequence until resume is called.
This method allows you to suspend execution of a query sequence until the occurrence of an
external event. When the external event occurs (it might be a user-initiated event, a network
event, or a timeout) invoke the resume method to restart query execution.
Only one wait at a time is supported.
| Name | Type | Required | Description |
|---|---|---|---|
func |
function |
✓ | Callback invoked after outstanding asynchronous work completes, before the next step runs. |
.func(function() {
alert("Setting timeout.");
setTimeout(function() {
alert("Timeout expired.")
db.resume();
}, 2000);
})
.wait(function () {
alert('Waiting...');
})
.log('Waiting done.')
.end();
Setting timeout.
Waiting...
Timeout expired.
Waiting done.
db().setValues([1]).end(function(arr){ console.log(arr.length); })
1
console.log(typeof db().wait);
function
db().waitForCompletion(func)Wait for any parallel-executing query sequences to complete.
The function argument is invoked when there are no parallel query sequences
in execution except the caller.
| Name | Type | Required | Description |
|---|---|---|---|
func |
function |
✓ | Callback invoked once all outstanding operations have completed. |
See example of fork.
var c=db().setValues([1,2,3]).end(); db().waitForCompletion(c).end(function(){ console.log('done'); })
done
var c=db().setValues([1,2,3]).end(); db().waitForCompletion(c).end(function(){ console.log('done'); })
done
db().deleteSavedContext(index)Delete a previously saved context
This step passes the incoming result set unchanged to the following step.
| Name | Type | Required | Description |
|---|---|---|---|
index |
string|number |
✓ | The identifier of the result set to delete |
db([1,2,3])
.onError(function(err) { alert(err); })
.saveContext('xxx')
.restoreContext('xxx')
.deleteSavedContext('xxx')
.restoreContext('xxx')
.end()
Attempt to restore unsaved context "xxx".
db().saveContext('ctx').end()
db().deleteSavedContext('ctx').end(function(){ console.log('ok'); })
ok
db().saveContext('deleteSavedContext_ctx').end()
db().deleteSavedContext('deleteSavedContext_ctx').end(function(){ console.log('ok'); })
ok
db().peek()Restore the last pushed result set from the stack without removing it from the stack.
pop · push · stack · save · restore · saveContext · restoreContext · saveSession · restoreSession
See example for push.
db().setValues([1]).push().setValues([2]).peek().end(function(arr){ console.log(arr); })
[1]
db().setValues([1]).push().setValues([2]).peek().end(function(arr){ console.log(arr); })
[1]
db().pop()Restore a previously saved session and result set.
| Name | Type | Required | Description |
|---|---|---|---|
index |
string|number |
✓ | The index of the desired session and result set previously saved with the save method. |
del |
boolean |
Optional. True to remove the saved context and session from the store after it has been restored. |
save · saveSession · restoreSession · push · pop · peek · stack · saveContext · restoreContext
See example for save.
db().setValues([1]).push().setValues([2]).pop().end(function(arr){ console.log(arr); })
[1]
db().setValues([1]).push().setValues([2]).pop().end(function(arr){ console.log(arr); })
[1]
db().push()Push the current result set onto the result set stack.
pop · peek · stack · saveContext · restoreContext · saveSession · restoreSession
db(['3','1','2'])
.push()
.sort()
.push()
.reverse()
.push()
.stack(function(s) { alert(s); })
.pop().log()
.pop().log()
.peek().log()
.stack(function(s) { alert(s); })
.end()
[ [ '3', '1', '2' ],
[ '1', '2', '3' ],
[ '3', '2', '1' ] ]
[
"3",
"2",
"1"
]
[
"1",
"2",
"3"
]
[
"3",
"1",
"2"
]
[ [ '3', '1', '2' ] ]
db().setValues([1,2]).push().setValues([3]).pop().end(function(arr){ console.log(arr); })
[1,2]
db().setValues([1]).push().setValues([2]).pop().end(function(arr){ console.log(arr); })
[1]
db().restoreContext(index, del)Restore a previously saved result set.
| Name | Type | Required | Description |
|---|---|---|---|
index |
string|number |
✓ | The identifier of the desired result set previously saved with thesaveContext method. |
del |
boolean |
Optional. True to remove the saved context from the saved context store after it has been restored. |
saveContext · push · pop · peek · stack · save · restore · saveSession · restoreSession
See example for saveContext.
db().addTopics('alice','x','1').topicByName('alice').saveContext(1).end()
db().restoreContext(1).end(function(rs){ console.log(rs.map(function(t){return t.text;})); })
["alice"]
db().saveContext('restoreContext_ctx').end()
db().restoreContext('restoreContext_ctx').end(function(){ console.log('ok'); })
ok
db().restoreSession(index, del)Restore a previously saved session.
| Name | Type | Required | Description |
|---|---|---|---|
index |
string|number |
✓ | The index of the desired session previously saved with the saveSession method. |
del |
boolean |
Optional. True to remove the saved context from the saved context store after it has been restored. |
saveSession · push · pop · peek · stack · save · restore · saveContext · restoreContext
See example for saveSession.
db().saveSession('s').end()
db().restoreSession('s').end(function(){ console.log('ok'); })
ok
db().saveSession('restoreSession_s').end()
db().restoreSession('restoreSession_s').end(function(){ console.log('ok'); })
ok
db().save(index)Save session information and the current result set for later restoration.
This method is the equivalent of executing saveContext() and
saveSession() with the same index argument.
| Name | Type | Required | Description |
|---|---|---|---|
index |
string|number |
✓ | The identifier by which the saved information can be retrieved using the restore() method. |
restore · saveSession · saveContext · session
db()
.login('<appname>', '<username>', '<password>')
.save('userObject')
.topicByName('bogusTopicName')
.log()
// Result set is now empty
.restore('userObject')
// Display the user's login count
.tag('./loginCount')
.values().text()
.log()
.end()
db().setValues([1,2]).save('x').setValues([3]).restore('x').end(function(arr){ console.log(arr); })
[1,2]
db().setValues([1,2]).save('save_x').setValues([3]).restore('save_x').end(function(arr){ console.log(arr); })
[1,2]
db().saveContext(index)Save the current result set so that it can be restored in a later step.
This step passes the input result set unchanged to the following query sequence step.
| Name | Type | Required | Description |
|---|---|---|---|
index |
string|number |
✓ | The identifier by which the saved result set can be retrieved using the restoreContext() method. |
restoreContext · deleteSavedContext · save · restore · push · pop · peek · stack · saveSession · restoreSession
db().addTopics({text:'persons',friends:[{text:'Andy',gender:'male'},{text:'Mary',gender:'female',spouse:'Bill'},{text:'Bill',gender:'male',spouse:'Mary'}],coworkers:[{text:'Frank',gender:'male'},{text:'Wendy',gender:'female'}]}).end()
db()
.topicByName('persons')
.tags()
.saveContext(1)
.text()
.log()
.restoreContext(1)
.last()
.values()
.first()
.text()
.log()
.restoreContext(1)
.text()
.log()
.end();
[
"friends",
"coworkers"
]
[
"Frank"
]
[
"friends",
"coworkers"
]
db().saveContext('ctx').end(function(){ console.log('ok'); })
ok
db().saveContext('saveContext_ctx').end(function(){ console.log('ok'); })
ok
db().saveSession(index)Save session information for later restoration.
Session information includes the session identifier, the server URL, the application name,
the current username, and the contents of the in-memory client-side cache. (The session identifier
is assigned by the server after user authentication (i.e. a successful login.)
Note that this method does not save the current result set with the session information. If you wish to
save both, use save() instead.
Only a single session may be active at any time. You might want to change sessions dynamically
if you were, for example, copying information from one application to another or if you were copying
information from one user to another within an application.
| Name | Type | Required | Description |
|---|---|---|---|
index |
string|number |
✓ | The identifier by which the saved session can be retrieved using the restoreSession() method. |
restoreSession · save · restore · saveContext · restoreContext · push · pop · peek · stack
var firstId;
db()
.session(function(sess) { firstId = sess.sessionId; })
.saveSession(1)
.restoreSession(1)
.session(function(sess) {
alert('restored the same session: ' + (sess.sessionId === firstId));
})
.end();
restored the same session: true
db().saveSession('s').end(function(){ console.log('ok'); })
ok
db().saveSession('saveSession_s').end(function(){ console.log('ok'); })
ok
db().stack(func)Invoke a user-supplied function passing the current stack array as its single argument.
The array passed to the supplied function is not a copy of the stack, but the stack array itself. Thus
any changes made to it within the invoked function will persist after the function returns.
pop · push · peek · save · restore · saveContext · restoreContext · saveSession · restoreSession
See example for push.
db().setValues([1]).push().stack(function(s){ console.log(s.length); }).end()
1
db().setValues([1]).push().stack(function(s){ console.log(s.length); }).end()
1
db().session(func)Invoke a user-supplied function that is passed a session information object.
The members of the returned object are
- sessionId - the session identifier assigned on login by the server
- url - the URL of the server. Normally https://www.screwtopdb.com
- appId - the application ID of the application
- appName - the application name
- username - the username of the currently logged-in user
If a login has not been performed, the session information object passed is undefined.
| Name | Type | Required | Description |
|---|---|---|---|
func |
function(sessionObj) |
✓ | The function to be invoked with the session information object. |
db()
.session(function(sess) {
// Under basic authentication sessionId is null; login() sets it.
alert('session user: ' + sess.username);
})
.end();
session user: u
db().session(function(s){ console.log(typeof s); }).end()
object
db().session(function(s){ console.log(typeof s); }).end()
object
db().addTopicsLocal(topicText, tagText, valueText, options)Add a topic to the local cache without "writing through" to the server.
Normally, unless offline, added topics are transmitted to the server and
the server response is used to update the cache, including the server-assigned
topic, tag, and value IDs. This method does not update the server, thus behaving
as if the client was offline.
| Name | Type | Required | Description |
|---|---|---|---|
topicText |
string |
✓ | The topic text |
tagText |
string |
✓ | The tag text |
valueText |
string |
✓ | The value text |
Optional. |
object |
✓ | An options object |
db().addTopicsLocal('LocalT','x','1').end(function(){ console.log('ok'); })
ok
db().addTopicsLocal('addTopicsLocal_t','tag1','val1').end(function(){ console.log('ok'); })
ok
db().deleteTopicsLocal()Delete topics in the current result set from the local cache without "writing through" to the server.
Normally, unless offline, topic deletions are transmitted to the server and
the server response is used to update the cache. This method does not update
the server, thus behaving as if the client was offline.
db().addTopicsLocal('LocalT','x','1')
.topicByName('LocalT',{fromcache:true})
.deleteTopicsLocal()
.end(function(){ console.log('ok'); })
ok
console.log(typeof db().deleteTopicsLocal);
function
db().deleteValuesLocal(valIds)Delete values in the current result set from the local cache without "writing through" to the server.
Normally, unless offline, value deletions are transmitted to the server and
the server response is used to update the cache. This method does not update
the server, thus behaving as if the client was offline.
db().addTopicsLocal('LocalT','x','1').end()
db().topicByName('LocalT').tagValues('x').deleteValuesLocal().end(function(){ console.log('ok'); })
ok
console.log(typeof db().deleteValuesLocal);
function
db().enableCache(torf)Enable or disable caching of topics
By default, the ScrewtopDB Javascript library caches retrieved topics and thereafter if the same topic
is referenced again, it is retrieved from cache rather than requiring that another request
be sent to the server.
This function allows you to disable the caching feature. This might be desirable if, for example, you
are accessing a highly interactive application where ScrewtopDB topics are used to communicate between
multiple on-line clients.
db().addTopics({text:'persons',friends:[{text:'Andy',gender:'male'},{text:'Mary',gender:'female',spouse:'Bill'},{text:'Bill',gender:'male',spouse:'Mary'}],coworkers:[{text:'Frank',gender:'male'},{text:'Wendy',gender:'female'}]}).end()
db()
// Disable the local cache: every read goes to the server.
.enableCache(false)
.topicByName('persons')
.fn(function(ts) { console.log('fetched: ' + ts[0].text); })
.enableCache(true)
.end();
fetched: persons
db().enableCache(true).enableCache(false).end(function(){ console.log('ok'); })
ok
db().enableCache(true).enableCache(false).end(function(){ console.log('ok'); })
ok
db().invalidateCache(idOrName)Remove all entries from the local topic cache.
The ScrewtopDB Javascript library caches retrieved topics and thereafter if the same topic
is referenced again, it is retrieved from cache rather than requiring that another request
be sent to the server.
InvalidateCache is used when you want to be sure that you are using the server's copy of a
topic. This might be necessary if, for example, there are multiple clients accessing the
same topic simultaneously.
| Name | Type | Required | Description |
|---|---|---|---|
idOrName |
number | string |
Optional. The ID or name (topicText) of the cache element to remove. If this parameter is not present, all cached topics are removed. |
// Invalidate the cache to ensure that a server request is produced by the
// topicByName function.
db()
.appName('<appname>')
.invalidateCache()
.topicByName('user:<username>')
.lastRequestTime(function(ms) {
alert("Topic retrieval took " + ms + " ms on the server.");
})
.end();
db().invalidateCache().end(function(){ console.log('ok'); })
ok
db().invalidateCache().end(function(){ console.log('ok'); })
ok
db().localCacheData(func)Call the provided function passing the current contents of the local in-memory cache.
This method is intended for debugging of the ScrewtopDb library and is not likely to
be generally useful. The web page ScrewtopDb Cache Demo
uses this method to display cache content changes in real time.
| Name | Type | Required | Description |
|---|---|---|---|
The |
function |
✓ | function to be invoked. The single argument passed is the local cache content. |
db()
.appName('<appname>')
.topicByName('user:<username>')
.localCacheData(function(cache) {
db()
.log(JSON.stringify(cache, null, ' ')
.end();
}
.end();
console.log(typeof db().localCacheData);
function
db().localStorageData(func, cacheName)Call the provided function passing the current contents of the browser's local storage cache.
This method is intended for debugging of the ScrewtopDb library and is not likely to
be generally useful. The web page ScrewtopDb Cache Demo
uses this method to display cache content changes in real time.
| Name | Type | Required | Description |
|---|---|---|---|
cacheName |
string |
Optional. The named cache to read. Defaults to the primary cache. | |
func |
function |
✓ | Callback invoked with the local-storage cache data object. |
db()
.appName('<appname>')
.topicByName('user:<username>')
.localStorageData(function(cache) {
db()
.log(JSON.stringify(cache, null, ' ')
.end();
}
.end();
console.log(typeof db().localStorageData);
function
db().deferredWrite(torf)Set the deferredWrite state or passes the current deferredWrite state to a function.
When deferredeWrite is **true** all ScrewtopDb write requests will update the local cache only; no
server communication will be attempted. Later invocation of the synchronize method
will update the server with the new and changed content of the local cache. Use of deferredWrite and
synchroinize allow disconnected operation of ScrewtoDb applications.
| Name | Type | Required | Description |
|---|---|---|---|
torf |
boolean|function |
✓ | If this parameter is a boolean, the deferredWrite state is set to the value of the parameter. If the parameter is a function the function is called with a single argument is the current deferredWrite value. |
offline · synchronize · loadCacheFromLocalStorage · saveCacheToLocalStorage
db()
.deferredWrite(true)
.deferredWrite(function(offlineState) {
if (offlineState != true) alert('DeferredWrite state was not set.');
})
.deferredWrite(false)
.end();
db().deferredWrite(true).deferredWrite(false).end(function(){ console.log('ok'); })
ok
db().deferredWrite(true).deferredWrite(false).end(function(){ console.log('ok'); })
ok
db().deleteCacheFromLocalStorage(cacheName)Delete a previously saved cache from the browser's local storage.
The in-memory cache is unaffected by this operation.
| Name | Type | Required | Description |
|---|---|---|---|
cacheName |
string |
✓ | The name under which the cache was previously stored in the browser's LocalStorage. |
console.log(typeof db().deleteCacheFromLocalStorage);
function
db().loadCacheFromLocalStorage(cacheName)Restore a previously saved cache from the browser's local storage.
The cache is restored to the state it was in when it was saved. This is useful, for example, when
continuing a session across browser restarts when the user has been working off-line and was not
able to synchronize with the server database.
| Name | Type | Required | Description |
|---|---|---|---|
cacheName |
string |
✓ | The name under which the cache was previously stored in the browser's LocalStorage. |
console.log(typeof db().loadCacheFromLocalStorage);
function
db().offline(torf)Set the off-line state or passes the current off-line state to a function.
An off-line state of **true** affects only the login
method and then only when deferredWrite is also true. When both are true, the login method
does not attempt to communicate with the server to authenticate the user, but instead assumes
login success and continues. This is done to allow applications that perform a login to operate
when not connected to the Internet.
| Name | Type | Required | Description |
|---|---|---|---|
torf |
boolean|function |
✓ | If this parameter is a boolean, the offline state is set to the value of the parameter. If the parameter is a function the function is called with a single argument is the current off-line value. |
db()
.offline(true)
.offline(function(offlineState) {
if (offlineState != true) alert('Offline state was not set.');
})
.offline(false)
.end();
db().offline(false).end(function(){ console.log('ok'); })
ok
db().offline(false).end(function(){ console.log('ok'); })
ok
db().saveCacheToLocalStorage(cacheName)Save the ScrewtopDb cache in the browser's local storage.
This is useful, for example, when the user is working off-line and was not able to
synchronize with the server database.
| Name | Type | Required | Description |
|---|---|---|---|
cacheName |
string |
✓ | The name under which the cache was previously stored in the browser's LocalStorage. |
console.log(typeof db().saveCacheToLocalStorage);
function
db().synchronize(onlyIfChanged, func)Synchronize the local in-memory cache with the server database.
During synchronization, differences between the server database content and the current in-memory cache
contents are resolved. Additions, modifications and deletions are propagated between the the two. If
a conflict arises, it is resolved by honoring the change with the later timestamp.
Synchronize is most useful when used in conjunction with deferredWrite(true).
| Name | Type | Required | Description |
|---|---|---|---|
onlyIfChanged |
boolean |
Optional. If true, synchronization is performed only if changes have been made to the local cache. If false or not present, synchronization is performed unconditionally. Set this parameter to true when it is unlikely that any changes have been made by others to the server database and therefore synchronization is only required when local changes have been made. Set this parameter to true to pick up any changes to topics in the local cache that have occurred in the server database since the last synchronization. |
|
func |
function |
Callback invoked when synchronization completes. |
deferredWrite · loadCacheFromLocalStorage · saveCacheToLocalStorage
db()
.deferredWrite(true)
.addTopics('albert', 'phone number', '555-1212')
.synchronize(false, function(arr) {
alert('synchronized');
})
.deferredWrite(false)
.topicByName('albert')
.tagValues('phone number')
.text()
.log()
.end();
synchronized
[
"555-1212"
]
console.log(typeof db().synchronize);
function
db().autoRenderer(cb, errcb)Creates a real-time auto-rendering system for a topic. Returns the chain instance with two new methods attached:
`subscribe` and `unsubscribe`.
An autoRenderer manages subscribing to server-sent notifications for a topic. When events occur
(additions, deletions, modifications, re-ordering of values), the autoRenderer updates the local cache
and re-populates the data. On connection errors, it automatically reconnects with retry logic.
**subscribe(notifyId, topicText, tagPrefix, renderOptions, eventFn, fetchOptions)**
Subscribes to real-time notifications for a topic. After subscribing, performs an initial fetch
of the topic data (invalidating the cache first). On subsequent events (`add`,
`delete`, `update`, `move`, `ts`), updates the local
cache and calls the `cb` callback. If the connection is lost, unsubscribes, waits 2 seconds,
and re-subscribes automatically. The optional `eventFn` is called with raw event data after
each event is processed. The `fetchOptions` parameter defaults to `{elide:true}`.
**unsubscribe(notifyId)**
Unsubscribes from notifications for the given `notifyId`.
| Name | Type | Required | Description |
|---|---|---|---|
cb |
function |
✓ | Optional. A callback invoked after every data update (passed to .end() of internal chains). |
errcb |
function |
✓ | Optional. A callback invoked whenever the connection to the server is lost. The cb functionis called when the connection is restored. |
notifyId |
string |
✓ | The notification channel ID to subscribe to. |
topicText |
string |
✓ | The topic name to watch for changes. |
tagPrefix |
string |
✓ | Tag prefix used via renderOptions. |
renderOptions |
object |
✓ | Options passed to populate. |
eventFn |
function |
✓ | Optional. Called with raw event data after each notification event is processed. |
fetchOptions |
object |
✓ | Optional. Options passed to topicByName. Defaults to {elide:true}. |
var ar = db().autoRenderer(function() {
console.log('notification processed');
}, function() {
console.log('connection lost');
});
ar.subscribe('myNotifyId', 'myTopic', '', {}, function(eventData) {
console.log('event:', eventData);
});
// Later, to unsubscribe:
ar.unsubscribe('myNotifyId');
console.log(typeof db().autoRenderer);
function
db().populate(topicName, prefix, options)Populate DOM objects from a ScrewtopDb topic using jQuery's html() and val() functions.
The text of the topic's tags specify the DOM element IDs. The tag values contain the text to be
inserted using the html() or val() function. DOM element IDs are assumed to be prefixed with the topic
name followed by a dash. Here is an example ID: myform-newpassword. The topic is myform and the
tag might be <username>/newpassword.
The ScrewtopDB Application Dashboard is populated using this method.
| Name | Type | Required | Description |
|---|---|---|---|
topicName |
string |
✓ | The topic that contains the information to be used to populate the DOM elements |
prefix |
string |
✓ | The tag prefix. This is generally the tag owner but may include additional fields as well. Use of the prefix ensures that tags with similar names created by other users do not interfere with the population of DOM elements. |
topicName |
string |
✓ | Topic name to populate the DOM from. |
prefix |
string |
✓ | CSS selector / id prefix used to locate the target DOM nodes. |
options |
object |
Render options (see autoRenderer for the shared shape). |
<!doctype html>
<html>
<head>
<title>ScrewtopDb Populate method Demo</title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
<script type="text/javascript" src="/js/ttv.node.js"></script>
<script type="text/javascript">
// Insert the topic that will be used to populate the page. (Normally
// this would not be done here, but instead perhaps using the ScrewtopDb
// topic browser to insert the information.)
function prepareDb() {
screwtopDb()
.login('<appname>', '<username>', '<password>')
.putTopic(screwtopDb.objToDb({
text: 'demo',
intro: 'ScrewtopDb populate()',
detail: 'The populate() screwtopDb method is used to insert text from the '
+ 'screwtopDb database into a web page.'
+ '<p/>'
+ 'This allows the textual content of the web page to be separated from '
+ 'the structure of the page so content can be changed without modifying '
+ 'the HTML and changes to the structure can be made without disturbing '
+ 'the content.',
button: 'Clean up'
}))
.end();
}
// Populate the page and show it. (This is the only function that would
// normally be needed in a non-demo page.)
function populatePage() {
screwtopDb()
.populate('demo', '<username>')
.end(function() {
$('body').show();
});
}
// Remove the topic we created from the database and
// clear the page. (This step would normally not be needed as the
// topic would not need to be deleted.)
function cleanup() {
screwtopDb()
.topicByName('demo')
.deleteTopics()
.end(function() {
$('body').hide().children().remove();
});
}
$(function () {
$('#demo-button').click(cleanup);
// Let's do it.
screwtopDb()
.func(prepareDb)
.func(populatePage)
.end();
});
</script>
</head>
<body style="margin:40px; padding:20px; background-color:lightgray; display:none;">
<h2 id="demo-intro"></h2>
<div id="demo-detail" style="width:400px;"></div>
<button id="demo-button" style="margin-top: 20px;"/>
</body>
</html>
console.log(typeof db().populate);
function
<!-- HTML: <div id='alice-city'></div> -->
db().addTopics('Alice', 'city', 'Berkeley').end()
db().populate('Alice', 'alice-').end()
<div id='alice-city'>Berkeley</div>
db().autoRenderer(cb).subscribe(notifyId, topicText, tagPrefix, renderOptions, eventFn, fetchOptions)Open a server-sent-events connection and re-render a topic into the DOM whenever the server broadcasts a change.
**subscribe** and unsubscribe are attached to a chain instance by
autoRenderer — they are not standalone chain steps. Browser-only (depends on
`EventSource`).
| Name | Type | Required | Description |
|---|---|---|---|
notifyId |
string |
✓ | SSE channel identifier. Must match the id used by any notify call that should trigger this subscriber. |
topicText |
string |
✓ | The name of the topic to subscribe to and render. |
tagPrefix |
string |
✓ | Regex prefix for tag names to include. Pass ".*" to include everything. |
renderOptions |
object |
Optional. Pipe functions for custom rendering, keyed by the |name suffix on the data-db attribute. |
|
eventFn |
function |
Optional. Invoked with the raw SSE actions object after every event. | |
fetchOptions |
object |
Optional. Options object forwarded to the internal topicByName call that performs the initial fetch. Defaults to {elide:true}. |
console.log(typeof db().autoRenderer(function(){}).subscribe);
function
console.log(typeof db().subscribe);
undefined
db().autoRenderer(cb).unsubscribe()Close the SSE connection opened by an earlier subscribe call. Like subscribe, this is
attached by autoRenderer.
console.log(typeof db().autoRenderer(function(){}).unsubscribe);
function
console.log(typeof db().unsubscribe);
undefined
db().onError(func)Invoke a specified function when an error occurs.
By default errors are logged and query sequence execution is terminated when an error occurs. This function allows you to
specify additional actions to be executed when an error occurs.
| Name | Type | Required | Description |
|---|---|---|---|
func |
function(errObj) |
The function to invoke on error. Receives the error object; return true to stop the sequence, false to continue. Omit to remove the current handler. |
// Handle the unrecognized application error.
function errorHandler(errorText) {
alert(errorText);
return true;
}
db()
.appName('bogus-appname')
.onError(errorHandler)
.topicByName('bogus-topic')
.log("This text will not be displayed.")
.end();
// Example error object:
{ result: 'Unrecognized application' }
db().onError(function(){}).end(function(){ console.log('ok'); })
ok
db().onError(function(){}).end(function(){ console.log('ok'); })
ok
db().terminateOnError(torf)Disable or enable query sequence termination when an error occurs.
By default query sequence execution is terminated when an error occurs. This function allows you to
allow termination to continue after an error.
This function is most useful during testing.
| Name | Type | Required | Description |
|---|---|---|---|
torf |
boolean |
Optional. False to continue execution after an error. Default is true. |
throwErrors · logErrors · onError · abort
// Continue after the unrecognized application error.
db()
.appName('bogus-appname')
.terminateOnError(false)
.topicByName('bogus-topic')
.log("Continuing after error.")
.terminateOnError()
.end();
db().terminateOnError(false).end(function(){ console.log('ok'); })
ok
db().throwErrors(torf)Throw an exception when an error occurs.
By default errors are logged. This function allows you to cause errors to throw exceptions.
**Note:** You cannot catch exceptions thrown by ScrewtopDb query sequences by enclosing the sequence
in a try block because the query is not actually executed until after the try-catch block has been
exited. This means that error exceptions will always cause termination of the script. In almost all
cases, the onError function is a better choice.
| Name | Type | Required | Description |
|---|---|---|---|
torf |
boolean |
Optional. False to disable throwing error exceptions. Default is true. |
// Throw the unrecognized application error normally logged when no app has been specified.
db()
.appName('bogus-appname')
.throwErrors()
.topicByName('bogus-topic')
.throwErrors(false)
.end();
db().throwErrors(false).end(function(){ console.log('ok'); })
ok
db().throwErrors(false).end(function(){ console.log('ok'); })
ok
try(opFn, [onSuccess], [onFailure])Run an operation as an isolated sub-chain, capture whether it produced an error, then run exactly one branch — onSuccess or onFailure — before continuing the enclosing chain. A failure inside the operation is captured: it does NOT invoke the module-level onError handler and does NOT terminate the enclosing chain. onFailure receives the captured error object as its second argument.
Each branch callback receives a fresh chain to build on and must NOT call .end() — try() owns the sub-chain lifecycle. The operation fragment is seeded with the enclosing result set so opFn can read its inbound context, but try() is a control-flow bracket: the enclosing result set passes through UNCHANGED to the steps after .try(), and onSuccess cannot see what the operation produced. If you need the operation’s output downstream, use a plain chain with explicit error handling instead.
| Name | Type | Required | Description |
|---|---|---|---|
opFn |
function |
✓ | The operation, run as an isolated sub-chain. Receives a fresh chain seeded with the enclosing result set; must NOT call .end(). |
onSuccess |
function |
Run (with a fresh chain) when the operation completes without error. | |
onFailure |
function |
Run when the operation fails; receives (freshChain, capturedError). |
// .try() runs the operation in isolation; a failure routes to
// onFailure without aborting the enclosing chain.
db().try(
function(op){ op.addTopics('Widget','price','9.99'); },
function(ok){ ok.log('add succeeded'); },
function(fail, err){ fail.log('add failed: ' + err); }
).topicByName('Widget').values().text()
.end(function(vals){ console.log(vals); })
["9.99"]
db().log(text)Output the current result set or a text string.
In the Node.js environment, output is directed by default to the console. In the browser
environment, output is displayed by default in an alert box. The output destination may be
changed using the logFunc method.
This step passes the current result set unchanged to the following step.
| Name | Type | Required | Description |
|---|---|---|---|
text |
string |
Optional. Text to be output. If this parameter is not present, a formatted representation of the current result set is output. |
logText · trace · logRequests · logResponses
db()
.log('Test')
.end()
Test
db().fn(function(){ console.log('Test'); }).end()
Test
db().fn(function(){ console.log('Test'); }).end()
Test
db().logErrors(torf)Suppress or enable logging of errors.
By default errors are logged. This function allows you to cause errors not to be displayed in any way.
This function is most useful during testing.
| Name | Type | Required | Description |
|---|---|---|---|
torf |
boolean |
Optional. False to disable logging of errors. Default is true. |
// Suppress the error normally logged an unrecognized application has been specified.
db()
.appName('bogus-appname')
.logErrors(false)
.topicByName('bogus-topic')
.logErrors(true)
.end();
db().logErrors(false).logErrors(true).end(function(){ console.log('ok'); })
ok
db().logErrors(false).logErrors(true).end(function(){ console.log('ok'); })
ok
db().logFunc(func)Replace the default logging function.
The default logging function displays an alert dialog when in the browser environment and logs to the console in the
Node.js environment. This function allows to replace the default logging function with one of your own.
| Name | Type | Required | Description |
|---|---|---|---|
func |
function |
A function that receives log output in place of the console. |
// Log to a buffer.
var logMessages = '';
function myLogger(text) {
logMessages += text + '\n\n';
}
db()
.appName('<appname>')
.logFunc(myLogger)
.topicByName('user:<username>')
.log('Retrieved topic:')
.log() // This logs the retrieved topic
.end(function() {
// Show the messages.
alert(logMessages);
});
db().logFunc(function(){}).end(function(){ console.log('ok'); })
ok
db().logRequests(torf)Log HTTP requests to the server.
This function is only functional in the Node.js environment.
By default server requests and responses are not logged.
Outgoing requests are prefixed with "`-->`" to distinguish them from server responses.
| Name | Type | Required | Description |
|---|---|---|---|
torf |
boolean |
Optional. False to disable logging of server requests. Default is true. |
logResponses · log · trace
db()
.appName('<appname>')
.logRequests()
.topicByName('user:<username>')
.logRequests(false)
.end();
db().logRequests(false).end(function(){ console.log('ok'); })
ok
db().logRequests(false).end(function(){ console.log('ok'); })
ok
db().logRequestTimes(torf)Enable or disable console logging of HTTP request timing information.
When enabled, each log line includes a request number, timestamp, server time, total time,
cumulative time, HTTP method, and URL.
| Name | Type | Required | Description |
|---|---|---|---|
torf |
boolean |
✓ | True to enable logging of request times, false to disable. Defaults to true if not a boolean. |
logRequests · logResponses · saveRequestTimes · requestTimes
db()
.logRequestTimes(true)
.topicByName('myTopic')
.end();
db().logRequestTimes(false).end(function(){ console.log('disabled'); })
disabled
db().logResponses(torf)Log HTTP server responses.
This function is only functional in the Node.js environment.
By default server requests and responses are not logged.
Incoming requests are prefixed with "`<--`" to distinguish them from requests to the server.
| Name | Type | Required | Description |
|---|---|---|---|
torf |
boolean |
Optional. False to disable logging of server responses. Default is true. |
logRequests · log · trace
db()
.appName('<appname>')
.logRequests()
.logResponses()
.topicByName('user:<username>')
.logRequests(false)
.logResponses(false)
.end();
db().logResponses(false).end(function(){ console.log('ok'); })
ok
db().logResponses(false).end(function(){ console.log('ok'); })
ok
db().logText(strip)Output the the text members of the current result set.
In the Node.js environment, output is directed by default to the console. In the browser
environment, output is displayed by default in an alert box. The output destination may be
changed using the logFunc method.
This step passes the current result set unchanged to the following step.
| Name | Type | Required | Description |
|---|---|---|---|
strip |
boolean |
Optional. True to strip UUIDs from the output text. |
log · trace · logRequests · logResponses
db().addTopics({text:'persons',friends:[{text:'Andy',gender:'male'},{text:'Mary',gender:'female',spouse:'Bill'},{text:'Bill',gender:'male',spouse:'Mary'}],coworkers:[{text:'Frank',gender:'male'},{text:'Wendy',gender:'female'}]}).end()
db()
.topicByName('persons')
.tags()
.values()
.logText()
.end();
Andy
Mary
Bill
Frank
Wendy
db().fn(function(){ console.log('hello'); }).end()
hello
db().fn(function(){ console.log('hello'); }).end()
hello
db().trace(enable)Enable or disable tracing of query sequence execution.
In the Node.js environment, output is directed by default to the console. In the browser
environment, output is displayed by default in an alert box. The output destination may be
changed using the logFunc method.
This method is intended to aid in debugging. In the browser environment, it is most useful
when combined with the output redirection using the logFunc method.
This step passes the current result set unchanged to the following step.
| Name | Type | Required | Description |
|---|---|---|---|
enable |
boolean |
✓ | True ot enable tracing, false to disable. |
db().addTopics({text:'persons',friends:[{text:'Andy',gender:'male'},{text:'Mary',gender:'female',spouse:'Bill'},{text:'Bill',gender:'male',spouse:'Mary'}],coworkers:[{text:'Frank',gender:'male'},{text:'Wendy',gender:'female'}]}).end()
db()
.trace(true)
.topicByName('persons')
.tags()
.values()
.logText()
.end();
Step 7: topicByName("persons")
Step 8: tags()
Step 9: values()
Step 10: logText()
Andy
Mary
Bill
Frank
Wendy
Step 11: end(function(){})
db().trace(false).end(function(){ console.log('ok'); })
ok
db().trace(false).end(function(){ console.log('ok'); })
ok
db().cacheStats(func)Log the ScrewtopDB cache statistics or pass them to the optionally-provided function.
The object passed to the function contains two integer members: hits and misses.
| Name | Type | Required | Description |
|---|---|---|---|
func |
function(statsObj) |
✓ | Optional. The function to be invoked. The return value of this function is ignored. If this function is not provided or something other than a function is passed, the cache statistics are logged. |
// Fetch a topic twice and observe that the second fetch came from cache.
db()
.appName('<appname>')
.invalidateCache() // Make sure we actually fetch it
.topicByName('user:<username>')
.cacheStats(function(statsObj) {
hits = statsObj.hits;
misses = statsObj.misses;
})
.topicByName('user:<username>')
.cacheStats(function(statsObj) {
if (statsObj.hits > hits) alert('The cache is working.');
})
.end();
db().cacheStats(function(s){ console.log(typeof s); }).end()
object
db().clearRequestTimes()Log request timings
Request timing is displayed in a single line and includes, for each server request
- requestNumber - The 1-based index of the request
- timestamp - The time the request was made
- serverTime - The time the server application code spent processing the request
- networkTime - The total time minus the server time.
- totalTime - The time the client spent waiting for the response from the server. This time
includes the time spent transmitting the request and receiving the response as well as the server time.
- request - The method (GET, PUT, POST, or DELETE) and the URL path of the request
| Name | Type | Required | Description |
|---|---|---|---|
torf |
boolean |
✓ | Optional. True to start logging request times, false to stop. The default is true |
See the example for saveRequestTimes.
Example request time log line:
2 2011-09-02T23:04:29Z 126/559/685 PUT https://www.screwtopdb.com/303/topics.json?&session=7bfa894f57ac6da8
db().clearRequestTimes(); console.log('ok');
ok
console.log(typeof db().clearRequestTimes);
function
db().lastRequestTime(func)Invoke the provided function passing as its arguments statistics related to the time that was required to process
the last request.
All times are in milliseconds.
The time required to process a request includes
- Client preparation time - the time required to prepare the request in the client (generally negligable)
- Request transmission time - the time required to transfer the request over the network and dispatch it to the server code
that processes the request.
- Server processing time - the time required by the server to process the request and produce a response.
- Response transmission time - the time required to transfer the response to the client over the network and dispatch
it to the client code that processes the response.
In the example below, number one above is ignored and numbers two and four are combined into "Network transfer
time".
Note that often requests for data are served from the client-side cache, and when this happens, no server request is
issued. In this case the last saved times remain in place and the requestCount is not incremented.
| Name | Type | Required | Description |
|---|---|---|---|
func |
function |
✓ | Callback invoked with the timestamp (ms) of the most recent server request. |
db().addTopics({text:'persons',friends:[{text:'Andy',gender:'male'},{text:'Mary',gender:'female',spouse:'Bill'},{text:'Bill',gender:'male',spouse:'Mary'}],coworkers:[{text:'Frank',gender:'male'},{text:'Wendy',gender:'female'}]}).end()
db()
.topicByName('persons')
.lastRequestTime(function(totalTime, serverTime) {
alert('total time is a number: ' + (typeof totalTime === 'number'));
})
.end();
total time is a number: true
console.log(typeof db().lastRequestTime);
function
console.log(typeof db().lastRequestTime);
function
db().requestTimes(func)Invoke a user-supplied function, passing it an array of saved request timing information.
See the example for saveRequestTimes.
console.log(typeof db().requestTimes);
function
console.log(typeof db().requestTimes);
function
db().saveRequestTimes(torf)Save request timing information for later processing.
Request timing information saved includes, for each server request
- requestNumber - The 1-based index of the request
- timestamp - The time the request was made
- serverTime - The time the server application code spent processing the request
- totalTime - The time the client spent waiting for the response from the server. This time
includes the time spent transmitting the request and receiving the response as well as the server time.
- request - The method (GET, PUT, POST, or DELETE) and the URL path of the request
| Name | Type | Required | Description |
|---|---|---|---|
torf |
boolean |
✓ | Optional. True to enable saving request times, false to disable. The default is true |
db()
.saveRequestTimes()
.addTopics('persons', 'friends', 'Ralph')
.requestTimes(function(times) {
alert('captured requests: ' + (times.length > 0));
})
.saveRequestTimes(false)
.clearRequestTimes()
.end();
captured requests: true
db().saveRequestTimes(false).end(function(){ console.log('ok'); })
ok
db().saveRequestTimes(false).end(function(){ console.log('ok'); })
ok
allSymbols([options])Return the app's interned symbol registry — the global list of text symbols underlying every topic, tag and value. Each entry carries the symbol id, text, primary frame id (fid) and reference-count bookkeeping. This is an introspection/diagnostic tool (the topic browser's all-symbols view is built on it); most applications never need it.
| Name | Type | Required | Description |
|---|---|---|---|
options |
object |
Optional bag passed through to the server symbol dump. |
db().addTopics('Alice', 'city', 'SF').end()
db().allSymbols().end(function(syms){ console.log(syms.length > 0); })
true
db().appInfo(options)Fetch application information
the following information is returned. Items marked with + are only included if the requesting user
is the responsible user of the app.
- appId
- appName
- responsibleUserId
- responsibleUserName
- + application attribute names and values
- + for each app user, username, userId, admin flag, lastLogin, privileges
db().appInfo().end(function(info){ console.log(typeof info); })
object
db().attributes(attrName,u)Fetch all user attributes or a specific user attribute.
Attributes are name/value pairs that are saved on a per-user basis. Only the owning user (and the
app's responsible user) may access user attributes. For this reason attributes are useful for saving
such information as an email address and other personal information that should not be exposed to other
users but that may be needed to perform actions for the logged-in user.
ScrewtopDb creates and maintains the user attribute userTopicId which contains the identifier of
the user topic. This attribute may not be modified or deleted.
This method replaces the result set with the returned attribute objects.
| Name | Type | Required | Description |
|---|---|---|---|
attrName |
string |
Optional. The name of the attribute to fetch. If this parameter is not supplied, all attributes are returned. |
|
username |
string |
Optional. The user whose attributes are to be retrieved. Only a super-user can retrieve another user's attributes. |
db().putAttributes([{name:'login count', value:'147'}]).end()
db()
.attributes(['login count'])
.each(function(attr) {
alert('Login count: ' + attr.value);
})
.end();
Login count: 147
db().putAttributes([{name:'greet',value:'hi'}]).end()
db().attributes(['greet']).end(function(a){ console.log(a[0].value); })
hi
console.log(typeof db().attributes);
function
db().createUnauthenticatedUser(appName, username, email)Create an unauthenticated user.
Unauthenticated users may have an inactivity lifetime specified in the application
attribute UnauthentcatedUserInactiveLifetimeMin. If the application is not accessed
by the user within the inactive lifetime, the user's account and all contributed
data are automatically deleted.
If username is not provided, a random username is returned by the server.
The returned pseudo-topic contains the assigned username, if any, and the assigned
password for the new account.
This method is only available if application attributes related to it are
defined. Such attributes include UnauthenticatedAddTopic, UnauthenticatedAddTag, UnauthenticatedAddValue,
UnauthenticatedSync, UnauthenticatedVote, and UnauthenticatedUpdate. UnauthenticatedRead is not one of them: it governs reads, which need no unauthenticated user, and setting it to true does not enable this method.
| Name | Type | Required | Description |
|---|---|---|---|
appName |
string |
The application name. If not provided, the current application is used. |
|
username |
string |
The username desired. | |
email |
string |
Optional. The email address to be used for warnings of impending account deletion due to inactivity. |
db()
.createUnauthenticatedUser()
.each(function(t) {
console.log('Has generated username: ' + (t.username[0].length > 0));
console.log('Has generated password: ' + (t.password[0].length > 0));
})
.end()
Has generated username: true
Has generated password: true
console.log(typeof db().createUnauthenticatedUser);
function
db().createUser(username, pswd, email, appName, loginUrl, admin)Create a new ScrewtopDb application user.
Depending on the application options in effect, this method may
- only be invoked successfully by the app's responsible user,
- result in a confirmation email being sent to the specified email address, or
- none of the above.
| Name | Type | Required | Description |
|---|---|---|---|
username |
string |
✓ | The username desired. |
pswd |
string |
✓ | The password to be associated with the username |
email |
string |
Optional. The email address to be used for confirmation. This parameter is required if email confirmation of new accounts is required by the application. |
|
appName |
string |
Optional. The application name used in confirmation emails. The default is the current application. |
|
loginUrl |
string |
Optional. The URL to which the user is to be directed in the confirmation email, if any. |
|
admin |
boolean |
Optional. True to create an application administrator account. Administrators may impersonate other application users and log in as the application itself. This parameter is ignored unless the currently logged in user is the responsible user or an administrator. |
See the example for saveSession.
console.log(typeof db().createUser);
function
db().createUser2(user)Create a new ScrewtopDb application user.
Depending on the application options in effect, this method may
- only be invoked successfully by the app's responsible user,
- result in a confirmation email being sent to the specified email address, or
- none of the above.
| Name | Type | Required | Description |
|---|---|---|---|
user |
object |
✓ | An object which contains the following members: - username - password - email Required if email confirmation of new accounts is required by the application. - loginUrl Optional. The URL to which the user is to be directed in the confirmation email, if any - appName Optional. The application name used in confirmation emails. The default is the current application. - admin Optional. True to create an application administrator account. Administrators may impersonate other application users and log in as the application itself. This parameter is ignored unless the currently logged in user is the responsible user or an administrator. - Other members which will become user attributes. |
console.log(typeof db().createUser2);
function
db().deleteApp(appName)Delete an entire application, along with all of its topics, tags, values, and users. May only be invoked by the
admin user or the app's responsible user. Irreversible — there is no undo.
console.log(typeof db().deleteApp);
function
db().deleteAttributes(arg,u)Delete user attributes by name.
Attributes are name/value pairs that are saved on a per-user basis. Only the owning user (and the
app's responsible user) may access user attributes. For this reason attributes are useful for saving
such information as an email address and other personal information that should not be exposed to other
users but that may be needed to perform actions for the logged-in user.
ScrewtopDb creates and maintains the user attribute userTopicId which contains the identifier of
the user topic. This attribute may not be modified or deleted.
If this method is invoked without an argument, attributes in the current result set are deleted. See the
example for how this can be used to delete all attributes.
| Name | Type | Required | Description |
|---|---|---|---|
attrnames |
array|string |
Optional. The names of the attributes to be deleted. This may be an array of strings or a comma-separated list of the names to be deleted. |
|
username |
string |
Optional. The user whose attributes are to be deleted. Only a super-user can delete another user's attributes. |
function mine(attrs) {
return ['email','phone'].filter(function(n) {
return attrs.some(function(a){ return a.name === n; });
}).join(',');
}
db()
.putAttributes([{ name: 'email', value: '[email protected]' },
{ name: 'phone', value: '206 555-1212' }])
.attributes()
.fn(function(attrs) { console.log('after put: ' + mine(attrs)); })
.deleteAttributes(['email'])
.attributes()
.fn(function(attrs) { console.log('after delete: ' + mine(attrs)); })
.end();
after put: email,phone
after delete: phone
db().putAttributes([{name:'k',value:'v'}]).end()
db().deleteAttributes(['k']).end(function(){ console.log('ok'); })
ok
db().putAttributes({delAttr_deleteAttributes:'val'}).end()
db().deleteAttributes(['delAttr_deleteAttributes']).end(function(){ console.log('ok'); })
ok
db().deleteUser(arg)Delete a specified user from the current app.
A user may delete themselves and the app's responsible user may delete other users.
This action is irrevocable. The user's database objects will be deleted except where doing so
would necessitate deleting another user's database objects. This might occur, for example if the
user being deleted had created a topic to which another user had added a tag and value.
| Name | Type | Required | Description |
|---|---|---|---|
username |
string |
✓ | The username of the user to delete. |
See the example for saveSession.
console.log(typeof db().deleteUser);
function
db().diagnose()Verify consistency of application data
Performs a consistency check of the app data and returns results. This
is intended for use by Screwtop only.
db().diagnose(false).end(function(){ console.log('ok'); })
ok
db().putApp(newData)Create a new application
This method may only be executed by the ScrewtopDb administrator account and is thus
not available to normal users, even the responsible users of other apps. Visit
The ScrewtopDb Dashboard to create a
new app.
| Name | Type | Required | Description |
|---|---|---|---|
An |
object |
✓ | object containing the following members: appName, appDescription, responsibleUserName, and responsibleUserPassword. |
console.log(typeof db().putApp);
function
db().putAttributes(attrs, u)Create or update user attributes
Attributes are name/value pairs that are saved on a per-user basis. Only the owning user (and the
app's responsible user) may access user attributes. For this reason attributes are useful for saving
such information as an email address and other personal information that should not be exposed to other
users but that may be needed to perform actions for the logged-in user.
ScrewtopDb creates and maintains the user attribute userTopicId which contains the identifier of
the user topic. This attribute may not be modified or deleted.
| Name | Type | Required | Description |
|---|---|---|---|
attrs |
object|array |
✓ | The attribute objects. Attribute objects have two members, name and value whose values are strings. |
username |
string |
Optional. The user whose attributes are to be affected. Only a super-user can update another user's attributes. |
See the example for deleteAttributes.
db().putAttributes([{name:'app_attr',value:'value'}]).end(function(){
db().attributes(['app_attr']).end(function(a){ console.log(a[0].value); });
})
value
console.log(typeof db().putAttributes);
function
db().resetUserPassword(username, newpassword)Administrative password reset for another user. May only be invoked by the app's responsible user or an admin user.
The user's own password (for self-service change) goes through updateUser with a
`password` attribute instead.
console.log(typeof db().resetUserPassword);
function
db().sendEmail(to, from, subj, text, html, bcc, fwd)Send email on behalf of the authenticated user
Send an email message to a specified addressee using the email configuration
previously saved in user attributes. The user attributes that must be present are
- EmailServerAddress (example: smtp.myserver.com)
- EmailServerPort (a number, example: 465)
- EmailUsesTLS (true or false, true for secure mail)
- EmailServerUsername
- EmailServerPassword
At least one of text, html, or fwd must be present. If either text or html is
present, fwd is ignored.
| Name | Type | Required | Description |
|---|---|---|---|
to |
string |
✓ | A comma spearated list of the email addresses of the intended recipients |
from |
string |
✓ | The from address to be specified in the email |
subj |
string |
✓ | The subject line |
text |
string |
✓ | The plaintext email content (optional) |
html |
string |
✓ | The HTML email content (optional) |
bcc |
string |
✓ | A comma-separated list the email addresses of the blind-copy recipients (optional) |
fwd |
string |
✓ | A complete rfc822 mail message to be forwarded (optional) |
console.log(typeof db().sendEmail);
function
db().sendPasswordReminder(username)Send a message to the a user's email address containing new password information
The result set is replaced with a string such as the one below:
"A password reminder message has been sent to the email address associated with the username <username>, if any."
The subject of the email message is "<appname> account reminder".
The email message contains text such as the following:
"The password for your <appname> account has been set to wihyterobi."
The email is sent using the email information stored in the relevant application attributes. (See the
Srewtopdb Book sections on Application Attributes and Email
Confirmation for details.
| Name | Type | Required | Description |
|---|---|---|---|
username |
string |
✓ | The name of the user to whom the reminder message is to be sent. |
db()
.appName('myapp')
.sendPasswordReminder('some-username')
.log()
.end()
A password reminder message has been sent to the email address associated with the username some-username, if any.
console.log(typeof db().sendPasswordReminder);
function
db().sendUsernameReminder(email)Send a message to the a user's email address containing the usernames registered with that email address
The result set is replaced with a string such as the one below:
"A reminder message containing the username(s) associated with <emailaddress>, if any, has been sent."
The subject of the email message is "<appname> account reminder".
The email message sent contains text such as the following:
The following <appname> username(s) are associated with the email address <emailaddress>:
<username>
| Name | Type | Required | Description |
|---|---|---|---|
email |
string |
✓ | address to which the reminder message is to be sent. |
db()
.appName('myapp')
.sendUsernameReminder('[email protected]')
.log()
.end()
A reminder message containing the username(s) associated with [email protected], if any, has been sent.
console.log(typeof db().sendUsernameReminder);
function
db().updateUser(attrs)Update user account information and attributes
Attributes are name/value pairs that are saved on a per-user basis. Only the owning user (and the
app's responsible user) may access user attributes. For this reason attributes are useful for saving
such information as an email address and other personal information that should not be exposed to other
users but that may be needed to perform actions for the logged-in user.
ScrewtopDb creates and maintains the user attribute userTopicId which contains the identifier of
the user topic. This attribute may not be modified or deleted.
This method performs essentially the same function as putAttributes except
that the distinguished attributes email and password are included in the set of attributes that may be updated.
Note that the user attributes username and votes may not be updated.
| Name | Type | Required | Description |
|---|---|---|---|
attrsobj |
object |
✓ | An object whose members are attribute names, the values of which are attribute values. Note that this object is different than the array of name-value pairs used in the putAttributes and attributes methods. |
username |
string |
Optional. The user whose attributes are to be updated. Only a super-user can update another user's attributes. |
console.log(typeof db().updateUser);
function
db().assert(func, errText)Execute a function and thow or log an assertion failure if it returns false.
This method is intended for use in unit tests.
| Name | Type | Required | Description |
|---|---|---|---|
func |
function |
✓ | The function to be executed. The single argument is the current result set. If this function returns true, sequence execution is unaffected. If it returns false, an exception is thrown or an assertion failure message is logged and sequence execution is terminated. |
errText |
string |
✓ | The text to be logged if the function above returns false. |
var seen=false; db().setValues([1]).assert(function(arr){ seen=arr.length===1; return true; }).end(function(){ console.log(seen); })
true
db().deny(func, errText)Execute a function and throw or log an assertion failure if it returns true.
This method is intended for use in unit tests.
| Name | Type | Required | Description |
|---|---|---|---|
func |
function |
✓ | The function to be executed. The single argument is the current result set. If this function returns true, sequence execution is unaffected. If it returns true, an exception is thrown or an assertion failure message is logged and sequence execution is terminated. |
errText |
string |
✓ | The text to be logged if the function above returns true. |
var seen=false; db().setValues([]).deny(function(arr){ seen=arr.length>0; return false; }).end(function(){ console.log(seen); })
false
console.log(typeof db().deny);
function
db().clear()Clear the current result set.
The result set is the array of objects passed to the next step in the sequence. This
method clears that array.
db()
.setValues([1, 2, 3])
.clear()
.log()
.end();
[]
db().setValues([1,2]).clear().end(function(arr){ console.log(arr); })
[]
db().setValues([1,2]).clear().end(function(arr){ console.log(arr); })
[]
db.pathValueIdForTopic(arg)Get the value that led you to a topic.
Each time the topics method is executed, it saves the objects from which
it obtained the topic IDs that it will be fetching. The pathValueIdForTopic utility method, given
a topic or topic ID, returns the value that was last used to navigate to the topic. Note that many
topics may contain values referencing the specified topic. The one that is returned by this method is the one
that was last used by the topics method to retrieve the topic.
This can be useful in the circumstance where the topic referenced by a value needs to be retrieved in
order to determine what action to take on the value (e.g. deletion).
| Name | Type | Required | Description |
|---|---|---|---|
topicId |
topicId |
✓ | The topic ID for which the path value is being requested. |
console.log(typeof db.pathValueIdForTopic);
function
db().options(obj)Set options affecting the behavior of the ScrewtopDB Javascript library.
The following options may be set using this function by passing an object containing the
members shown:
{ tagPrefix: "user"|"app"|<string>> }
The tagPrefix option defines the prefix that will be applied to tag specifications.
The value of the tagPrefix option may be
- "user" - The username of the currently logged in user, if any.
- "app" - The application name of the current application, if any.
- a string - If the value is neither "user" or "app", then the the string itself is used.
Tag specifications are of the form owner/tagname where owner is the username of the tag's
owner and tagname is the name of the tag.
Note that there is also a short form of tag specification. A tag may be prefixed with ./ or
../ in place of the owner. When the tag is encountered by the ScrewtopDB Javascript library,
the ./ prefix is replaced by the username of the currently logged-in user.
The ../ prefix is replaced by the the application name of the current application.
| Name | Type | Required | Description |
|---|---|---|---|
obj |
object |
✓ | The options object containing a member and associated value for each option. |
// Set the tagPrefix option so that the current logged-in user is assumed to be the owner of
// tags specified without an owner field.
db()
.login('<appname>', '<username>', '<password>')
.options({ tagPrefix: 'app' })
.topicByName('user:<username>')
.tagValues('login count')
.each(function(val) {
alert('Login count: ' + val.text);
})
.end();
db().options({}).end(function(){ console.log('ok'); })
ok
db().options({}).end(function(){ console.log('ok'); })
ok
db().url(arg)Set or get the web address of the ScrewtopDB server
This is primarily for use by Twistoff Software but might be useful if you are
accessing the ScrewtopDB server via a proxy.
The default value is https://www.screwtopdb.com.
| Name | Type | Required | Description |
|---|---|---|---|
arg |
string | function(addr) |
✓ | If this argument is a string, it is the URL of the server to which requests will be sent. If this argument is a function, the function will be invoked and passed as its single argument the URL of the current ScrewtopDB server. The return value of the function is ignored. |
db()
.url(function(addr) {
alert("Default server is " + addr + ".");
})
.url('http://localhost')
.url(function(addr) {
alert("Default server is now " + addr + ".");
})
.end()
console.log(typeof db().url);
function
console.log(typeof db().url);
function
db.abortAll()Cancel all pending chain executions by resetting the function sequencer queues.
This effectively abandons all in-flight query sequences. Sequences initiated with
fork or go are also terminated.
db.abortAll();
db.abortAll(); console.log('ok');
ok
db.addTopicMembers(topic)Augment a topic object with convenience properties derived from its tags.
For each tag in the topic, creates a property on the topic object named after the tag's text
(with the owner prefix stripped), whose value is an array of the tag's value text strings.
Non-standard properties are removed first. The tag named `text` is skipped to avoid
overwriting the topic's own `.text` property.
| Name | Type | Required | Description |
|---|---|---|---|
topic |
object |
✓ | A ScrewtopDB topic object with a .tags array. |
db().addTopics({text:'person', name:'Alice', comments:['Great!','Thanks']}).end()
db()
.topicByName('person')
.first(function(topic) {
db.addTopicMembers(topic);
console.log(JSON.stringify(topic.comments));
})
.end();
["Great!","Thanks"]
var t={text:'X',tags:[{text:'k',values:[{text:'v'}]}]}; db.addTopicMembers(t); console.log(t.k);
["v"]
db.applyPatch(p, o)Apply a diff-match-patch text patch to a string.
Takes a patch produced by db.makePatch and applies it to the
original string, returning the patched result.
| Name | Type | Required | Description |
|---|---|---|---|
p |
string |
✓ | A patch in text format, as produced by db.makePatch. |
o |
string |
✓ | The original string to apply the patch to. |
var patch = db.makePatch('hello', 'hello world');
var result = db.applyPatch(patch, 'hello');
console.log(result); // "hello world"
"hello world"
var p=db.makePatch('hi','hi there'); console.log(db.applyPatch(p,'hi'));
hi there
db.dataFunctor(name)Create a functor (closure) that returns the current value of a named key from the shared data store
when invoked.
This allows deferred/lazy evaluation — the value is looked up at call time, not at creation time.
The returned function is internally marked so the library can identify it as a ScrewtopDB functor.
| Name | Type | Required | Description |
|---|---|---|---|
name |
string |
✓ | The key in the shared data store. |
db.setData('myTopicName', 'blog-article');
var getTopicName = db.dataFunctor('myTopicName');
db()
.topicByName(getTopicName)
.end();
db.setData('k','v'); var f=db.dataFunctor('k'); console.log(f());
v
db.getData(name)Retrieve a value from the shared module-level key-value data store.
| Name | Type | Required | Description |
|---|---|---|---|
name |
string |
✓ | The key to look up. |
db.setData('currentUser', 'alice');
console.log(db.getData('currentUser')); // "alice"
db.setData('k','v'); console.log(db.getData('k'));
v
db.isArguments(v)Return true if the argument is an arguments object.
When control enters the execution context of a Javascript function an arguments object is created.
The arguments object has an array-like structure with an indexed property for each passed argument
and a length property equal to the total number of parameters supplied by the caller.
| Name | Type | Required | Description |
|---|---|---|---|
v |
any |
✓ | The argument to be tested. |
db.isFunction · db.isRegExp · db.isNumber · db.isBoolean · db.isObject · db.isString · db.isDefined · db.isEmpty
function test(x) {
alert(db.isArguments(arguments));
alert(db.isArray(arguments));
}
test(1);
true
console.log(db.isArguments({}));
false
db.isArray(v)Return true if the argument is an array.
| Name | Type | Required | Description |
|---|---|---|---|
v |
any |
✓ | The argument to be tested. |
value |
any |
✓ | The value to store. |
db.isFunction · db.isRegExp · db.isNumber · db.isBoolean · db.isObject · db.isString · db.isDefined · db.isEmpty
alert(db.isArray([ 1, 2 ]) + '\n' + db.isArray('xyz'));
true
false
console.log(db.isArray([1,2,3]));
true
console.log(db.isArray([1, 2, 3]))
true
db.isBoolean(v)Return true if the argument is a boolean.
| Name | Type | Required | Description |
|---|---|---|---|
v |
any |
✓ | The argument to be tested. |
db.isArray · db.isFunction · db.isNumber · db.isRegEx · db.isObject · db.isString · db.isDefined · db.isEmpty
alert(db.isBoolean(false) + '\n' + db.isBoolean(1 == 2));
true
true
console.log(db.isBoolean(true));
true
db.isDefined(v)Return true if the argument is defined.
| Name | Type | Required | Description |
|---|---|---|---|
v |
any |
✓ | The argument to be tested. |
db.isArray · db.isFunction · db.isNumber · db.isRegEx · db.isBoolean · db.isObject · db.isString · db.isEmpty
alert(db.isDefined(db().topicByName) + '\n' + db.isDefined(db.bogus));
true
false
console.log(db.isDefined(0));
true
db.isEmpty(value, allowBlank)Return true if the argument is an empty string, null, or undefined.
| Name | Type | Required | Description |
|---|---|---|---|
v |
any |
✓ | The argument to be tested. |
allowBlank |
boolean |
✓ | True to not consider a zero-length string empty |
db.isArray · db.isFunction · db.isNumber · db.isRegEx · db.isBoolean · db.isObject · db.isString · db.isDefined
alert(db.isEmpty(null) + '\n' + db.isEmpty('') + '\n' + db.isEmpty('', true));
true
true
false
console.log(db.isEmpty(''));
true
db.isFunction(v)Return true if the argument is a function.
| Name | Type | Required | Description |
|---|---|---|---|
v |
any |
✓ | The argument to be tested. |
db.isArray · db.isRegExp · db.isNumber · db.isBoolean · db.isObject · db.isString · db.isDefined · db.isEmpty
alert(db.isFunction(function(){}) + '\n' + db.isFunction('xyz'));
true
false
console.log(db.isFunction(function(){}));
true
db.isNumber(v)Return true if the argument is a number.
| Name | Type | Required | Description |
|---|---|---|---|
v |
any |
✓ | The argument to be tested. |
db.isArray · db.isFunction · db.isRegEx · db.isBoolean · db.isObject · db.isString · db.isDefined · db.isEmpty
alert(db.isNumber(23.01) + '\n' + db.isNumber(23/67));
true
true
console.log(db.isNumber(42));
true
db.isObject(v)Return true if the argument is an object.
| Name | Type | Required | Description |
|---|---|---|---|
v |
any |
✓ | The argument to be tested. |
db.isArray · db.isFunction · db.isNumber · db.isRegEx · db.isBoolean · db.isString · db.isDefined · db.isEmpty
alert(db.isObject(false) + '\n' + db.isObject(db()));
false
true
console.log(db.isObject({}));
true
db.isRegExp(v)Return true if the argument is a regular expression.
| Name | Type | Required | Description |
|---|---|---|---|
v |
any |
✓ | The argument to be tested. |
db.isArray · db.isFunction · db.isNumber · db.isBoolean · db.isObject · db.isString · db.isDefined · db.isEmpty
alert(db.isRegExp(/^xyz$/) + '\n' + db.isRegExp('xyz'));
true
false
console.log(db.isRegExp(/x/));
true
db.isString(v)Return true if the argument is a string.
| Name | Type | Required | Description |
|---|---|---|---|
v |
any |
✓ | The argument to be tested. |
db.isArray · db.isFunction · db.isNumber · db.isRegEx · db.isBoolean · db.isObject · db.isDefined · db.isEmpty
alert(db.isString('xyz') + '\n' + db.isString());
true
false
console.log(db.isString('hi'));
true
db.makePatch(o, n)Create a diff-match-patch text patch representing the changes needed to transform one string into another.
| Name | Type | Required | Description |
|---|---|---|---|
o |
string |
✓ | The original text. |
n |
string |
✓ | The new/modified text. |
var patch = db.makePatch('hello', 'hello world');
var result = db.applyPatch(patch, 'hello');
console.log(result); // "hello world"
"hello world"
var p=db.makePatch('hi','hi there'); console.log(typeof p);
string
db.matchTagText(str)Expand shorthand tag text prefixes based on the current API version.
In version 0: `../` expands to `<appName>/` and `./` expands
to `<username>/`.
In version 1: `../` and `./` prefixes are simply stripped.
If the string contains no `/`, it is returned unchanged.
| Name | Type | Required | Description |
|---|---|---|---|
str |
string |
✓ | A tag text string, possibly containing shorthand prefixes. |
// With version 0, logged in as 'alice' to app 'myApp':
db.matchTagText('./comments'); // "alice/comments"
db.matchTagText('../settings'); // "myApp/settings"
// With version 1:
db.matchTagText('./comments'); // "comments"
console.log(db.matchTagText('city', 'city'));
city
db.resume(func)Resume a chain that was suspended by wait.
Retrieves the saved result set from the paused chain. If `func` is provided, executes it
with the saved result set; if it returns a defined value, that value replaces the result set.
Then continues the chain from where it was paused.
| Name | Type | Required | Description |
|---|---|---|---|
func |
function |
✓ | Optional. A function to execute before resuming. Receives the saved result set. If it returns a defined value, that replaces the result set. |
db()
.topicByName('myTopic')
.wait()
.log()
.end();
// Later, from another context:
db.resume();
console.log(typeof db.resume);
function
db.setData(name, value)Store a value in the shared module-level key-value data store, accessible across all chains.
| Name | Type | Required | Description |
|---|---|---|---|
name |
string |
✓ | The key under which to store the value. |
value |
any |
✓ | The value to store. |
db.setData('currentUser', 'alice');
console.log(db.getData('currentUser')); // "alice"
db.setData('k','v'); console.log(db.getData('k'));
v
db.userTopic()Return the topic text of the currently logged-in user (e.g. `"user:username"`).
This value is set during login or setSession.
console.log(db.userTopic()); // "user:alice"
console.log(typeof db.userTopic);
function
db.userTopicId()Return the topic ID of the currently logged-in user's user topic.
This value is set during login or setSession.
console.log(db.userTopicId()); // "5a3f..."
console.log(typeof db.userTopicId);
function
db.valueTopicIdForTag(tagText, topic)Find a tag within a topic by its text (case-insensitive) and return the `topicId`
of its first value.
Useful for navigating topic references — when a value in one topic points to another topic,
this extracts the referenced topic's ID.
| Name | Type | Required | Description |
|---|---|---|---|
tagText |
string |
✓ | The tag text to search for (case-insensitive match). |
topic |
object |
✓ | A ScrewtopDB topic object containing a .tags array. |
db()
.topicByName('blog-article')
.first(function(topic) {
var commentTopicId = db.valueTopicIdForTag('comments', topic);
console.log(commentTopicId);
})
.end();
console.log(typeof db.valueTopicIdForTag);
function
db.collect(array, testfunc)Return a new array consisting of elements returned from a user-supplied function that is invoked for
each element of the input array.
| Name | Type | Required | Description |
|---|---|---|---|
array |
array |
✓ | The input array |
testfunc |
function |
✓ | The function that is invoked once for each array element. The function should return the element that is to be included in the output array. |
db.includes · db.select · db.reject · db.detect · db.forEach
console.log(db.collect([1,2,3], function(x){ return x*x; }));
[1,4,9]
db.detect(array, testfunc)Return the first element of an array that passes a specified test.
| Name | Type | Required | Description |
|---|---|---|---|
array |
array |
✓ | The input array |
testfunc |
function |
✓ | The function that is invoked once for each array element. |
db.includes · db.select · db.reject · db.collect · db.forEach · db.detect2
console.log(db.detect([1,2,3], function(x){ return x>1; }));
2
db.detect2(array, testfunc)Return the first element of an array that passes a specified test as the single member of a new array
If the input object is undefined or empty or no element matches the test, an empty array is returned.
| Name | Type | Required | Description |
|---|---|---|---|
array |
array |
✓ | The input array |
testfunc |
function |
✓ | The function that is invoked once for each array element. |
db.includes · db.select · db.reject · db.collect · db.forEach · db.detect
console.log(db.detect2([1,2,3], function(x){ return x>1; }));
[2]
db.firstIndexOf(array, func)Return the zero-based index of the first matching element or -1 if no matching element is found
| Name | Type | Required | Description |
|---|---|---|---|
array |
array |
✓ | The input array |
func |
function |
✓ | The function that is invoked once for each array element. This function is passed the array element and its index as its two input arguments. If this function returns true, the index of the current array element is the return value of firstIndexOf. |
db.includes · db.select · db.reject · db.collect · db.detect · db.forEach
console.log(db.firstIndexOf([10,20,30], function(x){return x===20;}));
1
db.forEach(array, func)Execute a function once for each element of the input array.
| Name | Type | Required | Description |
|---|---|---|---|
array |
array |
✓ | The input array |
testfunc |
function |
✓ | The function that is invoked once for each array element. This function is passed the array element and its index as its two input arguments. The return value of this function, if true, terminates the iteration. |
db.includes · db.select · db.reject · db.collect · db.detect
var out=[]; db.forEach([1,2,3], function(x){ out.push(x); }); console.log(out);
[1,2,3]
db.includes(array, obj)Return true if an array includes a specified element.
| Name | Type | Required | Description |
|---|---|---|---|
array |
array |
✓ | The input array |
testfunc |
function |
✓ | The function that is invoked once for each array element. This function should return true when the desired element is encountered. |
db.detect · db.select · db.reject · db.collect · db.forEach
console.log(db.includes([1,2,3], 2));
true
db.objToDb(obj, dbObjs)Return value topicId for the first value in a tag specified by name
| Name | Type | Required | Description |
|---|---|---|---|
tagText |
string |
✓ | The text of the tag |
topic |
object |
✓ | The topic in which the tag resides |
var arr=db.objToDb({text:'x',k:'v'}); console.log(Array.isArray(arr));
true
db.reject(array, testfunc)Return a new array containing only those elements from the input array that di not pass a specified test.
| Name | Type | Required | Description |
|---|---|---|---|
array |
array |
✓ | The input array |
testfunc |
function |
✓ | The function that is invoked once for each array element. The function should return false for elements that are not to be selected. |
db.includes · db.select · db.detect · db.collect · db.forEach
console.log(db.reject([1,2,3], function(x){return x===2;}));
[1,3]
db.select(array, testfunc)Return a new array containing elements selected from the input array that pass a specified test.
| Name | Type | Required | Description |
|---|---|---|---|
array |
array |
✓ | The input array |
testfunc |
function |
✓ | The function that is invoked once for each array element. This function should return true for each element that is to be selected. |
db.includes · db.detect · db.reject · db.collect · db.forEach
console.log(db.select([1,2,3], function(x){return x>1;}));
[2,3]
Delete an ACL by id. Requires an authenticated session.
| Method | DELETE |
|---|---|
| Path | /:app/acls.json/:id |
| Auth | true |
| Response | { result:"success" } |
Delete an application.
Delete an application.
Authorization: Admin or responsible user.
URL Parameters:
app - Application name (used for routing)todel - Name of application to deleteResponse:
{
"result": "success"
}
---
| Method | DELETE |
|---|---|
| Path | /:app/apps.json/:todel |
| Auth | true |
curl -s -u 'screwtop:<admin-password>' -X DELETE 'http://localhost:4342/screwtop/apps.json/EX_TODEL'
{
"result": "success",
"serverProcessingTime": 3,
"cacheHitRate": 0.15,
"cacheEvictionRate": 0,
"cacheSize": 1,
"cacheLimit": 1048576
}
Delete user attributes.
Delete user attributes.
Authentication: Session required.
URL Parameters:
names - Comma-separated attribute names to deleteQuery Parameters:
username - (Optional) Target username. Requires admin or responsible user privileges.Notes:
appattrs cannot be deleted.email sets it to empty string rather than removing it.Response:
{
"result": "success"
}
---
| Method | DELETE |
|---|---|
| Path | /:app/attributes.json/:names |
| Auth | true |
curl -s \
-u 'pfu:pfp' \
-X DELETE \
'http://localhost:4342/PROSE_FIX_MOEK3D80/attributes.json/delme'
{
"result": "success",
"serverProcessingTime": 1,
"cacheHitRate": 0.7058823529411765,
"cacheEvictionRate": 0,
"cacheSize": 215,
"cacheLimit": 1048576
}
REMOVED in v2, for the same reason as the GET: there are no instance numbers. The
route answers HTTP 409 with { result, hint, instances }, listing the topicIds that
carry the name. Delete one node with DELETE /:app/topics.json/<topicId>.
| Method | DELETE |
|---|---|
| Path | /:app/instances.json/:text/:instance |
| Auth | true |
| Response | HTTP 409 { result, hint, instances:[topicId, ...] } |
| Implemented by | deleteInstance |
Delete topic(s) by ID(s).
Delete topic(s) by ID(s).
URL Parameters:
app - Application nametext - Comma-separated numeric IDs (e.g., 123 or 1,2,3)Response:
{
"result": "success",
"actions": {
"ts": {},
"delete": [123, 456, 789]
}
}
Note: Deleting a topic cascades to delete all associated values.
---
These endpoints return HTML-formatted topic views instead of JSON.
| Method | DELETE |
|---|---|
| Path | /:app/topics.json/:text |
| Auth | true |
{
"result": "success",
"actions": {
"ts": {},
"delete": [123, 456, 789]
}
}
curl -s \
-u 'pfu:pfp' \
-X DELETE \
'http://localhost:4342/PROSE_LATE_MOEKQDHB/topics.json/deleteme'
Access denied
Delete a user from an application.
Delete a user from an application.
Authorization:
Restrictions:
URL Parameters:
app - Application nameusername - Username to deleteResponse:
{
"result": "success"
}
Error Response (responsible user):
{
"result": "Responsible user may not be deleted."
}
---
| Method | DELETE |
|---|---|
| Path | /:app/users.json/:username |
| Auth | true |
{
"result": "success"
}
curl -s \
-u 'pfu:pfp' \
-X DELETE \
'http://localhost:4342/PROSE_FIX_MOEK3D80/users.json/killme'
{
"result": "success",
"serverProcessingTime": 1,
"cacheHitRate": 0.6932599724896836,
"cacheEvictionRate": 0,
"cacheSize": 215,
"cacheLimit": 1048576
}
List ACLs for the app. NOTE: this endpoint is currently a stub — it returns { result:"success" } without enumerating ACLs. Use GET /:app/acls.json/:name to resolve a specific ACL by name. Requires an authenticated session.
| Method | GET |
|---|---|
| Path | /:app/acls.json |
| Auth | true |
| Response | { result:"success" } |
Resolve an ACL id by its name. Requires an authenticated session.
| Method | GET |
|---|---|
| Path | /:app/acls.json/:name |
| Auth | true |
| Response | { result:"success", aclId:"..." } (or { result:"ACL not found" }) |
Get application details including member list.
Get application details including member list.
URL Parameters:
app - Application nameQuery Parameters:
include=userattributes - Include user attributes (adds userTopicId to each member)Response:
{
"result": "success",
"data": {
"appId": "1",
"appName": "myapp",
"responsibleUserId": "5",
"responsibleUserName": "admin",
"lastModified": 1234567890,
"appAttributes": [],
"appMembers": [
{
"username": "myapp:john",
"userId": 10,
"lastLogin": "1234567890",
"unauthenticated": false,
"privileges": ["admin"]
}
]
}
}
Notes:
privileges contains ["admin"] for responsible users, empty array otherwise.username is prefixed with the app name and colon.---
| Method | GET |
|---|---|
| Path | /:app/apps.json |
| Auth | true |
curl -s -u 'screwtop:<admin-password>' -X GET 'http://localhost:4342/screwtop/apps.json'
{
"result": "success",
"data": {
"appId": "0",
"appName": "screwtop",
"responsibleUserId": "0",
"responsibleUserName": "",
"lastModified": 1772837053115,
"appAttributes": [],
"appMembers": [
{
"username": "screwtop:screwtop",
"userId": 1,
"lastLogin": "1777135622420",
"unauthenticated": false,
"privileges": [
"admin"
]
}
]
},
"serverProcessingTime": 1,
"cacheHitRate": 0.1,
"cacheEvictionRate": 0,
"cacheSize": 1,
"cacheLimit": 1048576
}
Get all user attributes.
Get all user attributes.
Authentication: Session required.
Query Parameters:
username - (Optional) Username to look up. Requires admin or responsible user privileges.Response:
{
"result": "success",
"data": { "attr1": "value1", "attr2": "value2" }
}
---
| Method | GET |
|---|---|
| Path | /:app/attributes.json |
| Auth | true |
curl -s \
-u 'pfu:pfp' \
-X GET \
'http://localhost:4342/PROSE_FIX_MOEK1HZR/attributes.json'
{
"result": "success",
"data": [
{
"name": "userTopicId",
"value": "01KQ2QK7CHZZ026SJ19PEHX41X"
},
{
"name": "previousLogin",
"value": "1777135604045"
},
{
"name": "loginTime",
"value": "1777135604153"
}
],
"serverProcessingTime": 0,
"cacheHitRate": 0.3660130718954248,
"cacheEvictionRate": 0,
"cacheSize": 69,
"cacheLimit": 1048576
}
Get a specific user attribute by name.
Get a specific user attribute by name.
Authentication: Session required.
URL Parameters:
app - Application nameattrName - Attribute name to retrieveQuery Parameters:
username - (Optional) Username to look up. Requires admin or responsible user privileges.Response:
{
"result": "success",
"data": [{ "name": "attrName", "value": "attrValue" }]
}
Notes:
null value if the attribute does not exist.encryptedPassword falls back to legacy encpassword attribute if not found.---
| Method | GET |
|---|---|
| Path | /:app/attributes.json/:attrName |
| Auth | true |
curl -s \
-u 'pfu:pfp' \
-X GET \
'http://localhost:4342/PROSE_FIX_MOEK1HZR/attributes.json/getattr'
{
"result": "success",
"data": [
{
"name": "getattr",
"value": null
}
],
"serverProcessingTime": 1,
"cacheHitRate": 0.36486486486486486,
"cacheEvictionRate": 0,
"cacheSize": 69,
"cacheLimit": 1048576
}
Run the in-process diagnose audit over the app's graph and return its report: symbol/frame/slot integrity, missing-symbol and reverse-edge checks. Read-only.
| Method | GET |
|---|---|
| Path | /:app/diagnostics.json |
| Auth | true |
| Response | { ...diagnose report... } |
| Implemented by | diagnose |
Subscribe to Server-Sent Events (SSE) for real-time updates.
Subscribe to Server-Sent Events (SSE) for real-time updates.
No authentication required (the notifyId acts as an opaque authorization token).
URL Parameters:
app - Application namenotifyId - Notification channel IDQuery Parameters:
source - (Optional) Source identifier. Events triggered by this source will not be sent back to this subscriber.Response:
text/event-stream: connected sent on connectiondata: <JSON>\n\n whenever a mutation occurs on the channelNotes:
?notify=<notifyId> in its query string.---
| Method | GET |
|---|---|
| Path | /:app/events/:notifyId |
| Auth | true |
Full-text search over the names of all nodes (native LevelDB FTS). In v2 a value's text is itself a node, so VALUE text is indexed, not just topic names. A hit's text may therefore be a value node (e.g. an email subject or body); resolve it to its owning topic with an inbound hop -- topicById(hit.topicId, {include:"inbound"}) or via:{tag:<tag>, inbound:true}. With ?q=QUERY returns ranked hits; without q returns index status (availability, document count N, version). Optional ?limit=N and ?mode=AND|OR. Long text that should NOT be searchable belongs in a blob, not a value.
| Method | GET |
|---|---|
| Path | /:app/fts.json |
| Auth | true |
| Response | { result:"success", impl:"native", hits:[...] } (or status when q omitted) |
| Implemented by | ftsSearch |
curl -u 'docsadmin:docsadmin-dev-pass' \
'http://localhost:4342/screwtopdb-docs/fts.json?q=topicByName'
{"result":"success","impl":"native","hits":[ ... ]}
REMOVED in v2. Addressing an instance by NUMBER is gone, so this route answers
HTTP 409 with { result, hint, instances } -- `instances` lists the topicIds carrying
the name, so a caller can recover in one hop. Fetch one node with
GET /:app/topics.json/<topicId>, or the whole same-named set with
GET /:app/topics.json/<name>.
| Method | GET |
|---|---|
| Path | /:app/instances.json/:text/:instance |
| Auth | true |
| Response | HTTP 409 { result, hint, instances:[topicId, ...] } |
| Implemented by | topicByNameAndInstance |
Read the app listing (anti-enumeration) policy.
Read the app's listing policy, which controls whether ordinary callers may enumerate the app's topics and members.
URL Parameters:
app - Application name.Response:
{ "result": "success", "policy": "open" }
policy is open (the default: enumeration works normally) or restricted (see PUT). Readable by any session.
| Method | GET |
|---|---|
| Path | /:app/listpolicy.json |
| Auth | true |
curl -s -u 'user:pass' 'http://localhost:4342/myapp/listpolicy.json'
{ "result": "success", "policy": "open" }
Read the app no-ACL policy.
Read the app's no-ACL policy: how objects that carry no explicit ACL are treated.
URL Parameters:
app - Application name.Response:
{ "result": "success", "policy": "open" }
policy is open (the default: ACL-less objects are world-readable, additions are open, modify/delete are owner-only) or owner (ACL-less objects are owner-only for every right, reads included). Explicit ACLs are unaffected either way. Readable by any session.
| Method | GET |
|---|---|
| Path | /:app/noaclpolicy.json |
| Auth | true |
curl -s -u 'user:pass' 'http://localhost:4342/myapp/noaclpolicy.json'
{ "result": "success", "policy": "open" }
Return a stored value (page HTML, CSS, ...) as the raw response body.
Return one stored value as the whole response body, with no JSON wrapping. It serves a page, stylesheet or document kept in a topic, and it is the v2 form of the IW front controller's /{app}/topics?name=<page>.
URL Parameters:
app - Application name.name - Topic name.tag - Optional. The tag whose first value is returned. Defaults to raw (GET /:app/raw/:name).Behavior:
content-type tag on the same topic (same owner rule), else from the topic name's extension (site.css is text/css), else text/html. Text types get charset=utf-8. X-Content-Type-Options: nosniff is always set.UnauthenticatedRead=false answers 403 to an unauthenticated caller.Response: the value's text as the body. 404 (plain text) when the topic, the tag, or a value the caller may read is missing.
| Method | GET |
|---|---|
| Path | /:app/raw/:name/:tag |
| Auth | false |
curl -s -u 'user:pass' 'http://localhost:4342/myapp/raw/index'
<html>...the first value of the "raw" tag on topic "index"...</html>
Full-graph symbol audit and reclamation. Walks the symbol registry, recomputes each symbol's true reference count from the graph, and reports drift plus orphan symbols (symbols with no associated object). Read-only by default; pass ?commit=true (or ?commit=1) to rewrite drifted counts and reclaim orphans. Backfills refs on legacy databases and cleans orphans accumulated before inline reference counting; steady-state reclamation is inline.
| Method | GET |
|---|---|
| Path | /:app/reclaim.json |
| Auth | true |
| Response | { scanned, drift:[...], orphans:[...], reclaimed:[...] (when commit) } |
// dry run (read-only). add ?commit=true to actually reclaim.
curl -u 'docsadmin:docsadmin-dev-pass' \
'http://localhost:4342/screwtopdb-docs/reclaim.json'
{"scanned":...,"drift":[],"orphans":[]}
Dump the app's interned symbol registry as JSON. Optional ?maxlen=N truncates long symbol keys in the response.
| Method | GET |
|---|---|
| Path | /:app/symbols.json |
| Auth | true |
| Response | { result:"success", data:[ { symbol fields... } ] } |
| Implemented by | allSymbols |
Get HTML view with query parameter `?name=<topicname>`.
Get HTML view with query parameter ?name=<topicname>.
---
User attributes are key-value pairs associated with a user account.
| Method | GET |
|---|---|
| Path | /:app/topics.html/ |
| Auth | true |
Get HTML view of topic by name or ID.
Get HTML view of topic by name or ID.
| Method | GET |
|---|---|
| Path | /:app/topics.html/:text |
| Auth | true |
Get HTML view of topic by numeric ID.
Get HTML view of topic by numeric ID.
| Method | GET |
|---|---|
| Path | /:app/topics.html/id/:id |
| Auth | true |
Get HTML view of topic by name.
Get HTML view of topic by name.
| Method | GET |
|---|---|
| Path | /:app/topics.html/name/:text |
| Auth | true |
Search or query topics.
Search or query topics.
URL Parameters:
app - Application nameQuery Parameters:
name - Get topic by exact name matchfind - Regex pattern to search topic namesinclude - Relationships to include (default: outbound)exclude - Relationships to excluderecursevia - Same as above (recursive graph traversal)via - Same as above (multi-hop graph traversal)Response:
{
"result": "success",
"topics": [...]
}
---
| Method | GET |
|---|---|
| Path | /:app/topics.json |
| Auth | true |
| Response | { "result": "success", "topics": [ {text, topicId, tags:[...]} ] } |
| Implemented by | topicByName |
{
"result": "success",
"topics": [...]
}
curl -s \
-u 'pfu:pfp' \
-X GET \
'http://localhost:4342/PROSE_FIX_MOEK1HZR/topics.json?find=search'
{
"result": "success",
"topics": [
{
"text": "searchA",
"topicId": "01KQ2QK83DWQSXD0CZ3Z9X0SWC",
"unique": false,
"instance": 0,
"cnt": 1,
"creationTime": 1777134575725,
"ts": 1777134575725,
"tags": [
{
"tagId": "01KQ2QK83E9EYYCKS82V28HXE0",
"text": "x",
"tagType": "outbound",
"topicId": "01KQ2QK7S417V3A5ZG3G4NSHHJ",
"parent": "01KQ2QK83DWQSXD0CZ3Z9X0SWC",
"unique": false,
"ts": 1777134575725,
"owner": "pfu",
"values": [
{
"text": "1",
"valueId": "01KQ2QK83E9EYYCKS82V28HXE1",
"topicId": "01KQ2QK83E9EYYCKS82V28HXE2",
"parent": "01KQ2QK83E9EYYCKS82V28HXE0",
"unique": false,
"ts": 1777134575725,
"owner": "pfu",
"acl": 0,
"cnt": 0,
"instance": 0,
"topicInstance": 0
}
],
"cnt": 1
}
]
},
{
"text": "searchB",
"topicId": "01KQ2QK83HN7M4EGJZWR5C8EHT",
"unique": false,
"instance": 0,
"cnt": 1,
"creationTime": 1777134575728,
"ts": 1777134575728,
"tags": [
{
"tagId": "01KQ2QK83HN7M4EGJZWR5C8EHV",
"text": "x",
"tagType": "outbound",
"topicId": "01KQ2QK7S417V3A5ZG3G4NSHHJ",
"parent": "01KQ2QK83HN7M4EGJZWR5C8EHT",
"unique": false,
"ts": 1777134575728,
"owner": "pfu",
"values": [
{
"text": "2",
"valueId": "01KQ2QK83HN7M4EGJZWR5C8EHW",
"topicId": "01KQ2QK83JFTASGK8B94NNCAEZ",
"parent": "01KQ2QK83HN7M4EGJZWR5C8EHV",
"unique": false,
"ts": 1777134575728,
"owner": "pfu",
"acl": 0,
"cnt": 0,
"instance": 0,
"topicInstance": 0
}
],
"cnt": 1
}
]
}
],
"serverProcessingTime": 3,
"cacheHitRate": 0.3010752688172043,
"cacheEvictionRate": 0,
"cacheSize": 53,
"cacheLimit": 1048576
}
// curl with basic auth (user:pass), URL-encode the topic name
curl -u 'docsadmin:docsadmin-dev-pass' \
'http://localhost:4342/screwtopdb-docs/topics.json/addTopics'
{"result":"success","topics":[{"text":"addTopics",...}]}
Retrieve topic(s) by name or ID(s).
Retrieve topic(s) by name or ID(s).
URL Parameters:
app - Application nametext - Topic name OR comma-separated numeric IDs (e.g., 123 or 1,2,3)Query Parameters:
include - Comma-separated list of relationships to include:outbound - Include outbound tag relationshipsinbound - Include inbound tag relationshipsallvalues - Include all valuesalltopics - Include all related topicsrecursevia - Recursive graph traversal. Follows outbound tag values matching the given tag name recursively, collecting all reachable topics. Handles cycles. Example: ?recursevia=childrenvia - Multi-hop graph traversal. JSON-encoded (or plain string for single tag name). Follows outbound tag values from the starting topic through one or more hops, returning the destination topics. Accepts a string, an object {"tag":"...", "with":{"tagName":"valueName"}}, or an array of such objects for multi-hop traversal. The optional with property filters destinations by requiring matching outbound tag:value pairs (AND logic). Values can be strings (exact match) or operator objects: {"$not":"X"} (negation), {"$none":"X"} (universal negation), {"$contains":"X"} (substring), {"$gt":"X"}, {"$gte":"X"}, {"$lt":"X"}, {"$lte":"X"} (comparison). Use {"$or":[...]} for OR across multiple tag criteria. Operators compose: {"$not":{"$contains":"X"}}.Behavior:
text matches pattern ^[0-9,]+$, treats it as ID(s) and fetches by IDtext as a topic nameResponse:
{
"result": "success",
"data": [
{
"text": "topic name",
"tags": [
{
"text": "tag name",
"cnt": 2,
"values": [
{ "text": "value text", "topicId": 123, "valueId": 456 }
]
}
]
}
]
}
---
| Method | GET |
|---|---|
| Path | /:app/topics.json/:text |
| Auth | true |
{
"result": "success",
"data": [
{
"text": "topic name",
"tags": [
{
"text": "tag name",
"cnt": 2,
"values": [
{ "text": "value text", "topicId": 123, "valueId": 456 }
]
}
]
}
]
}
curl -s \
-u 'pfu:pfp' \
-X GET \
'http://localhost:4342/PROSE_FIX_MOEK1HZR/topics.json/alice'
{
"result": "success",
"data": [
{
"text": "alice",
"topicId": "01KQ2QK7DFXMHGEYRA0PH3XSCG",
"unique": false,
"instance": 0,
"cnt": 1,
"creationTime": 1777134575019,
"ts": 1777134575019,
"tags": [
{
"tagId": "01KQ2QK7DFXMHGEYRA0PH3XSCH",
"text": "city",
"tagType": "outbound",
"topicId": "01KQ2QK7DJ1SPQD1TA5KAQ9BRS",
"parent": "01KQ2QK7DFXMHGEYRA0PH3XSCG",
"unique": false,
"ts": 1777134575019,
"owner": "pfu",
"values": [
{
"text": "SF",
"valueId": "01KQ2QK7DHB3MNY4FEGV7NR123",
"topicId": "01KQ2QK7DHB3MNY4FEGV7NR124",
"parent": "01KQ2QK7DFXMHGEYRA0PH3XSCH",
"unique": false,
"ts": 1777134575019,
"owner": "pfu",
"acl": 0,
"cnt": 0,
"instance": 0,
"topicInstance": 0
}
],
"cnt": 1
}
]
}
],
"serverProcessingTime": 103,
"cacheHitRate": 0.2033898305084746,
"cacheEvictionRate": 0,
"cacheSize": 41,
"cacheLimit": 1048576
}
Retrieve a topic by its numeric ID.
Retrieve a topic by its numeric ID.
URL Parameters:
app - Application nameid - Numeric topic IDQuery Parameters:
include - Same as aboverecursevia - Same as above (recursive graph traversal)via - Same as above (multi-hop graph traversal)Response:
{
"text": "topic name",
"tags": [...]
}
---
| Method | GET |
|---|---|
| Path | /:app/topics.json/id/:id |
| Auth | true |
{
"text": "topic name",
"tags": [...]
}
curl -s \
-u 'pfu:pfp' \
-X GET \
'http://localhost:4342/PROSE_FIX_MOEK1HZR/topics.json/id/01KQ2QK7S2CQC0595NE2CFH00G'
[
{
"text": "bobid",
"topicId": "01KQ2QK7S2CQC0595NE2CFH00G",
"unique": false,
"instance": 0,
"cnt": 1,
"creationTime": 1777134575393,
"ts": 1777134575393,
"tags": [
{
"tagId": "01KQ2QK7S2CQC0595NE2CFH00H",
"text": "x",
"tagType": "outbound",
"topicId": "01KQ2QK7S417V3A5ZG3G4NSHHJ",
"parent": "01KQ2QK7S2CQC0595NE2CFH00G",
"unique": false,
"ts": 1777134575393,
"owner": "pfu",
"values": [
{
"text": "y",
"valueId": "01KQ2QK7S2CQC0595NE2CFH00J",
"topicId": "01KQ2QK7S417V3A5ZG3G4NSHHF",
"parent": "01KQ2QK7S2CQC0595NE2CFH00H",
"unique": false,
"ts": 1777134575393,
"owner": "pfu",
"acl": 0,
"cnt": 0,
"instance": 0,
"topicInstance": 0
}
],
"cnt": 1
}
]
}
]
Get the current user's votes.
Get the current user's votes.
Authentication: Session required.
Response:
{
"result": "success",
"data": { ... }
}
---
| Method | GET |
|---|---|
| Path | /:app/users.json/votes |
| Auth | true |
curl -s \
-u 'pfu:pfp' \
-X GET \
'http://localhost:4342/PROSE_FIX_MOEK1HZR/users.json/votes'
{
"result": "success",
"data": [],
"serverProcessingTime": 0,
"cacheHitRate": 0.37142857142857144,
"cacheEvictionRate": 0,
"cacheSize": 71,
"cacheLimit": 1048576
}
Reset or change a user's password.
Reset or change a user's password.
Authorization: Requires responsible user of the app OR admin.
URL Parameters:
app - Application nameusername - Username whose password to resetRequest Body:
{
"password": "newpassword"
}
Response:
{
"result": "success"
}
Error Response:
{
"result": "Failed to reset password"
}
---
| Method | PATCH |
|---|---|
| Path | /:app/users.json/:username |
| Auth | true |
{
"password": "newpassword"
}
{
"result": "success"
}
curl -s \
-u 'pfu:pfp' \
-X PATCH \
'http://localhost:4342/PROSE_FIX_MOEK3D80/users.json/patchme' \
-H 'Content-Type: application/json' \
--data "{\"password\":\"newpass\"}"
{
"result": "success",
"serverProcessingTime": 1,
"cacheHitRate": 0.7015558698727016,
"cacheEvictionRate": 0,
"cacheSize": 215,
"cacheLimit": 1048576
}
Incremental sync. Given a set of topic ids and a timestamp, return the topics whose ts is greater than `since`, plus per-topic deletions recorded since then. Used by the disconnected/reconnection layer to catch up a local cache.
| Method | POST |
|---|---|
| Path | /:app/changes.json |
| Auth | true |
| Request | { since:<ts>, topicIds:[id,...] } |
| Response | { result:"success", topics:[...], deletions:{ topicId:[...] } } |
Build (or rebuild) the full-text search index for the app.
| Method | POST |
|---|---|
| Path | /:app/fts.json |
| Auth | true |
| Response | { result:"success", build:{...} } |
| Implemented by | ftsBuildIndex |
Mint a DISTINCT topic node carrying `topicText` -- this is what v2 instancing is --
and return its frame, whose `topicId` is the handle for every later reference.
`topicText` is required. `tagText`/`valueText` are optional and add the first edge;
omit them and a bare node is minted, to be given edges later by id.
The client-side equivalent is addTopics with a spec carrying instance:'new', in
either arity: addTopics({text, instance:'new', ...tags}) or
addTopics({text, instance:'new'}, tagText, valueText).
| Method | POST |
|---|---|
| Path | /:app/instances.json |
| Auth | true |
| Request | { topicText, tagText?, valueText?, options? } |
| Response | { result:"success", data:[...] } |
curl -u 'docsadmin:docsadmin-dev-pass' -H 'Content-Type: application/json' \
-d '{"topicText":"shopping","tagText":"item","valueText":"berries"}' \
'http://localhost:4342/screwtopdb-docs/instances.json'
{"result":"success","data":[ ... ]}
Run a restricted ScrewtopDB chain on the server in one request.
Run a chain of ScrewtopDB data operations on the server in a single request, instead of one HTTP call per step. The server applies the caller's identity, runs the chain, and returns the final result set as data.
URL Parameters:
app - Application name.Query Parameters:
notify - optional SSE channel id; a successful run is broadcast to it.source - optional client id recorded on the broadcast SSE event.Request Body:
{ "script": "topicByName('counter:k')" }
What a script may contain: The script is parsed, not evaluated. It must be a single chain of allowlisted data methods whose arguments are all literals (strings, numbers, booleans, null, and arrays/objects of those). Allowed methods are the data reads/writes and result-set navigation/filtering, e.g. topicByName, topicById, createValue, addToValue, subtractFromValue, addTopics, deleteTopics, deleteValues, tag, values, select, setACL, setVersion. Identity methods (setSession, url, logout, appName), error-handling switches (onError, safe, terminateOnError), flow control, logging, local-cache/offline methods, and app/user administration are not allowed. A script that uses a disallowed method, a non-literal argument, or more than one statement is refused with { "result": "script rejected: <reason>" }.
Identity:
Behavior:
result; the request does not hang.Response:
{ "result": "success", "data": { ... }, "serverProcessingTime": 42 }
Error Response:
{ "result": "No script provided" }
| Method | POST |
|---|---|
| Path | /:app/scripts.json |
| Auth | true |
{ "script": "createValue('counter:k','value','0').topicByName('counter:k')" }
{
"result": "success",
"data": { ... },
"serverProcessingTime": 42
}
curl -s -u 'user:pass' -X POST -H 'Content-Type: application/json' \
--data "{\"script\":\"log('hi')\"}" \
'http://localhost:4342/myapp/scripts.json'
{ "result": "script rejected: method not allowed: log" }
Batch operations on topics.
Batch operations on topics.
URL Parameters:
app - Application nameQuery Parameters:
get=true&multiple=true - Get multiple topics by namecreate=true - Create or update a topic-tag-valuepatch=true - (with create=true) Apply diff-match-patch instead of replacing the valueeval - Evaluate expression on value (see below)notify - Notification channel ID (triggers SSE broadcast on change)source - Source identifier for SSEallowNegative=true - (with eval) Allow negative results (otherwise clamps to 0)Eval Expressions:
v++ - Increment valuev-- - Decrement valuev+=N - Add N to valuev-=N - Subtract N from valuev=N - Set value to NIf the topic/tag doesn't exist yet, it is created with the expression evaluated against 0.
Request Body (for get multiple):
["topic1", "topic2", "topic3"]
Request Body (for create/eval):
{
"topicText": "topic name",
"tagText": "tag name",
"valueText": "value"
}
Response (get multiple):
{
"result": "success",
"topics": [...]
}
Response (create):
{
"result": "success",
"actions": {
"add": {
"data": [...]
}
}
}
Response (eval):
{
"result": "success",
"actions": {
"update": {
"data": {
"topicText": "...",
"tagText": "...",
"value": 5
}
}
}
}
Notes:
create=true: if the tag already exists on the topic, the last value is updated; otherwise a new topic-tag-value is created.eval: when allowNegative is not true and the result would be negative, value is clamped to 0 and actions.update.data.value is set to -1 to signal the clamp.---
| Method | POST |
|---|---|
| Path | /:app/topics.json |
| Auth | true |
["topic1", "topic2", "topic3"]
{
"topicText": "topic name",
"tagText": "tag name",
"valueText": "value"
}
{
"result": "success",
"topics": [...]
}
{
"result": "success",
"actions": {
"add": {
"data": [...]
}
}
}
{
"result": "success",
"actions": {
"update": {
"data": {
"topicText": "...",
"tagText": "...",
"value": 5
}
}
}
}
curl -s \
-u 'pfu:pfp' \
-X POST \
'http://localhost:4342/PROSE_FIX_MOEK1HZR/topics.json' \
-H 'Content-Type: application/json' \
--data "{\"topicText\":\"posttarget\",\"tagText\":\"newtag\",\"valueText\":\"newval\"}"
{
"result": "success",
"actions": [],
"serverProcessingTime": 0,
"cacheHitRate": 0.7552083333333334,
"cacheEvictionRate": 0,
"cacheSize": 205,
"cacheLimit": 1048576
}
Update a topic value, move an element, vote, or unvote.
Update a topic value, move an element, vote, or unvote.
URL Parameters:
app - Application nameid - Element ID (topic, tag, or value)Query Parameters:
move - If true, move the element instead of updatingvote - Integer vote value to cast on the topicunvote - Integer vote value to remove from the topicpatch - If true, apply a diff-match-patch instead of replacing the valuenotify - Notification channel ID (triggers SSE broadcast on change)source - Source identifier for SSE (excluded from receiving the broadcast)appupdated - If false, skip updating the app's lastModified timestampRequest Body (for update):
{
"valueText": "new value text"
}
Request Body (for topic text update):
{
"topicText": "new topic text"
}
Request Body (for move):
{
"insertBeforeId": 123
}
Response (move):
{
"result": "success",
"actions": {
"move": {
"nextId": 123,
"movedId": 456,
"ts": "timestamp",
"topicIds": [...],
"tagIds": [...],
"valueIds": [...]
}
}
}
Response (update):
{
"result": "success",
"actions": [...]
}
Response (vote):
{
"result": "success",
"actions": {
"vote": {
"data": { ... }
}
}
}
Response (unvote):
{
"result": "success",
"actions": {
"unvote": {
"data": { ... }
}
}
}
Notes:
UnauthenticatedUpdate app attribute to update, or UnauthenticatedVote to vote.---
| Method | POST |
|---|---|
| Path | /:app/topics.json/:id |
| Auth | true |
{
"valueText": "new value text"
}
{
"topicText": "new topic text"
}
{
"insertBeforeId": 123
}
{
"result": "success",
"actions": {
"move": {
"nextId": 123,
"movedId": 456,
"ts": "timestamp",
"topicIds": [...],
"tagIds": [...],
"valueIds": [...]
}
}
}
{
"result": "success",
"actions": [...]
}
{
"result": "success",
"actions": {
"vote": {
"data": { ... }
}
}
}
{
"result": "success",
"actions": {
"unvote": {
"data": { ... }
}
}
}
curl -s \
-u 'pfu:pfp' \
-X POST \
'http://localhost:4342/PROSE_FIX_MOEK1HZR/topics.json/01KQ2QM60QRGKNSNHEBRJMNGP3' \
-H 'Content-Type: application/json' \
--data "{\"topicText\":\"renamed\"}"
{
"result": "success",
"actions": {
"update": [
{
"topicId": "01KQ2QM60QRGKNSNHEBRJMNGP3",
"topicText": "renamed",
"ts": 1777134606547
}
]
},
"serverProcessingTime": 1,
"cacheHitRate": 0.7586206896551724,
"cacheEvictionRate": 0,
"cacheSize": 195,
"cacheLimit": 1048576
}
Create an access-control list. Requires an authenticated session. Each list entry grants or denies an access level to a set of ids.
| Method | PUT |
|---|---|
| Path | /:app/acls.json |
| Auth | true |
| Request | { name, list:[ { access:"r"|"w", ids:[...], allow:true|false } ] } |
| Response | { result:"success", aclId:"..." } |
Create a new application.
Create a new application.
Authorization: Admin only.
URL Parameters:
app - Application name (used for routing, typically "screwtop")Request Body:
{
"appName": "newapp",
"responsibleUserName": "admin_user",
"responsibleUserPassword": "password"
}
Response:
{
"result": "success",
"data": {
"text": "app",
"tags": [
{ "text": "userId", "values": [{ "text": "123" }] }
]
}
}
Error Response:
{
"result": "Unauthorized"
}
---
| Method | PUT |
|---|---|
| Path | /:app/apps.json |
| Auth | true |
{
"appName": "newapp",
"responsibleUserName": "admin_user",
"responsibleUserPassword": "password"
}
{
"result": "success",
"data": {
"text": "app",
"tags": [
{ "text": "userId", "values": [{ "text": "123" }] }
]
}
}
curl -s -u 'screwtop:<admin-password>' -X PUT 'http://localhost:4342/screwtop/apps.json' \
-H 'Content-Type: application/json' \
--data "{\"appName\":\"EX_DEMO_APP\",\"responsibleUserName\":\"demo\",\"responsibleUserPassword\":\"demopw\"}"
{
"result": "Error creating app EX_DEMO_APP",
"serverProcessingTime": 19,
"cacheHitRate": 0.10526315789473684,
"cacheEvictionRate": 0,
"cacheSize": 11,
"cacheLimit": 1048576
}
Set user attributes.
Set user attributes.
Authentication: Session required.
Query Parameters:
username - (Optional) Target username. Requires admin or responsible user privileges.Request Body: Single object or array of name/value pairs:
[
{ "name": "attrName", "value": "attrValue" }
]
Read-Only Attributes (cannot be set):
logintimepreviousloginusertopicidapptopicidadminvotesRestricted Attributes:
appattrs - Only settable by super users (admin)Response:
{
"result": "success"
}
---
| Method | PUT |
|---|---|
| Path | /:app/attributes.json |
| Auth | true |
[
{ "name": "attrName", "value": "attrValue" }
]
curl -s \
-u 'pfu:pfp' \
-X PUT \
'http://localhost:4342/PROSE_LATE2_MOEKVZWH/attributes.json' \
-H 'Content-Type: application/json' \
--data '[{"name":"put_attr","value":"put_val"}]'
{
"result": "success",
"serverProcessingTime": 1,
"cacheHitRate": 0.751937984496124,
"cacheEvictionRate": 0,
"cacheSize": 63,
"cacheLimit": 1048576
}
Set the app listing policy (admin/responsible).
Set the app's listing policy. Super-admin or the app's responsible user only.
URL Parameters:
app - Application name.Request Body:
{ "policy": "restricted" }
policy must be open or restricted. Under restricted, enumeration is refused to every caller except the super-admin and the app's responsible user: topics.json?find=, fts.json?q=, v2/find.json, the ?name=&via= and ?name=&recursevia= traversals, and inbound includes are answered 403 { "result": "listing restricted" }, and the member list (apps.json) returns only the caller's own entry. By-name and by-id reads, writes, SSE, and login are unaffected; the policy only removes enumeration, it never grants anything.
Response:
{ "result": "success", "policy": "restricted" }
Returns { "result": "Unauthorized" } for any other caller.
| Method | PUT |
|---|---|
| Path | /:app/listpolicy.json |
| Auth | true |
curl -s -u 'resp:pass' -X PUT -H 'Content-Type: application/json' \
--data '{"policy":"restricted"}' 'http://localhost:4342/myapp/listpolicy.json'
{ "result": "success", "policy": "restricted" }
Set the app no-ACL policy (admin/responsible).
Set the app's no-ACL policy. Super-admin or the app's responsible user only.
URL Parameters:
app - Application name.Request Body:
{ "policy": "owner" }
policy must be open or owner. owner makes every ACL-less object owner-only, reads included (the super-admin, and the responsible user's write/delete/change override, still apply). Explicit ACLs are unaffected.
Response:
{ "result": "success", "policy": "owner" }
Returns { "result": "Unauthorized" } for any other caller.
| Method | PUT |
|---|---|
| Path | /:app/noaclpolicy.json |
| Auth | true |
curl -s -u 'resp:pass' -X PUT -H 'Content-Type: application/json' \
--data '{"policy":"owner"}' 'http://localhost:4342/myapp/noaclpolicy.json'
{ "result": "success", "policy": "owner" }
Send a notification to all SSE subscribers on a channel.
Send a notification to all SSE subscribers on a channel.
URL Parameters:
app - Application namenotifyId - Notification channel IDQuery Parameters:
source - (Optional) Source identifier to exclude from receiving the notification.Request Body: Any JSON object to broadcast.
Response:
{
"result": "success"
}
Broadcast payload:
{
"notify": { ... }
}
---
These parameters are supported across multiple mutation endpoints:
| Parameter | Description | |-----------|-------------| | notify | Notification channel ID. When present, the mutation's actions are broadcast to all SSE subscribers on this channel. | | source | Used with notify. The subscriber with this source identifier is excluded from receiving the broadcast. Prevents echo. | | appupdated | Set to false to skip updating the app's lastModified timestamp after a mutation. |
---
HTTP Status: 401
Headers:
WWW-Authenticate: Basic realm="example"
Body: Access denied
HTTP Status: 400
{
"result": "Invalid session"
}
{
"result": "Insufficient privilege"
}
---
{
"text": "topic name",
"topicId": 123,
"tags": [
{
"text": "tag name",
"tagId": 456,
"cnt": 2,
"values": [
{
"text": "value text",
"valueId": 789,
"topicId": 123
}
]
}
]
}
f - Frame (topic)out - Outbound relationship (tag)in - Inbound relationshipv - Value---
Two query parameters allow selecting topics by following outbound tag relationships as a graph.
Recursively follows a single tag name from a starting topic, collecting all reachable topics. Handles cycles via a visited set.
Example: Given topics A --children--> B, C and B --children--> D:
GET /:app/topics.json/A?recursevia=children
Returns topics A, B, C, and D.
Multi-hop graph traversal with optional filtering at each hop. Follows outbound tag values through one or more hops, returning only the destination topics (not intermediate hops).
Accepted formats for the via query parameter:
| Format | Example | |--------|---------| | Plain string (single hop) | ?via=departments | | JSON object (single hop with filter) | ?via={"tag":"departments","with":{"region":"US"}} | | JSON array (multi-hop) | ?via=[{"tag":"departments"},{"tag":"members"}] | | JSON array (multi-hop with filters) | ?via=[{"tag":"departments","with":{"region":"US"}},{"tag":"members","with":{"status":"active"}}] |
The with property filters candidate topics at each hop. All conditions must match (AND logic). Each key is an outbound tag name and each value is the required tag value text (for exact match) or an operator object.
with value operators:
| Operator | Meaning | Example | |----------|---------|---------| | "value" (string) | Exact match (default) | {"region": "US"} | | {"$not": X} | Existential negation — topic has at least one value NOT matching X | {"region": {"$not": "US"}} | | {"$none": X} | Universal negation — topic has NO values matching X | {"region": {"$none": "US"}} | | {"$contains": "str"} | Substring match (case-sensitive) — value contains the string | {"name": {"$contains": "smith"}} | | {"$gt": "X"} | Greater than (numeric if both parse as numbers, otherwise lexicographic) | {"score": {"$gt": "5"}} | | {"$gte": "X"} | Greater than or equal | {"date": {"$gte": "2026-03-01"}} | | {"$lt": "X"} | Less than | {"score": {"$lt": "10"}} | | {"$lte": "X"} | Less than or equal | {"date": {"$lte": "2026-03-31"}} |
Range queries: Multiple comparison and $contains operators AND together within a single object: {"$gte": "2026-03-01", "$lte": "2026-03-31"} matches values in that range.
$or clause: Use "$or" as a top-level key in with alongside regular tag criteria. Its value is an array of clause objects. Each clause is a {tagName: critValue} object (all keys within a clause must match). The $or passes if ANY clause matches. Regular criteria AND with the $or result.
Example: {"status": "active", "$or": [{"region": "US"}, {"region": "EU"}]} — status must be "active" AND region must be "US" or "EU".
Operator composition: $not and $none can wrap any operator or plain string.
{"$not": {"$contains": "str"}} — has a value that does NOT contain "str"{"$none": {"$contains": "str"}} — NO values contain "str"{"$none": {"$gte": "5"}} — NO values are >= 5Examples: Given Acme Corp --departments--> Engineering, Sales where Engineering has tag region: US and Sales has tag region: EU:
GET /:app/topics.json/Acme%20Corp?via={"tag":"departments","with":{"region":"US"}}
Returns only Engineering.
GET /:app/topics.json/Acme%20Corp?via={"tag":"departments","with":{"region":{"$not":"US"}}}
Returns only Sales (region is not US).
GET /:app/topics.json/Acme%20Corp?via={"tag":"departments","with":{"region":{"$contains":"U"}}}
Returns both Engineering (US) and Sales (EU) since both contain "U".
GET /:app/topics.json/Acme%20Corp?via={"tag":"departments","with":{"$or":[{"region":"US"},{"region":"EU"}]}}
Returns both Engineering and Sales (region is US or EU).
---
getSession callsessionId, lastAccess, user, app, admin, impersonated---
Query parameters that accept boolean values recognize these as true: true, t, 1, yes, y (case-insensitive). All other values are treated as false.
| Method | PUT |
|---|---|
| Path | /:app/notifications.json/:notifyId |
| Auth | true |
{
"result": "success"
}
{
"notify": { ... }
}
WWW-Authenticate: Basic realm="example"
{
"result": "Invalid session"
}
{
"result": "Insufficient privilege"
}
{
"text": "topic name",
"topicId": 123,
"tags": [
{
"text": "tag name",
"tagId": 456,
"cnt": 2,
"values": [
{
"text": "value text",
"valueId": 789,
"topicId": 123
}
]
}
]
}
GET /:app/topics.json/A?recursevia=children
GET /:app/topics.json/Acme%20Corp?via={"tag":"departments","with":{"region":"US"}}
GET /:app/topics.json/Acme%20Corp?via={"tag":"departments","with":{"region":{"$not":"US"}}}
GET /:app/topics.json/Acme%20Corp?via={"tag":"departments","with":{"region":{"$contains":"U"}}}
curl -s \
-u 'pfu:pfp' \
-X PUT \
'http://localhost:4342/PROSE_FIX_MOEK3D80/notifications.json/notif1' \
-H 'Content-Type: application/json' \
--data "{\"message\":\"hello subscribers\"}"
{
"result": "success",
"serverProcessingTime": 0,
"cacheHitRate": 0.689280868385346,
"cacheEvictionRate": 0,
"cacheSize": 215,
"cacheLimit": 1048576
}
Create a new session (login).
Create a new session (login).
URL Parameters:
app - Application name (used for routing, actual app specified in body)Request Body:
{
"appIdOrName": "application name",
"username": "user",
"password": "pass"
}
Impersonation (admin/responsible users only):
{
"appIdOrName": "application name",
"username": "user to impersonate",
"password": ""
}
Response:
{
"result": "success",
"version": 1,
"data": {
"sessionId": "guid-session-id",
"appName": "application name",
"appId": 1,
"username": "user"
}
}
Error Response:
{
"result": "Authentication failed."
}
---
| Method | PUT |
|---|---|
| Path | /:app/sessions.json |
| Auth | true |
{
"appIdOrName": "application name",
"username": "user",
"password": "pass"
}
{
"appIdOrName": "application name",
"username": "user to impersonate",
"password": ""
}
{
"result": "success",
"version": 1,
"data": {
"sessionId": "guid-session-id",
"appName": "application name",
"appId": 1,
"username": "user"
}
}
curl -s \
-X PUT \
'http://localhost:4342/PROSE_LATE2_MOEKVZWH/sessions.json' \
-H 'Content-Type: application/json' \
--data '{"appIdOrName":"PROSE_LATE2_MOEKVZWH","username":"pfu","password":"pfp"}'
{
"result": "success",
"version": 1,
"data": {
"sessionId": "b34f61de-d071-46bc-9aa6-983b6236e4d1",
"appName": "PROSE_LATE2_MOEKVZWH",
"appId": 1,
"username": "pfu"
},
"serverProcessingTime": 2,
"cacheHitRate": 0.7266187050359713,
"cacheEvictionRate": 0,
"cacheSize": 63,
"cacheLimit": 1048576
}
Create new topic(s) with tags and values.
Create new topic(s) with tags and values.
URL Parameters:
app - Application nameQuery Parameters:
unique - If true, enforce uniquenessallowDuplicateValues - If true, allow duplicate valuesRequest Body: Array of topic objects:
[
{
"text": "topic name",
"tagName1": ["value1", "value2"],
"tagName2": ["value3"]
}
]
OR alternative format:
[
{
"topicText": "topic name",
"tagText": "tag name",
"valueText": "value"
}
]
Response:
{
"result": "success",
"version": 1,
"actions": {
"add": {
"data": [
{
"text": "topic name",
"tags": [...]
}
]
}
}
}
---
| Method | PUT |
|---|---|
| Path | /:app/topics.json |
| Auth | true |
[
{
"text": "topic name",
"tagName1": ["value1", "value2"],
"tagName2": ["value3"]
}
]
[
{
"topicText": "topic name",
"tagText": "tag name",
"valueText": "value"
}
]
{
"result": "success",
"version": 1,
"actions": {
"add": {
"data": [
{
"text": "topic name",
"tags": [...]
}
]
}
}
}
curl -s \
-u 'pfu:pfp' \
-X PUT \
'http://localhost:4342/PROSE_FIX_MOEK1HZR/topics.json' \
-H 'Content-Type: application/json' \
--data "[{\"text\":\"putExample\",\"tags\":[{\"text\":\"k\",\"values\":[{\"text\":\"v\"}]}]}]"
{
"result": "success",
"version": 1,
"actions": {
"add": {
"data": [
{
"text": "putExample",
"topicId": "01KQ2QK8BETZ3JMKBXDSYE49N8",
"unique": false,
"instance": 0,
"cnt": 1,
"creationTime": 1777134575981,
"ts": 1777134575981,
"tags": [
{
"tagId": "01KQ2QK8BETZ3JMKBXDSYE49N9",
"text": "k",
"tagType": "outbound",
"topicId": "01KQ2QK8BF0H3NPYBHZYCRE93B",
"parent": "01KQ2QK8BETZ3JMKBXDSYE49N8",
"unique": false,
"ts": 1777134575981,
"owner": "pfu",
"values": [
{
"text": "v",
"valueId": "01KQ2QK8BETZ3JMKBXDSYE49NA",
"topicId": "01KQ2QK8BF0H3NPYBHZYCRE938",
"parent": "01KQ2QK8BETZ3JMKBXDSYE49N9",
"unique": false,
"ts": 1777134575981,
"owner": "pfu",
"acl": 0,
"cnt": 0,
"instance": 0,
"topicInstance": 0
}
],
"cnt": 1
}
]
}
]
}
},
"serverProcessingTime": 6,
"cacheHitRate": 0.36231884057971014,
"cacheEvictionRate": 0,
"cacheSize": 69,
"cacheLimit": 1048576
}
Add a tag/value to an existing topic by ID.
Add a tag/value to an existing topic by ID.
URL Parameters:
app - Application nametext - Numeric topic IDQuery Parameters:
unique - Enforce uniquenessallowDuplicateValues - Allow duplicate valuesRequest Body:
{
"tagText": "tag name",
"valueText": "value text"
}
OR (to add just a value to an existing tag):
{
"valueText": "value text"
}
Response:
{
"result": "success",
"actions": {
"add": {
"data": {
"topics": [...]
}
}
}
}
---
| Method | PUT |
|---|---|
| Path | /:app/topics.json/:text |
| Auth | true |
{
"tagText": "tag name",
"valueText": "value text"
}
{
"valueText": "value text"
}
{
"result": "success",
"actions": {
"add": {
"data": {
"topics": [...]
}
}
}
}
curl -s \
-u 'pfu:pfp' \
-X PUT \
'http://localhost:4342/PROSE_LATE_MOEKQDHB/topics.json/puttext' \
-H 'Content-Type: application/json' \
--data '{"tagText":"newtag","valueText":"newval"}'
Access denied
Create a new user in an application.
Create a new user in an application.
Authorization: Requires responsible user of the app OR admin.
URL Parameters:
app - Application name (used for routing)Request Body:
{
"appName": "application name",
"username": "newuser",
"password": "password",
"email": "[email protected]"
}
Response:
{
"result": "success",
"data": {
"text": "user",
"tags": [
{ "text": "appName", "values": [{ "text": "appname" }] },
{ "text": "username", "values": [{ "text": "newuser" }] },
{ "text": "userId", "values": [{ "text": "123" }] }
]
}
}
---
| Method | PUT |
|---|---|
| Path | /:app/users.json |
| Auth | true |
{
"appName": "application name",
"username": "newuser",
"password": "password",
"email": "[email protected]"
}
curl -s \
-u 'pfu:pfp' \
-X PUT \
'http://localhost:4342/PROSE_FIX_MOEK3D80/users.json' \
-H 'Content-Type: application/json' \
--data "{\"username\":\"newuser\",\"password\":\"newpass\",\"appName\":\"PROSE_FIX_MOEK3D80\"}"
{
"result": "success",
"data": {
"text": "user",
"tags": [
{
"text": "appName",
"values": [
{
"text": "PROSE_FIX_MOEK3D80"
}
]
},
{
"text": "username",
"values": [
{
"text": "newuser"
}
]
},
{
"text": "userId",
"values": [
{
"text": "01KQ2QQQXV8BQYWA78ZG57GYHT"
}
]
}
]
},
"serverProcessingTime": 1,
"cacheHitRate": 0.7126099706744868,
"cacheEvictionRate": 0,
"cacheSize": 215,
"cacheLimit": 1048576
}