Giter Site home page Giter Site logo

vlcn-io / vlcn-orm Goto Github PK

View Code? Open in Web Editor NEW
210.0 10.0 6.0 14.78 MB

Develop with your data model anywhere. Query and load data reactively. Replicate between peers without a central server.

Home Page: https://vlcn.io

License: Other

JavaScript 1.47% TypeScript 98.34% Shell 0.05% HTML 0.13%
database local-first orm peer-to-peer

vlcn-orm's People

Contributors

a-type avatar tantaman avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

vlcn-orm's Issues

Fixup query layer generics

The client facing API always presents the right generics. Internal to the framework they aren't always correct, however.

The problem has to do with queries being able to return different projects.

E.g.,
id, node, edge, hop with nodes projections.

And maybe edges being partially optimized (rolled into prior expressions) as well.

more complex demo app

Todo lists barely require any interesting functionality.

Re-write strut to use Aphrodite and/or some other non-trivial apps.

Add connection pool support

wa-sqlite serializes reads that are on the same connection.

We should update the sqlite connectors to:

  • have a single write connection (all writes are always serialized even at the sqlite level)
  • have N read connections

To allow for parallel reads.

Abstract and simplify edge definition?

Should we allow defining edges without defining id fields??

Foo as Node {
  blahId: ID<Blah>
} & OutboundEdges {
  blah: Edge<Foo.blahId>
}

to:

Foo as Node {
} & Edges {
  blah: OneToOne<Blah>
}

but this removes control from the developer and feels a bit opaque.

Prioritize list of storage backends to support

Given the focus on local-first software the initial list would be:

  • IndexDB
  • SQLite

And to not completely preclude adding a server as a peer for server side syncing

  • Postgres
  • Maria

What else? The list should be fairly limited until we've proven the concept.

i64 support in browser & node

@databases connections do not support 64 bit ints. They silently get truncated.

better-sqlite returns everything as bigints. Not great.

sqlite-3 has a fork that returns ints as strings if they'd overflow.

Single runtime package

Bundle all the various runtime-ts packages into one so its easier for clients to use. Would require updating codegen to import from this single package.

ID Generation

Right now we're using our own 64bit int id generation scheme (loosely based on https://dev.mysql.com/doc/refman/5.6/en/miscellaneous-functions.html#function_uuid-short). Problem is peer ids are not so easily assigned as server ids. Given the issue with assigning ids to peers (and clock skew between peers), I've done no formal verification that this won't collide.

Security would be another concern. What are the attack vectors in the p2p space when the id space is partially deterministic? Data that is shared between trusted peers wouldn't have an issue. "Public" apps where any peer can connect could have malicious peers that try resetting their clocks to clobber data. Authz rules and hmac'd replications should prevent this, however?


We could use nanoid but that has the concerns raised here https://www.percona.com/blog/2019/11/22/uuids-are-popular-but-bad-for-performance-lets-discuss/

maybe that doesn't matter given local first apps likely won't have datasets large enough for this to become an issue.

Given all the unknowns with sid and the probably small perf hit with nanoid -- we should go with nanoid for now.

Enable more complex types in fields

Fields can be:

  • primitives
  • ids
  • arrays
  • maps

Lets add:

  • sets

Explore adding:

  • other model instances

Explore:

  • thrift, protobuff & json-serializable things

read after optimistic write & optimistic reactivity

If a user strictly performs optimistic writes (without awaiting for the write to complete) they can issue a read that doesn't return what they expect.

The current design requires hitting the database to fulfill any query. So issuing a write that you don't await can result in a later query not returning the data in that write.

We can:

  1. Update our query layer to understand if there are pending writes. If so, await them before returning the read.
    ^-- I think this might already be the case accidentally when using wa-sqlite-connector as all those operations are serialized

When we make changes for #46 we'll have to consider how it impacts this task.

Reactive queries do not update optimistically. This might not be a big deal but could lead to strange behavior where a component lags behind another. When tackling #49 we can address parts of this problem. E.g., by making single hop reactive queries resolve themselves in-memory.

Allow printing of query plans

So users can understand if all clauses are optimized or not.

Log a warning when a non-optimized query is run against a dataset of >1k rows.

Queries that reference other fields (whereExists, whereRaw)

I know it's early on, but I'm just tinkering with this. One thing I'd like to express in a query is a predicate which is related to another field on a model.

Example use case: a grocery list app which lets you change the quantity of items. Suppose you've already purchased 6 eggs, but you increase the desired quantity to 12. In order to express a query for "purchased items," I want to query all items where item.purchasedQuantity >= item.desiredQuantity.

The scope here would only be predicates relevant to other fields on the same model, not traversing edges or anything like that.

Smarter Reactive Queries

Currently we just re-run a query whenever one of its queried tables is updated.

This is good enough for now (based on current perf numbers and being in beta) but in the future if we need row-level reactivity some ideas are:

For single hop queries, we can run expressions in-memory against the modified/created/deleted node.

For multi-hop we of course lose the ids of the nodes we joined on. We have a few options:

  1. ๐Ÿ‘Ž Require materialized views so all queries are single hop
    1. Horrible devx
    2. Horrible to maintain
    3. We could automate this if all queries are statically known ala Relay.
  2. ๐Ÿ‘Ž In the background, fetch ids of hops.
  3. what if there are thousands or millions of these for a given hop?
  4. ๐Ÿ‘ Model the query path as a graph.
    1. We know:
      1. Start node
      2. End node(s)
      3. Some updated node inside the path (the target of the mutation)
    2. We can use that to run simpler queries across subsections of the path to understand if the mutation target is part of the original query

IndexedDB support?

While pure sqlite is great it is quite a bit of bloat to bring into the browser.

Is it worth supporting indexeddb directly?

Some reasons to do it:

  • faster first time load
  • less complex application setup (no sql files to generate, simpler table creation process, simpler db startup)

Not to:

  • Entirely new SourceExpression type to support
  • Entirely new query plan optimizer to write
  • CRDT layer would need to be re-implemented for IndexedDB

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.