diff --git a/.travis.yml b/.travis.yml index 23396e14..eb808d4a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,5 +2,5 @@ language: rust script: - cargo build --verbose - cargo test --verbose - - cargo test --verbose -p datomish-query-parser - - cargo test --verbose -p datomish-cli \ No newline at end of file + - cargo test --verbose -p mentat_query_parser + - cargo test --verbose -p mentat_cli diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2f84292e..05bd945f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -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 comment on a bug before putting significant effort in, if you'd like to @@ -29,10 +29,10 @@ Signed-off-by: Random J Developer ## 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. ``` -git clone git@github.com:YOURNAME/datomish.git +git clone git@github.com:YOURNAME/mentat.git ``` Check your remotes: ``` @@ -40,7 +40,7 @@ git remote --verbose ``` 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: diff --git a/Cargo.toml b/Cargo.toml index 5fc8c42b..b897cbcc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,18 +1,18 @@ [package] -name = "datomish" +name = "mentat" version = "0.4.0" authors = ["Richard Newman ", "Nicholas Alexander "] [dependencies] rusqlite = "0.8.0" -[dependencies.datomish-query-parser] +[dependencies.mentat_query_parser] path = "query-parser" [dev-dependencies] -[dev-dependencies.datomish-cli] +[dev-dependencies.mentat_cli] path = "cli" [[bin]] -name = "datomish-cli" -path = "cli/src/main.rs" \ No newline at end of file +name = "mentat_cli" +path = "cli/src/main.rs" diff --git a/README.md b/README.md index 42ef7246..e7c9766f 100644 --- a/README.md +++ b/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 -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. @@ -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?" -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/).) @@ -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. -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 @@ -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. -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 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 @@ -78,7 +78,7 @@ To run tests use: cargo test # Run tests for the query-parser folder -cargo test -p datomish-query-parser +cargo test -p mentat_query_parser ```` To start the cli use: @@ -87,15 +87,15 @@ To start the cli use: 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 -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 -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). diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 83950fb8..1fa09f50 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -1,7 +1,7 @@ [package] -name = "datomish-cli" +name = "mentat_cli" version = "0.0.1" [dependencies] -[dependencies.datomish] - path = "../" \ No newline at end of file +[dependencies.mentat] + path = "../" diff --git a/cli/README.md b/cli/README.md index b067eb15..0ac97748 100644 --- a/cli/README.md +++ b/cli/README.md @@ -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. diff --git a/cli/src/main.rs b/cli/src/main.rs index 861e8670..9ac6a22d 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -9,11 +9,11 @@ // specific language governing permissions and limitations under the License. use std::env; -extern crate datomish; +extern crate mentat; // This is just a placeholder to get the project structure in place. fn main() { - println!("Loaded {}", datomish::get_name()); + println!("Loaded {}", mentat::get_name()); let args: Vec = env::args().collect(); println!("I got {:?} arguments: {:?}.", args.len() - 1, &args[1..]); diff --git a/js/.babelrc b/js/.babelrc deleted file mode 100644 index d707934a..00000000 --- a/js/.babelrc +++ /dev/null @@ -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 -} diff --git a/js/addon/.babelrc b/js/addon/.babelrc deleted file mode 100644 index a0dc53f5..00000000 --- a/js/addon/.babelrc +++ /dev/null @@ -1,6 +0,0 @@ -{ - "presets": ["es2015"], - "plugins": [ - "transform-async-to-generator" - ] -} diff --git a/js/addon/CREDITS b/js/addon/CREDITS deleted file mode 100644 index 359a4f89..00000000 --- a/js/addon/CREDITS +++ /dev/null @@ -1,3 +0,0 @@ -Icon file is "Line Graph" by Cris Dobbins, from The Noun Project. - -https://thenounproject.com/term/line-graph/145324/ diff --git a/js/addon/build.sh b/js/addon/build.sh deleted file mode 100755 index 925bc6c3..00000000 --- a/js/addon/build.sh +++ /dev/null @@ -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 diff --git a/js/addon/package.json b/js/addon/package.json deleted file mode 100644 index c2e4d9f0..00000000 --- a/js/addon/package.json +++ /dev/null @@ -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" - } -} diff --git a/js/addon/release/README.md b/js/addon/release/README.md deleted file mode 100644 index 85643d4f..00000000 --- a/js/addon/release/README.md +++ /dev/null @@ -1,2 +0,0 @@ -#Datomish Test -An example add-on that loads Datomish on top of Sqlite.jsm. \ No newline at end of file diff --git a/js/addon/release/data/datomish-48.png b/js/addon/release/data/datomish-48.png deleted file mode 100644 index 42b9cb67..00000000 Binary files a/js/addon/release/data/datomish-48.png and /dev/null differ diff --git a/js/addon/release/package.json b/js/addon/release/package.json deleted file mode 100644 index 6a190546..00000000 --- a/js/addon/release/package.json +++ /dev/null @@ -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 ", - "engines": { - "firefox": ">=48.0a1" - }, - "license": "MPL-2.0", - "keywords": [ - "jetpack" - ] -} diff --git a/js/addon/release/run.sh b/js/addon/release/run.sh deleted file mode 100755 index 40114394..00000000 --- a/js/addon/release/run.sh +++ /dev/null @@ -1 +0,0 @@ -jpm run -b /Applications/FirefoxNightly.app/ diff --git a/js/addon/src/index.js b/js/addon/src/index.js deleted file mode 100644 index d0cb6142..00000000 --- a/js/addon/src/index.js +++ /dev/null @@ -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 -}); diff --git a/js/addon/src/wrapper.prefix b/js/addon/src/wrapper.prefix deleted file mode 100644 index f69c8236..00000000 --- a/js/addon/src/wrapper.prefix +++ /dev/null @@ -1,4 +0,0 @@ -// Monkeypatch. -var { setTimeout } = require("sdk/timers"); -this.setTimeout = setTimeout; - diff --git a/js/addon/webpack.config.js b/js/addon/webpack.config.js deleted file mode 100644 index f82bede4..00000000 --- a/js/addon/webpack.config.js +++ /dev/null @@ -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' - }] - } -} diff --git a/js/test/js/tests.js b/js/test/js/tests.js deleted file mode 100644 index 6cd92536..00000000 --- a/js/test/js/tests.js +++ /dev/null @@ -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)); diff --git a/js/test/v1.db b/js/test/v1.db deleted file mode 100644 index e76cdbfd..00000000 Binary files a/js/test/v1.db and /dev/null differ diff --git a/query-parser/Cargo.toml b/query-parser/Cargo.toml index a17d9c6c..e939fdd9 100644 --- a/query-parser/Cargo.toml +++ b/query-parser/Cargo.toml @@ -1,3 +1,3 @@ [package] -name = "datomish-query-parser" -version = "0.0.1" \ No newline at end of file +name = "mentat_query_parser" +version = "0.0.1" diff --git a/query-parser/src/lib.rs b/query-parser/src/lib.rs index 952491a8..4589b6b8 100644 --- a/query-parser/src/lib.rs +++ b/query-parser/src/lib.rs @@ -10,7 +10,7 @@ // This file is just a stub pub fn get_name() -> String { - return String::from("datomish-query-parser"); + return String::from("mentat-query-parser"); } #[cfg(test)] @@ -19,6 +19,6 @@ mod tests { #[test] fn it_works() { - assert_eq!(String::from("datomish-query-parser"), get_name()); + assert_eq!(String::from("mentat-query-parser"), get_name()); } -} \ No newline at end of file +} diff --git a/src/lib.rs b/src/lib.rs index e259b8d8..ae434424 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,18 +8,18 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -extern crate datomish_query_parser; +extern crate mentat_query_parser; extern crate rusqlite; use rusqlite::Connection; pub fn get_name() -> String { - return String::from("datomish"); + return String::from("mentat"); } // Just an example of using a dependency 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 @@ -33,6 +33,6 @@ mod tests { #[test] fn can_import_parser() { - assert_eq!(String::from("datomish-query-parser"), get_parser_name()); + assert_eq!(String::from("mentat-query-parser"), get_parser_name()); } -} \ No newline at end of file +} diff --git a/tests/external_test.rs b/tests/external_test.rs index 13c65dee..88d49967 100644 --- a/tests/external_test.rs +++ b/tests/external_test.rs @@ -8,7 +8,7 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -extern crate datomish; +extern crate mentat; #[test] fn can_import_sqlite() { @@ -20,7 +20,7 @@ fn can_import_sqlite() { data: Option> } - let conn = datomish::get_connection(); + let conn = mentat::get_connection(); conn.execute("CREATE TABLE person ( id INTEGER PRIMARY KEY,