Package Exports
- tuple-database
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (tuple-database) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
Tuple Database
This database stores tuples in component-wise lexicographical sorted order.
import sqlite from "better-sqlite3"
import { SQLiteStorage } from "tuple-database/storage/SQLiteStorage"
const people = [
{ id: 1, first: "Chet", last: "Corcos", age: 29 },
{ id: 2, first: "Simon", last: "Last", age: 26 },
{ id: 3, first: "Jon", last: "Schwartz", age: 30 },
{ id: 4, first: "Luke", last: "Hansen", age: 29 },
]
const sqliteStorage = new SQLiteStorage(sqlite("./app.db"))
const transaction = sqliteStorage.transact()
for (const person of people) {
transaction.set("person", [person.age, person.last, person])
}
transaction.commit()
console.log(sqliteStorage.scan("person", { lt: [30] }))
// [
// [ 26, 'Last', { id: 2, first: 'Simon', last: 'Last', age: 26 } ],
// [ 29, 'Corcos', { id: 1, first: 'Chet', last: 'Corcos', age: 29 } ],
// [ 29, 'Hansen', { id: 4, first: 'Luke', last: 'Hansen', age: 29 } ]
// ]Queries are also reactive based on the index and any prefix for the gt/lt arguments.
import { ReactiveStorage, MIN, MAX } from "tuple-database"
const reactiveStorage = new ReactiveStorage(sqliteStorage)
const [results, unsubscribe] = reactiveStorage.subscribe(
"person",
{ gte: [30, MIN], lte: [30, MAX] }, // Alternatively, we could use { prefix: [30] }
(updates) => {
console.log("UPDATES", updates)
}
)
console.log(results)
// [
// [ 30, 'Schwartz', { id: 3, first: 'Jon', last: 'Schwartz', age: 30 } ]
// ]
// Update my age from 29 -> 30.
reactiveStorage
.transact()
.remove("person", [29, "Corcos", { id: 1, first: 'Chet', last: 'Corcos', age: 29 }])
.set("person", [30, "Corcos", { id: 1, first: 'Chet', last: 'Corcos', age: 30 }])
.commit()
// > UPDATES {
// person: {
// sets: [[30, "Corcos", { id: 1, first: "Chet", last: "Corcos", age: 30 }]],
// removes: [],
// },
// }
// Update Simon's age from 26 -> 27
reactiveStorage
.transact()
.remove("person", [26, 'Last', { id: 2, first: 'Simon', last: 'Last', age: 26 }])
.set("person", [27, 'Last', { id: 2, first: 'Simon', last: 'Last', age: 27 }])
.commit()
// Update doesn't log because it falls outside the query.Why?
Databases are complicated. And as with most complicated things, you might find yourself battling the tool more than battling the problem you're trying to solve.
The goal of this project is to create a dead-simple database. It's just a binary tree index where you can store tuples that are component-wise sorted.
This database pushes all of the data modeling and indexing details down to you, the developer, so you get fine-grained control over read/write performance trade-offs.
Last but not least, this database is designed to be embedded in local-first applications.
Example
To run the example app, clone this repo, then:
npm install
npm run build
cd example
npm install
npm startTODO
TODO:
first we need to solve the ID / custom data types middleware problem
then we need to create runtime validators for type assertions.
last, if we want, we can think about orm ux.
{uuid: string} sounds good enough to me. {date: string} can work just as well.
can we get rid of MIN/Max too?
usability stuff
middleware for schemas and validation kinds of things.
custom data types for Date and others -- this shouldn't be in the database. just the basics. string and number even... boolean and json to be nice.
runtime validators and transformers with nice types.
useSubscribe should have the same api as scan so they can be swapped out.
Might make sense for transaction to have the same apis as well? Prosemirror has state.tx which is interesting... Also tx.commit() might not make the most sense... though the fluent api is nice.
Write an article explaining this project in more detail.
Better reactivity performance? There might be a way to do this with a btree, but I think it might be necessary to build a proper hierarchical structure to make reactivity a more performant.
Some kind of benchmark?
better file format.