all repos — litestore @ b5f68a1e33e4af4eae82a376d5d7e3716afaebc3

A minimalist nosql document store.

Fixed bug on tags+search queries, updated docs.
h3rald h3rald@h3rald.com
Sun, 20 Sep 2015 10:59:01 +0200
commit

b5f68a1e33e4af4eae82a376d5d7e3716afaebc3

parent

beb1d1e5aef4a3309f0bac7d5aa986af8d8f3c8f

M admin/js/components/editor.jsadmin/js/components/editor.js

@@ -6,7 +6,6 @@

app.editor.config = function(obj){ return function(element, isInitialized, context){ var e = element; - if (!isInitialized) { var editor = ace.edit(e); obj.editor = editor;

@@ -57,7 +56,10 @@ * @param {Object} args

* @param {string} args.content */ app.editor.view = function(ctrl, args) { + if (args.ext === 'json'){ + args.content = JSON.stringify(args.content); + } return m(".editor.panel.panal-default", {config: app.editor.config(args)}, args.content); }; -}()); +}());
M admin/js/components/navbar.jsadmin/js/components/navbar.js

@@ -18,7 +18,7 @@ {path: "/guide/data_model", title: caret+"Data Model"},

{path: "/guide/getting-started", title: "Getting Started"}, {path: "/guide/usage", title: "Usage"}, {path: "/guide/admin_app", title: "Administration App"}, - {path: "/guide/api", title: "API"}, + {path: "/guide/api", title: "HTTP API Reference"}, {path: "/guide/api_info", title: caret+"info (LiteStore Information)"}, {path: "/guide/api_docs", title: caret+"docs (LiteStore Documents)"}, {path: "/guide/credits", title: "Credits"}
M admin/js/models.jsadmin/js/models.js

@@ -71,7 +71,9 @@ return m.request({

method: "PUT", url: host+"/docs/"+doc.id, data: doc.data, - serialize: function(data){return data;}, + serialize: function(data){ + return data; + }, config: xhrcfg }); };

@@ -82,7 +84,9 @@ return m.request({

method: "PUT", url: host+"/docs/"+doc.id, data: doc.data, - serialize: function(data) {return data} + serialize: function(data) { + return data; + } }); };
M admin/md/admin_app.mdadmin/md/admin_app.md

@@ -29,12 +29,39 @@ It can be used to easily access and explore any LiteStore data store (provided that it has been loaded in it) and access most of LiteStore functionalities via its HTTP API.

#### View Data Store Information -When first loaded, the app loads the _Info_ page by default. +When first loaded, the app loads the _Info_ page by default. This pages contains useful information on the currently-loaded LiteStore data store, some stats on documents and tags, and links to access documents by tag. + +![Info Page](images/app_info.png) #### Read LiteStore Documentation +The **Guide** section of the Administration App contains the official LiteStore User Guide, conveniently split into separate pages by section. + +> %note% +> Note +> +> If the data store is loaded in read/write mode (default), you'll see some **Edit** buttons on the Guide pages. Clicking them will open the corresponding Markdown source document for editing -- Such links have been very useful to update the docs in-place! + +![Guide](images/app_guide.png) + #### Display Documents by Tag +By clicking any of the tag links on the _Info_ page or by accessing the **Tags** menu in the navigation bar you can browse all documents tagged with a specific tag. Currently, it is only possible to specify only one single tag at a time although the API allows several tags to be specified at once. + +![Display documents by tag](images/app_tags.png) + #### Search Documents -#### View, Preview, Create and Edit Documents+You can search for documents using the search box in the navigation bar. The Administration App lets you search through all the textual/searchable documents loaded in the currently open data store. + +![Search](images/app_search.png) + +#### View, Preview, Delete, Create and Edit Documents + +You can view, edit and delete any document loaded in the data store using the bundled [ACE Editor](http://ace.c9.io/) component. Additionally: + +* It is possible to upload local files instead of creating them by hand. +* Preview is available for images and HTML documents +* Source code highlighting is available for Javascript, CSS, HTML, JSON and Markdown files. + +![Document](images/app_document.png)
M admin/md/api.mdadmin/md/api.md

@@ -1,1 +1,19 @@

-## HTTP API Reference+## HTTP API Reference + +LiteStore provide a simply and fairly RESTful HTTP API. At present, the only two resources exposed are the following: + +* info &ndash; information about the data store (read-only) +* docs &ndash; LiteStore documents (read-write) + +### Accessing LiteStore Resources + +To access a LiteStore resource, use URLs composed in the following way: + +`http:<hostname>:<port>/<resource>/<id>` + +Example: <http://localhost:9500/docs/admin/index.html> + +> %note% +> A note on document IDs... +> +> In a somewhat non-standard way, IDs of LiteStore documents can contain slashes. The main reason behind this is that this makes it possible to implement a virtual file system with LiteStore easily, and serve up web pages as you would from an ordinary filesystem.
M admin/md/api_docs.mdadmin/md/api_docs.md

@@ -8,6 +8,11 @@ * created: The document creation date expressed as combined date and time in UTC ([ISO 8601](http://en.wikipedia.org/wiki/ISO_8601) compliant).

* modified: The document modification date (if applicable) expressed as combined date and time in UTC ([ISO 8601](http://en.wikipedia.org/wiki/ISO_8601) compliant). * tags: A list of tags associated to the document. +> %note% +> JSON Documents +> +> Documents with content type "application/json" are special: their **data** property is _not_ set to a string like for all other textual and binary documents, but a real, non-escaped JSON object. This little quirk makes JSON documents _different_ from other documents, but also makes things so much easier when you just want to use LiteStore as a simple JSON document store. + #### Example Document ```

@@ -22,12 +27,12 @@ ```

#### OPTIONS docs -Returns the allowed HTTP verbs for this resource. +Returns the allowed HTTP verbs for the this resource. ##### Example ``` -$ curl -i -X OPTIONS http://127.0.0.1:9500/docs +$ curl -i -X OPTIONS 'http://127.0.0.1:9500/docs' HTTP/1.1 200 OK Content-Length: 0 Access-Control-Allow-Methods: HEAD,GET,OPTIONS,POST

@@ -44,7 +49,7 @@

##### Example ``` -curl -i -X OPTIONS http://0.0.0.0:9500/docs/test +curl -i -X OPTIONS 'http://127.0.0.1:9500/docs/test' HTTP/1.1 200 OK Content-Length: 0 Allow: HEAD,GET,PUT,PATCH,DELETE,OPTIONS

@@ -52,8 +57,12 @@ ```

#### POST docs +Creates a new document with a randomly-generated ID. + +##### Example + ``` -$ curl -i -X POST -d 'A document with a randomly-generated ID.' http://127.0.0.1:9500/docs --header "Content-Type:text/plain" +$ curl -i -X POST -d 'A document with a randomly-generated ID.' 'http://127.0.0.1:9500/docs' --header "Content-Type:text/plain" HTTP/1.1 201 Created Content-Length: 197 Content-Type: application/json

@@ -66,8 +75,10 @@ ```

#### HEAD docs +Retrieves all headers related to the docs resource and no content (this is probably not that useful, but at least it should make REST purists happy). + ``` -$ curl -i -X HEAD http://127.0.0.1:9500/docs +$ curl -i -X HEAD 'http://127.0.0.1:9500/docs' HTTP/1.1 200 OK Content-Length: 0 Content-Type: application/json

@@ -78,8 +89,10 @@ ```

#### HEAD docs/:id +Retrieves all headers related to the a document and no content. Useful to check whether a document exists or not. + ``` -$ curl -i -X HEAD http://127.0.0.1:9500/docs/test +$ curl -i -X HEAD 'http://127.0.0.1:9500/docs/test' HTTP/1.1 200 OK Content-Length: 0 Content-Type: application/json

@@ -90,27 +103,82 @@ ```

#### GET docs -``` -... -``` +Retrieves a list of documents in JSON format. ##### Query String Options The following query string options are supported: -* **search** -* **tags** -* **limit** -* **offset** -* **sort** -* **contents** -* **raw** +* **search** &ndash; Search for the specified string. Example: `http://127.0.0.1:9500/docs/?search=Something`. +* **tags** &ndash; Retrieve only documents with matching tag(s). Example: `http://127.0.0.1:9500/docs/?tags=tag1,tag2` +* **limit** &ndash; Retrieve only the first _n_ results. Example: `http://127.0.0.1:9500/docs/?limit=5` +* **offset** &ndash; Skip the first _n_ results. Example: `http://127.0.0.1:9500/docs/?offset=5` +* **sort** &ndash; Sort by **created**, **modified**, or **id**. Example: `http://127.0.0.1:9500/docs/?sort=id` +* **contents** &ndash; If set to **false**, do not retrieve document data. Example: `http://127.0.0.1:9500/docs/?contents=false` +##### Example + +``` +$ curl -i 'http://localhost:9500/docs?contents=false&tags=$subtype:css' +HTTP/1.1 200 OK +Content-Length: 855 +Content-Type: application/json +Access-Control-Allow-Headers: Content-Type +Access-Control-Allow-Origin: * +Server: LiteStore/1.0.0 + +{ + "tags": [ + "$subtype:css" + ], + "total": 3, + "execution_time": 0.001190000000000024, + "results": [ + { + "id": "admin/styles/bootstrap-theme.min.css", + "created": "2015-09-19T01:37:59Z", + "modified": null, + "tags": [ + "$type:text", + "$subtype:css", + "$format:text", + "$dir:admin" + ] + }, + { + "id": "admin/styles/bootstrap.min.css", + "created": "2015-09-19T01:37:59Z", + "modified": null, + "tags": [ + "$type:text", + "$subtype:css", + "$format:text", + "$dir:admin" + ] + }, + { + "id": "admin/styles/litestore.css", + "created": "2015-09-19T01:37:59Z", + "modified": null, + "tags": [ + "$type:text", + "$subtype:css", + "$format:text", + "$dir:admin" + ] + } + ] +} +``` #### GET docs/:id +Retrieves the specified document. By default the response is returned in the document's content type; however, it is possible to retrieve the raw document (including metadata) in JSON format by setting the **raw** query string option to true. + +##### Example: original content type + ``` -$ curl -i http://127.0.0.1:9500/docs/test +$ curl -i 'http://127.0.0.1:9500/docs/test' HTTP/1.1 200 OK Content-Length: 24 Content-Type: text/plain

@@ -121,10 +189,24 @@

This is a test document. ``` +###### Example: raw format + +``` +$ curl -i 'http://127.0.0.1:9500/docs/test?raw=true' +HTTP/1.1 200 OK +Content-Length: 191 +Content-Type: application/json +Access-Control-Allow-Headers: Content-Type +Access-Control-Allow-Origin: * +Server: LiteStore/1.0.0 + +{"id": "test", "data": "This is a test document.", "created": "2015-09-19T08:07:43Z", "modified": null, "tags": ["$type:text", "$subtype:plain", "$format:text"]} +``` + #### PUT docs/:id ``` -$ curl -i -X PUT -d 'This is a test document.' http://127.0.0.1:9500/docs/test --header "Content-Type:text/plain" +$ curl -i -X PUT -d 'This is a test document.' 'http://127.0.0.1:9500/docs/test' --header "Content-Type:text/plain" HTTP/1.1 201 Created Content-Length: 161 Content-Type: application/json

@@ -143,6 +225,13 @@ ```

#### DELETE docs/:id +##### Example + ``` -... +$ curl -i -X DELETE 'http://127.0.0.1:9500/docs/test' +HTTP/1.1 204 No Content +Content-Length: 0 +Access-Control-Allow-Headers: Content-Type +Access-Control-Allow-Origin: * +Server: LiteStore/1.0.0 ```
M lib/core.nimlib/core.nim

@@ -178,6 +178,7 @@ if id == "":

id = $genOid() # Store document try: + LOG.debug("Creating document '$1'" % id) store.begin() var res = store.db.insertID(SQL_INSERT_DOCUMENT, id, data, contenttype, binary, searchable, currentTime()) if res > 0:

@@ -212,6 +213,7 @@ var searchable = searchable

if binary == 1: searchable = 0 try: + LOG.debug("Updating document '$1'" % id) store.begin() var res = store.db.execAffectedRows(SQL_UPDATE_DOCUMENT, data, contenttype, binary, searchable, currentTime(), id) if res > 0:

@@ -239,6 +241,7 @@

proc destroyDocument*(store: Datastore, id: string): int64 = try: let singleOp = not LS_TRANSACTION + LOG.debug("Destroying document '$1'" % id) store.begin() result = store.db.execAffectedRows(SQL_DELETE_DOCUMENT, id) if result > 0:

@@ -261,9 +264,12 @@ var options = options

options.single = true var select = prepareSelectDocumentsQuery(options) var raw_document = store.db.getRow(select.sql, id) + LOG.debug("Retrieving document '$1'" % id) if raw_document[0] == "": + LOG.debug("(No Data)") return (data: "", contenttype: "") else: + LOG.debug("Content Length: $1" % $(raw_document[1].len)) if raw_document[3].parseInt == 1: return (data: raw_document[1].decode, contenttype: raw_document[2]) else:
M lib/utils.nimlib/utils.nim

@@ -22,13 +22,13 @@ if c == '\'': add(result, "''")

else: add(result, c) add(result, '\'') -proc selectDocumentsByTags(tags: string): string = +proc selectDocumentsByTags(tags: string, doc_id_col = "id"): string = var select_tagged = "SELECT document_id FROM tags WHERE tag_id = '" result = "" for tag in tags.split(','): if not tag.match(PEG_TAG): raise newException(EInvalidTag, "Invalid tag '$1'" % tag) - result = result & "AND id IN (" & select_tagged & tag & "') " + result = result & "AND " & doc_id_col & " IN (" & select_tagged & tag & "') " proc prepareSelectDocumentsQuery*(options: var QueryOptions): string = result = "SELECT "

@@ -62,7 +62,12 @@ result = result & " FROM documents WHERE 1=1 "

if options.single: result = result & "AND id = ?" if options.tags.len > 0: - result = result & options.tags.selectDocumentsByTags() + var doc_id_col: string + if options.search.len > 0 and options.select[0] != "COUNT(docid)": + doc_id_col = "documents.id" + else: + doc_id_col = "id" + result = result & options.tags.selectDocumentsByTags(doc_id_col) if options.search.len > 0: result = result & "AND searchdata MATCH '" & options.search.replace("'", "''") & "' " if options.orderby.len > 0 and options.select[0] != "COUNT(docid)":

@@ -112,6 +117,7 @@ continue

of "content_type": if rawvalue == "application/json": jsondoc = true + continue else: discard if rawvalue == "":