Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Redesign #48

Open
petterik opened this issue Dec 4, 2018 · 5 comments
Open

Redesign #48

petterik opened this issue Dec 4, 2018 · 5 comments

Comments

@petterik
Copy link
Owner

petterik commented Dec 4, 2018

Notes from textedit post clojure conj 2018 post hammock.

Has data requirements:

View

Cares about:

  • Fields to render.
  • Whether it's queryable or not.
    • Meaning: The way I'm querying this data, can I get it?
      • We can possibly check whether the query definition is possible against GraphQL API.

Does not (necessarily) care about:

  • Types of the fields
  • Parameters of where to get the fields
    • Routes or other paths in the app state structure.

Read

  • The definition of local reads can affect what's needed by the remote reads.

Local:

  • By specifying what's unique or what's required to satisfy a read, we can possibly declare a datamodel for reads, to avoid having to write reads.
  • Somehow, the specifications of the read need to be returned when asked for how to query it remotely.

Mutate

Local:

  • To perform an optimistic mutation:
    [RouteParams Env MutateParams] -> ?

Remote:

  • To perform a remote mutation, we don't really want to add params.
  • There is context involved with a mutation that should be inserted in to the
    remote query, such as RouteInfo (route and route-params), but otherwise
    the remote mutation should contain it all?
  • Is there anything that should be retrieved from these sources?
    • App state
    • URL
    • Local storage

Merge

Cares about:

  • Structured with a query:
    • ID's, how is this entity unique?
      • Single field
      • Multiple field
      • Singleton (enum/there's only one).
      • Component of cardinality 1, thus replace each time.
      • Component of cardinality many, collection cannot be normalized further.
  • DB transactions

Remote Query

Remote query is a merge of:

  • ViewQuery
    • (get-query RootView)
  • RemoteReadQuery
    • (remote-query ViewQuery)
  • MergeQuery
    • (ID specification of all queries).
    • Possibly from GraphQL API schema.
  • ContextParams
    • RouteInfo, and anything else specifying the current state of the client.

After merge, extract .

  • Such as GraphQL, EQL or REST(?)

Mechanical:

Local Query

  • ? Why did I write this section ?

Questions:

  • How are queries merged?

    • Do we merge queries by query root paths?
      • What about "_back-links", like in datomic.
        • Is that represented somehow in GraphQL?
  • Local Reads and Merge both care about ID specification

    • Can we do with:
      • View Query definitions
      • Query ID specifications
      • Read Query dependencies
        • Filters such as:
          • route data
          • "where clauses"?
      • Wait, Can we define RootQueries in hodur with meta data. See lacinia plugin.
        • Need to define examples of this.
        • The RootQueries defined in hodur can then also be merged with ViewQuery definitions
          • What does this mean ^. Is this awesome?
  • There's something about the property "full-name" that should be possible to do locally when there's a "first-name" and "last-name" in the GraphQL.

    • Implementing "pull" ourselves against DataScript given a query is probably a good thing. Using pathom for this is probably even better.
      • So, if someone has a query [Employees [full-name]]:
        • Remote query: [Employees [ID first-name last-name]]
          • Because full-name should expand to [first-name last-name].
          • Because ID is added to make them unique.
        • Local query resolution:
          1. 'Employees -> [Employee]
          2. (pull [full-name] [Employees])
          3. Pulling full-name will call a full-name resolver, which does (str first-name " " last-name).
        • Do we care? Maybe this resolution is up to GraphQL instead?
  • Regarding reverse lookup, that's a backend concern, and that's fine (it seems).

TODO:

  • Try to write an example app?
    • Wishful thinking.

What is the system? (model, state, logic)

Model

  • Domain Model

  • Root Queries

  • View Queries

    • Subscription Queries (special case of static queries).
  • Normal Model

    • Uniqueness/identity part of the domain model.
  • View data, such as:

    • Routes
    • Independent view children
    • Dependent view children (children who compose inside of the query)
    • Query
    • Subscriptions

Accumulated over time

  • RemoteLog
  • Layers
    • It's own thing.
      • Snapshotting a db from the layers could (in prod) remove remote layer data.

Logic:

  • Read(view-query, root-queries, app-state) -> render-data
  • Send(view-query, root-queries) -> remote-query
  • Merge(remote-response, remote-query, normalization-model, app-state) -> app-state
  • Reconcile(system) -> system
    • This part is purposely ambiguous.

State:

  • Route
  • LocalStorage
  • .. ?

TODO:

  • Given this definition of a system, I think we can redesign lajter. From the ground up? Maybe.
  • The parser concept might go away, not sure.
  • Definitely want to enable one to opt out of the Model definitions to configure everything.
@petterik
Copy link
Owner Author

petterik commented Dec 5, 2018

Is there some property between Domain Model, Normal Model (for reads) and View Queries?

  • Feels like, given a Domain Model, one should be able to:
    • generate data
    • generate reads (given their identities (normal model))
    • generate view queries (given reads and random pull patterns of domain model)
    • send generated queries
    • respond to the queries given the generated reads
    • merge response (normalized)
    • perform "render" (provide data to views via reads)
    • verify that views have all the data?
      • by verifying that pull patterns are satisfied by the props.

This requires that we can

  • Create generators from hodur datascript
    • generating domain data
    • generating view queries (as they are also hodur data).
  • Create hodur/schema from hodur/datascript
    • (If we want to create views with queries like what a user would create).
      • which we may not care about?
  • Create reads of a "root type" by getting all entities by their ids.
    • more suggestions?
  • Merge queries (to create send query).
  • Merge response given a query and it's normal model.

Doing this, we have a property based test making sure our views' data requirements are met.

After this we need to add Layers, Routing & Reconciliation. Querying remote log should fall out from work on Layers. We can steal all of these parts from the current work on lajter.

We also need React stuff. I wonder what the best way to do that is. lajter.react is gross.

@petterik
Copy link
Owner Author

petterik commented Dec 5, 2018

To be more specific regarding the models:

Model

  • Domain Model
    • Contains the types, required fields and other meta about the entities.
  • Root Queries
    • Specifies the root query definitions, such as:
      • query name
      • params
      • ?
  • View Queries
    • Consists of a root query and a "pull pattern" based on the domain model.
  • Subscription Queries
    • Defined the same way as a view query, but has different semantics (live updates).
  • Normal Model
    • Adds uniqueness/identity to Domain Model entities, where it doesn't already exist.

@petterik
Copy link
Owner Author

petterik commented Dec 12, 2018

Regarding normal model:

  • Component entities can be merged based on their parents.
    • When specifying a model, everything but the root nodes are components.
  • When merging data, having a priority strategy could make sense:
    • Merge by: ID first, then parent, multiple keys(?), with into if ^:many, lastly replace.

Just realized I have no idea how to model deletions with GraphQL. Something I'll have to figure out.

@petterik
Copy link
Owner Author

Thought about root queries.

  • Some root queries can probably be "get me all the things that have either (or all) of the fields at the first level of the pull pattern".

@petterik
Copy link
Owner Author

petterik commented Dec 12, 2018

Just realized I have no idea how to model deletions with GraphQL. Something I'll have to figure out.

^ Hahaha. I just googled this and was I in for a surprise. There's no story for this, so uhm just, figure it out?

It was nice to be able to just send deletions/retractions. I wonder if we can get this back with the Normal Model. Somehow describing to the backend that "I accept deletions in this way."

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant