Rename everything to Project Mentat. r=bgrins
This commit is contained in:
commit
22ebcd65f3
25 changed files with 44 additions and 367 deletions
|
@ -2,5 +2,5 @@ language: rust
|
||||||
script:
|
script:
|
||||||
- cargo build --verbose
|
- cargo build --verbose
|
||||||
- cargo test --verbose
|
- cargo test --verbose
|
||||||
- cargo test --verbose -p datomish-query-parser
|
- cargo test --verbose -p mentat_query_parser
|
||||||
- cargo test --verbose -p datomish-cli
|
- cargo test --verbose -p mentat_cli
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# How to contribute to Datomish
|
# How to contribute to Project Mentat
|
||||||
|
|
||||||
This project is very new, so we'll probably revise these guidelines. Please
|
This project is very new, so we'll probably revise these guidelines. Please
|
||||||
comment on a bug before putting significant effort in, if you'd like to
|
comment on a bug before putting significant effort in, if you'd like to
|
||||||
|
@ -29,10 +29,10 @@ Signed-off-by: Random J Developer <random@developer.example.org>
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
|
||||||
* Fork this repo at [github.com/mozilla/datomish](https://github.com/mozilla/datomish#fork-destination-box).
|
* Fork this repo at [github.com/mozilla/mentat](https://github.com/mozilla/mentat#fork-destination-box).
|
||||||
* Clone your fork locally. Make sure you use the correct clone URL.
|
* Clone your fork locally. Make sure you use the correct clone URL.
|
||||||
```
|
```
|
||||||
git clone git@github.com:YOURNAME/datomish.git
|
git clone git@github.com:YOURNAME/mentat.git
|
||||||
```
|
```
|
||||||
Check your remotes:
|
Check your remotes:
|
||||||
```
|
```
|
||||||
|
@ -40,7 +40,7 @@ git remote --verbose
|
||||||
```
|
```
|
||||||
Make sure you have an upstream remote defined:
|
Make sure you have an upstream remote defined:
|
||||||
```
|
```
|
||||||
git remote add upstream https://github.com/mozilla/datomish
|
git remote add upstream https://github.com/mozilla/mentat
|
||||||
```
|
```
|
||||||
|
|
||||||
* Create a new branch to start working on a bug or feature:
|
* Create a new branch to start working on a bug or feature:
|
||||||
|
|
10
Cargo.toml
10
Cargo.toml
|
@ -1,18 +1,18 @@
|
||||||
[package]
|
[package]
|
||||||
name = "datomish"
|
name = "mentat"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
authors = ["Richard Newman <rnewman@twinql.com>", "Nicholas Alexander <nalexander@mozilla.com>"]
|
authors = ["Richard Newman <rnewman@twinql.com>", "Nicholas Alexander <nalexander@mozilla.com>"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rusqlite = "0.8.0"
|
rusqlite = "0.8.0"
|
||||||
|
|
||||||
[dependencies.datomish-query-parser]
|
[dependencies.mentat_query_parser]
|
||||||
path = "query-parser"
|
path = "query-parser"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
[dev-dependencies.datomish-cli]
|
[dev-dependencies.mentat_cli]
|
||||||
path = "cli"
|
path = "cli"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "datomish-cli"
|
name = "mentat_cli"
|
||||||
path = "cli/src/main.rs"
|
path = "cli/src/main.rs"
|
||||||
|
|
30
README.md
30
README.md
|
@ -1,15 +1,15 @@
|
||||||
# Datomish
|
# Project Mentat
|
||||||
|
|
||||||
Datomish is a persistent, embedded knowledge base. It draws heavily on [DataScript](https://github.com/tonsky/datascript) and [Datomic](http://datomic.com).
|
Project Mentat is a persistent, embedded knowledge base. It draws heavily on [DataScript](https://github.com/tonsky/datascript) and [Datomic](http://datomic.com).
|
||||||
|
|
||||||
The first version of Datomish [was written in ClojureScript](https://github.com/mozilla/datomish/tree/master), targeting both Node (on top of `promise_sqlite`) and Firefox (on top of `Sqlite.jsm`). It also works in pure Clojure on the JVM on top of `jdbc-sqlite`.
|
The first version of Project Mentat, named Datomish, [was written in ClojureScript](https://github.com/mozilla/mentat/tree/master), targeting both Node (on top of `promise_sqlite`) and Firefox (on top of `Sqlite.jsm`). It also works in pure Clojure on the JVM on top of `jdbc-sqlite`. The name was changed to avoid confusion with [Datomic](http://datomic.com).
|
||||||
|
|
||||||
This branch is for rewriting Datomish in Rust, giving us a smaller compiled output, better performance, more type safety, better tooling, and easier deployment into Firefox and mobile platforms.
|
This branch is for rewriting Mentat in Rust, giving us a smaller compiled output, better performance, more type safety, better tooling, and easier deployment into Firefox and mobile platforms.
|
||||||
|
|
||||||
|
|
||||||
## Motivation
|
## Motivation
|
||||||
|
|
||||||
Datomish is intended to be a flexible relational (not key-value, not document-oriented) store that doesn't leak its storage schema to users, and doesn't make it hard to grow its domain schema and run arbitrary queries.
|
Mentat is intended to be a flexible relational (not key-value, not document-oriented) store that doesn't leak its storage schema to users, and doesn't make it hard to grow its domain schema and run arbitrary queries.
|
||||||
|
|
||||||
Our short-term goal is to build a system that, as the basis for a User Agent Service, can support multiple [Tofino](https://github.com/mozilla/tofino) UX experiments without having a storage engineer do significant data migration, schema work, or revving of special-purpose endpoints.
|
Our short-term goal is to build a system that, as the basis for a User Agent Service, can support multiple [Tofino](https://github.com/mozilla/tofino) UX experiments without having a storage engineer do significant data migration, schema work, or revving of special-purpose endpoints.
|
||||||
|
|
||||||
|
@ -20,9 +20,9 @@ By abstracting away the storage schema, and by exposing change listeners outside
|
||||||
|
|
||||||
DataScript asks the question: "What if creating a database would be as cheap as creating a Hashmap?"
|
DataScript asks the question: "What if creating a database would be as cheap as creating a Hashmap?"
|
||||||
|
|
||||||
Datomish is not interested in that. Instead, it's strongly interested in persistence and performance, with very little interest in immutable databases/databases as values or throwaway use.
|
Mentat is not interested in that. Instead, it's strongly interested in persistence and performance, with very little interest in immutable databases/databases as values or throwaway use.
|
||||||
|
|
||||||
One might say that Datomish's question is: "What if an SQLite database could store arbitrary relations, for arbitrary consumers, without them having to coordinate an up-front storage-level schema?"
|
One might say that Mentat's question is: "What if an SQLite database could store arbitrary relations, for arbitrary consumers, without them having to coordinate an up-front storage-level schema?"
|
||||||
|
|
||||||
(Note that [domain-level schemas are very valuable](http://martinfowler.com/articles/schemaless/).)
|
(Note that [domain-level schemas are very valuable](http://martinfowler.com/articles/schemaless/).)
|
||||||
|
|
||||||
|
@ -30,9 +30,9 @@ Another possible question would be: "What if we could bake some of the concepts
|
||||||
|
|
||||||
Some thought has been given to how databases as values — long-term references to a snapshot of the store at an instant in time — could work in this model. It's not impossible; it simply has different performance characteristics.
|
Some thought has been given to how databases as values — long-term references to a snapshot of the store at an instant in time — could work in this model. It's not impossible; it simply has different performance characteristics.
|
||||||
|
|
||||||
Just like DataScript, Datomish speaks Datalog for querying and takes additions and retractions as input to a transaction. Unlike DataScript, Datomish's API is asynchronous.
|
Just like DataScript, Mentat speaks Datalog for querying and takes additions and retractions as input to a transaction. Unlike DataScript, Mentat's API is asynchronous.
|
||||||
|
|
||||||
Unlike DataScript, Datomish exposes free-text indexing, thanks to SQLite.
|
Unlike DataScript, Mentat exposes free-text indexing, thanks to SQLite.
|
||||||
|
|
||||||
|
|
||||||
## Comparison to Datomic
|
## Comparison to Datomic
|
||||||
|
@ -41,14 +41,14 @@ Datomic is a server-side, enterprise-grade data storage system. Datomic has a be
|
||||||
|
|
||||||
Many of these design decisions are inapplicable to deployed desktop software; indeed, the use of multiple JVM processes makes Datomic's use in a small desktop app, or a mobile device, prohibitive.
|
Many of these design decisions are inapplicable to deployed desktop software; indeed, the use of multiple JVM processes makes Datomic's use in a small desktop app, or a mobile device, prohibitive.
|
||||||
|
|
||||||
Datomish is designed for embedding, initially in an Electron app ([Tofino](https://github.com/mozilla/tofino)). It is less concerned with exposing consistent database states outside transaction boundaries, because that's less important here, and dropping some of these requirements allows us to leverage SQLite itself.
|
Mentat is designed for embedding, initially in an Electron app ([Tofino](https://github.com/mozilla/tofino)). It is less concerned with exposing consistent database states outside transaction boundaries, because that's less important here, and dropping some of these requirements allows us to leverage SQLite itself.
|
||||||
|
|
||||||
|
|
||||||
## Comparison to SQLite
|
## Comparison to SQLite
|
||||||
|
|
||||||
SQLite is a traditional SQL database in most respects: schemas conflate semantic, structural, and datatype concerns; the main interface with the database is human-first textual queries; sparse and graph-structured data are 'unnatural', if not always inefficient; experimenting with and evolving data models are error-prone and complicated activities; and so on.
|
SQLite is a traditional SQL database in most respects: schemas conflate semantic, structural, and datatype concerns; the main interface with the database is human-first textual queries; sparse and graph-structured data are 'unnatural', if not always inefficient; experimenting with and evolving data models are error-prone and complicated activities; and so on.
|
||||||
|
|
||||||
Datomish aims to offer many of the advantages of SQLite — single-file use, embeddability, and good performance — while building a more relaxed and expressive data model on top.
|
Mentat aims to offer many of the advantages of SQLite — single-file use, embeddability, and good performance — while building a more relaxed and expressive data model on top.
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ To run tests use:
|
||||||
cargo test
|
cargo test
|
||||||
|
|
||||||
# Run tests for the query-parser folder
|
# Run tests for the query-parser folder
|
||||||
cargo test -p datomish-query-parser
|
cargo test -p mentat_query_parser
|
||||||
````
|
````
|
||||||
|
|
||||||
To start the cli use:
|
To start the cli use:
|
||||||
|
@ -87,15 +87,15 @@ To start the cli use:
|
||||||
cargo run
|
cargo run
|
||||||
````
|
````
|
||||||
|
|
||||||
For most `cargo` commands you can pass the `-p` argument to run the command just on that package. By convention, the package name will be "datomish-directory-name". So, `cargo build -p datomish-cli` will build just the "cli" folder.
|
For most `cargo` commands you can pass the `-p` argument to run the command just on that package. By convention, the package name will be "mentat_package_name". So, `cargo build -p mentat_cli` will build just the "cli" folder.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
Datomish is currently licensed under the Apache License v2.0. See the `LICENSE` file for details.
|
Project Mentat is currently licensed under the Apache License v2.0. See the `LICENSE` file for details.
|
||||||
|
|
||||||
|
|
||||||
## SQLite dependencies
|
## SQLite dependencies
|
||||||
|
|
||||||
Datomish uses partial indices, which are available in SQLite 3.8.0 and higher.
|
Mentat uses partial indices, which are available in SQLite 3.8.0 and higher.
|
||||||
|
|
||||||
It also uses FTS4, which is [a compile time option](http://www.sqlite.org/fts3.html#section_2).
|
It also uses FTS4, which is [a compile time option](http://www.sqlite.org/fts3.html#section_2).
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
name = "datomish-cli"
|
name = "mentat_cli"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
[dependencies.datomish]
|
[dependencies.mentat]
|
||||||
path = "../"
|
path = "../"
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
# datomish-cli
|
# mentat-cli
|
||||||
|
|
||||||
Note: this isn't actually doing anything and is just a placeholder to get the project structure in place.
|
Note: this isn't actually doing anything and is just a placeholder to get the project structure in place.
|
||||||
|
|
|
@ -9,11 +9,11 @@
|
||||||
// specific language governing permissions and limitations under the License.
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
extern crate datomish;
|
extern crate mentat;
|
||||||
|
|
||||||
// This is just a placeholder to get the project structure in place.
|
// This is just a placeholder to get the project structure in place.
|
||||||
fn main() {
|
fn main() {
|
||||||
println!("Loaded {}", datomish::get_name());
|
println!("Loaded {}", mentat::get_name());
|
||||||
|
|
||||||
let args: Vec<String> = env::args().collect();
|
let args: Vec<String> = env::args().collect();
|
||||||
println!("I got {:?} arguments: {:?}.", args.len() - 1, &args[1..]);
|
println!("I got {:?} arguments: {:?}.", args.len() - 1, &args[1..]);
|
||||||
|
|
27
js/.babelrc
27
js/.babelrc
|
@ -1,27 +0,0 @@
|
||||||
{
|
|
||||||
"env": {
|
|
||||||
"production": {
|
|
||||||
"presets": ["react", "react-optimize"]
|
|
||||||
},
|
|
||||||
"development": {
|
|
||||||
"presets": ["react"]
|
|
||||||
},
|
|
||||||
"test": {
|
|
||||||
"presets": ["react"]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"only": [
|
|
||||||
"test/js/**"
|
|
||||||
],
|
|
||||||
"plugins": [
|
|
||||||
"transform-es2015-destructuring",
|
|
||||||
"transform-es2015-parameters",
|
|
||||||
"transform-es2015-modules-commonjs",
|
|
||||||
"transform-async-to-generator",
|
|
||||||
"transform-object-rest-spread",
|
|
||||||
"transform-class-properties",
|
|
||||||
"transform-runtime"
|
|
||||||
],
|
|
||||||
"sourceMaps": "inline",
|
|
||||||
"retainLines": true
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
{
|
|
||||||
"presets": ["es2015"],
|
|
||||||
"plugins": [
|
|
||||||
"transform-async-to-generator"
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -1,3 +0,0 @@
|
||||||
Icon file is "Line Graph" by Cris Dobbins, from The Noun Project.
|
|
||||||
|
|
||||||
https://thenounproject.com/term/line-graph/145324/
|
|
|
@ -1,3 +0,0 @@
|
||||||
cp ../target/release-browser/datomish.js release/
|
|
||||||
node_modules/.bin/webpack -p
|
|
||||||
cat src/wrapper.prefix built/index.js > release/index.js
|
|
|
@ -1,23 +0,0 @@
|
||||||
{
|
|
||||||
"name": "datomish-example",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"description": "A test add-on for Datomish and Firefox.",
|
|
||||||
"main": "index.js",
|
|
||||||
"scripts": {
|
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
|
||||||
},
|
|
||||||
"author": "",
|
|
||||||
"license": "MPL-2.0",
|
|
||||||
"devDependencies": {
|
|
||||||
"babel": "^6.5.2",
|
|
||||||
"babel-cli": "^6.14.0",
|
|
||||||
"babel-core": "^6.14.0",
|
|
||||||
"babel-loader": "^6.2.5",
|
|
||||||
"babel-plugin-transform-async-to-generator": "^6.8.0",
|
|
||||||
"babel-preset-es2015": "^6.14.0",
|
|
||||||
"webpack": "^1.13.2"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"babel-polyfill": "^6.13.0"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,2 +0,0 @@
|
||||||
#Datomish Test
|
|
||||||
An example add-on that loads Datomish on top of Sqlite.jsm.
|
|
Binary file not shown.
Before Width: | Height: | Size: 1.1 KiB |
|
@ -1,15 +0,0 @@
|
||||||
{
|
|
||||||
"title": "Datomish Test",
|
|
||||||
"name": "datomish-test",
|
|
||||||
"version": "0.0.1",
|
|
||||||
"description": "An example add-on that loads Datomish on top of Sqlite.jsm.",
|
|
||||||
"main": "index.js",
|
|
||||||
"author": "Richard Newman <rnewman@mozilla.com>",
|
|
||||||
"engines": {
|
|
||||||
"firefox": ">=48.0a1"
|
|
||||||
},
|
|
||||||
"license": "MPL-2.0",
|
|
||||||
"keywords": [
|
|
||||||
"jetpack"
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
jpm run -b /Applications/FirefoxNightly.app/
|
|
|
@ -1,92 +0,0 @@
|
||||||
/* Any copyright is dedicated to the Public Domain.
|
|
||||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
|
||||||
|
|
||||||
var self = require("sdk/self");
|
|
||||||
var buttons = require('sdk/ui/button/action');
|
|
||||||
var tabs = require('sdk/tabs');
|
|
||||||
|
|
||||||
var datomish = require("datomish.js");
|
|
||||||
|
|
||||||
var schema = {
|
|
||||||
"name": "pages",
|
|
||||||
"attributes": [
|
|
||||||
{"name": "page/url",
|
|
||||||
"type": "string",
|
|
||||||
"cardinality": "one",
|
|
||||||
"unique": "identity",
|
|
||||||
"doc": "A page's URL."},
|
|
||||||
{"name": "page/title",
|
|
||||||
"type": "string",
|
|
||||||
"cardinality": "one",
|
|
||||||
"fulltext": true,
|
|
||||||
"doc": "A page's title."},
|
|
||||||
{"name": "page/content",
|
|
||||||
"type": "string",
|
|
||||||
"cardinality": "one", // Simple for now.
|
|
||||||
"fulltext": true,
|
|
||||||
"doc": "A snapshot of the page's content. Should be plain text."},
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
async function initDB(path) {
|
|
||||||
let db = await datomish.open(path);
|
|
||||||
await db.ensureSchema(schema);
|
|
||||||
return db;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function findURLs(db) {
|
|
||||||
let query = `[:find ?page ?url ?title :in $ :where [?page :page/url ?url][(get-else $ ?page :page/title "") ?title]]`;
|
|
||||||
let options = new Object();
|
|
||||||
options["limit"] = 10;
|
|
||||||
return datomish.q(db.db(), query, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function findPagesMatching(db, string) {
|
|
||||||
let query =
|
|
||||||
`[:find ?url ?title
|
|
||||||
:in $ ?str
|
|
||||||
:where
|
|
||||||
[(fulltext $ :any ?str) [[?page]]]
|
|
||||||
[?page :page/url ?url]
|
|
||||||
[(get-else $ ?page :page/title "") ?title]]`;
|
|
||||||
return datomish.q(db.db(), query, {"limit": 10, "inputs": {"str": string}});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function savePage(db, url, title, content) {
|
|
||||||
let datom = {"db/id": 55, "page/url": url};
|
|
||||||
if (title) {
|
|
||||||
datom["page/title"] = title;
|
|
||||||
}
|
|
||||||
if (content) {
|
|
||||||
datom["page/content"] = content;
|
|
||||||
}
|
|
||||||
let txResult = await db.transact([datom]);
|
|
||||||
return txResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function handleClick(state) {
|
|
||||||
let db = await datomish.open("/tmp/testing.db");
|
|
||||||
await db.ensureSchema(schema);
|
|
||||||
|
|
||||||
let txResult = await savePage(db, tabs.activeTab.url, tabs.activeTab.title, "Content goes here");
|
|
||||||
|
|
||||||
console.log("Transaction returned " + JSON.stringify(txResult));
|
|
||||||
console.log("Transaction instant: " + txResult.txInstant);
|
|
||||||
|
|
||||||
let results = await findURLs(db);
|
|
||||||
results = results.map(r => r[1]);
|
|
||||||
|
|
||||||
console.log("Query results: " + JSON.stringify(results));
|
|
||||||
|
|
||||||
let pages = await findPagesMatching(db, "goes");
|
|
||||||
|
|
||||||
console.log("Pages: " + JSON.stringify(pages));
|
|
||||||
await db.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
var button = buttons.ActionButton({
|
|
||||||
id: "datomish-save",
|
|
||||||
label: "Save Page",
|
|
||||||
icon: "./datomish-48.png",
|
|
||||||
onClick: handleClick
|
|
||||||
});
|
|
|
@ -1,4 +0,0 @@
|
||||||
// Monkeypatch.
|
|
||||||
var { setTimeout } = require("sdk/timers");
|
|
||||||
this.setTimeout = setTimeout;
|
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
entry: ['babel-polyfill', './src/index.js'],
|
|
||||||
output: {
|
|
||||||
filename: 'built/index.js'
|
|
||||||
},
|
|
||||||
target: 'webworker',
|
|
||||||
externals: {
|
|
||||||
'datomish.js': 'commonjs datomish.js',
|
|
||||||
'sdk/self': 'commonjs sdk/self',
|
|
||||||
'sdk/ui/button/action': 'commonjs sdk/ui/button/action',
|
|
||||||
'sdk/tabs': 'commonjs sdk/tabs'
|
|
||||||
},
|
|
||||||
module: {
|
|
||||||
loaders: [{
|
|
||||||
test: /\.js?$/,
|
|
||||||
exclude: /(node_modules)|(wrapper.prefix)/,
|
|
||||||
loader: 'babel'
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,126 +0,0 @@
|
||||||
/* Copyright 2016 Mozilla
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
|
||||||
* this file except in compliance with the License. You may obtain a copy of the
|
|
||||||
* License at http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* Unless required by applicable law or agreed to in writing, software distributed
|
|
||||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
|
||||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
var datomish = require("../../target/release-node/datomish.js");
|
|
||||||
|
|
||||||
var schema = {
|
|
||||||
"name": "pages",
|
|
||||||
"attributes": [
|
|
||||||
{"name": "page/url",
|
|
||||||
"type": "string",
|
|
||||||
"cardinality": "one",
|
|
||||||
"unique": "identity",
|
|
||||||
"doc": "A page's URL."},
|
|
||||||
{"name": "page/title",
|
|
||||||
"type": "string",
|
|
||||||
"cardinality": "one",
|
|
||||||
"doc": "A page's title."}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
async function testOpen() {
|
|
||||||
// Open a database.
|
|
||||||
let path = "/tmp/testing" + Date.now() + ".db";
|
|
||||||
console.log("Opening " + path);
|
|
||||||
let db = await datomish.open(path);
|
|
||||||
|
|
||||||
// Make sure we have our current schema.
|
|
||||||
await db.ensureSchema(schema);
|
|
||||||
|
|
||||||
// Add some data. Note that we use a temporary ID (the real ID
|
|
||||||
// will be assigned by Datomish).
|
|
||||||
let txResult = await db.transact([
|
|
||||||
{"db/id": datomish.tempid(),
|
|
||||||
"page/url": "https://mozilla.org/",
|
|
||||||
"page/title": "Mozilla"}
|
|
||||||
]);
|
|
||||||
|
|
||||||
console.log("Transaction returned " + JSON.stringify(txResult));
|
|
||||||
console.log("Transaction instant: " + txResult.txInstant);
|
|
||||||
|
|
||||||
// A simple query.
|
|
||||||
let results = await db.q("[:find [?url ...] :in $ :where [?e :page/url ?url]]");
|
|
||||||
console.log("Known URLs: " + JSON.stringify(results));
|
|
||||||
|
|
||||||
// Let's extend our schema. In the real world this would typically happen
|
|
||||||
// across releases.
|
|
||||||
schema.attributes.push({"name": "page/visitedAt",
|
|
||||||
"type": "instant",
|
|
||||||
"cardinality": "many",
|
|
||||||
"doc": "A visit to the page."});
|
|
||||||
await db.ensureSchema(schema);
|
|
||||||
|
|
||||||
// Now we can make assertions with the new vocabulary about existing
|
|
||||||
// entities.
|
|
||||||
// Note that we simply let Datomish find which page we're talking about by
|
|
||||||
// URL -- the URL is a unique property -- so we just use a tempid again.
|
|
||||||
await db.transact([
|
|
||||||
{"db/id": datomish.tempid(),
|
|
||||||
"page/url": "https://mozilla.org/",
|
|
||||||
"page/visitedAt": new Date()}
|
|
||||||
]);
|
|
||||||
|
|
||||||
// When did we most recently visit this page?
|
|
||||||
let date = (await db.q(
|
|
||||||
`[:find (max ?date) .
|
|
||||||
:in $ ?url
|
|
||||||
:where
|
|
||||||
[?page :page/url ?url]
|
|
||||||
[?page :page/visitedAt ?date]]`,
|
|
||||||
{"inputs": {"url": "https://mozilla.org/"}}));
|
|
||||||
console.log("Most recent visit: " + date);
|
|
||||||
|
|
||||||
// Add some more data about a couple of pages.
|
|
||||||
let start = Date.now();
|
|
||||||
let lr = datomish.tempid();
|
|
||||||
let reddit = datomish.tempid();
|
|
||||||
let res = await db.transact([
|
|
||||||
{"db/id": reddit,
|
|
||||||
"page/url": "http://reddit.com/",
|
|
||||||
"page/title": "Reddit",
|
|
||||||
"page/visitedAt": new Date(start)},
|
|
||||||
{"db/id": lr,
|
|
||||||
"page/url": "https://longreads.com/",
|
|
||||||
"page/title": "Longreads: The best longform stories on the web",
|
|
||||||
"page/visitedAt": (new Date(start + 100))},
|
|
||||||
|
|
||||||
// Two visits each.
|
|
||||||
{"db/id": lr,
|
|
||||||
"page/visitedAt": (new Date(start + 200))},
|
|
||||||
{"db/id": reddit,
|
|
||||||
"page/visitedAt": (new Date(start + 300))}
|
|
||||||
]);
|
|
||||||
|
|
||||||
// These are our new persistent IDs. We can use these directly in later
|
|
||||||
// queries or transactions
|
|
||||||
lr = res.tempid(lr);
|
|
||||||
reddit = res.tempid(reddit);
|
|
||||||
console.log("Persistent IDs are " + lr + ", " + reddit + ".");
|
|
||||||
|
|
||||||
// A query with a limit and order-by. Because we limit to 2, and order
|
|
||||||
// by most recent visit date first, we won't get mozilla.org in our results.
|
|
||||||
let recent = await db.q(
|
|
||||||
`[:find ?url (max ?date)
|
|
||||||
:in $
|
|
||||||
:where
|
|
||||||
[?page :page/url ?url]
|
|
||||||
[?page :page/visitedAt ?date]]`,
|
|
||||||
{"limit": 2, "order-by": [["_max_date", "desc"]]});
|
|
||||||
|
|
||||||
console.log("Recently visited: " + JSON.stringify(recent));
|
|
||||||
|
|
||||||
// Close: we're done!
|
|
||||||
await db.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
testOpen()
|
|
||||||
.then((r) => console.log("Done."))
|
|
||||||
.catch((e) => console.log("Failure: " + e.stack));
|
|
BIN
js/test/v1.db
BIN
js/test/v1.db
Binary file not shown.
|
@ -1,3 +1,3 @@
|
||||||
[package]
|
[package]
|
||||||
name = "datomish-query-parser"
|
name = "mentat_query_parser"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
// This file is just a stub
|
// This file is just a stub
|
||||||
pub fn get_name() -> String {
|
pub fn get_name() -> String {
|
||||||
return String::from("datomish-query-parser");
|
return String::from("mentat-query-parser");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -19,6 +19,6 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn it_works() {
|
fn it_works() {
|
||||||
assert_eq!(String::from("datomish-query-parser"), get_name());
|
assert_eq!(String::from("mentat-query-parser"), get_name());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
10
src/lib.rs
10
src/lib.rs
|
@ -8,18 +8,18 @@
|
||||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
// specific language governing permissions and limitations under the License.
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
extern crate datomish_query_parser;
|
extern crate mentat_query_parser;
|
||||||
extern crate rusqlite;
|
extern crate rusqlite;
|
||||||
|
|
||||||
use rusqlite::Connection;
|
use rusqlite::Connection;
|
||||||
|
|
||||||
pub fn get_name() -> String {
|
pub fn get_name() -> String {
|
||||||
return String::from("datomish");
|
return String::from("mentat");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Just an example of using a dependency
|
// Just an example of using a dependency
|
||||||
pub fn get_parser_name() -> String {
|
pub fn get_parser_name() -> String {
|
||||||
return datomish_query_parser::get_name();
|
return mentat_query_parser::get_name();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Will ultimately not return the sqlite connection directly
|
// Will ultimately not return the sqlite connection directly
|
||||||
|
@ -33,6 +33,6 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn can_import_parser() {
|
fn can_import_parser() {
|
||||||
assert_eq!(String::from("datomish-query-parser"), get_parser_name());
|
assert_eq!(String::from("mentat-query-parser"), get_parser_name());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
// specific language governing permissions and limitations under the License.
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
extern crate datomish;
|
extern crate mentat;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn can_import_sqlite() {
|
fn can_import_sqlite() {
|
||||||
|
@ -20,7 +20,7 @@ fn can_import_sqlite() {
|
||||||
data: Option<Vec<u8>>
|
data: Option<Vec<u8>>
|
||||||
}
|
}
|
||||||
|
|
||||||
let conn = datomish::get_connection();
|
let conn = mentat::get_connection();
|
||||||
|
|
||||||
conn.execute("CREATE TABLE person (
|
conn.execute("CREATE TABLE person (
|
||||||
id INTEGER PRIMARY KEY,
|
id INTEGER PRIMARY KEY,
|
||||||
|
|
Loading…
Reference in a new issue