aspen-cloud / triplit

A full-stack, syncing database that runs on both server and client. Pluggable storage (indexeddb, sqlite, durable objects), syncs over websockets, and works with your favorite framework (React, Solid, Vue, Svelte).
https://triplit.dev
GNU Affero General Public License v3.0
2.33k stars 71 forks source link

Simplify Queries by passing client / Query #187

Open sgup opened 3 months ago

sgup commented 3 months ago

In a query like this:

useQuery(
  triplit,
  triplit
    .query('directors')
    .include('allFilms', (rel) => rel('allFilms').include('actors').build())
);

In the ClientQueryBuilder class, why not expose the current Q Query and a reference to the client, so it could be simplified further to:

useQuery(
  triplit
    .query('directors')
    .include('allFilms', (rel) => rel('allFilms').include('actors'))
    // no build() or client ref required as it can be accessed from class
);

& since useQuery is a react-specific hook, and thus made specifically to provide an easier/better interface over triplit, it would make sense to go further react-y and use the context/provider pattern:

import { TriplitProvider } from '@triplit/react'

function App() {
  <TriplitProvider client={triplitClient}>
    <div>
      <h1>My Triplit App</h1>
    </div>
  </TriplitProvider>
}

& in the components:

useQuery(
  "directors",
  (q) => q.include("allFilms", (rel) => rel("allFilms").include("actors"))
  // triplit client is provided by the TriplitProvider
);

Final Diff:

useQuery(
  triplit,
  triplit
    .query('directors')
    .include('allFilms', (rel) => rel('allFilms').include('actors').build())
);

// vs 

useQuery(
  "directors",
  (q) => q.include("allFilms", (rel) => rel("allFilms").include("actors"))
);
matlin commented 3 months ago

I like your idea! Especially the query builder callback ((q) => q.include(allFilms"....) Have you tried implementing this in "userland"? Seemingly only thing that would need to change is the @triplit/react package.

MentalGear commented 3 months ago

// no build() or client ref required as it can be accessed from class

Yeah, I'd also like to see this simplified syntax across all frameworks (svelte, etc) that use useQuery!

MentalGear commented 1 month ago

@sgup Maybe you could add a PR to add the abridged syntax version to the core ?

itoxiq commented 1 week ago

Also think this looks way more useable. The only annoying part here is, that you have to bind the client somehow to useQuery. I made a example implementation for the vue package here

import { TriplitClient, Schema as S, ClientSchema } from '@triplit/client';
import { useTriplit } from '@triplit/vue';

const schema = {
  todos: {
    schema: S.Schema({
      id: S.Id(),
      text: S.String(),
      complete: S.Boolean(),
    }),
  },
} satisfies ClientSchema;

const client = new TriplitClient({
  serverUrl: YOUR_SERVER_URL,
  token: YOUR_TOKEN,
  schema
});

const { useQuery } = useTriplit(client);

const { fetching, results, error, updateQuery } = useQuery(
  'todos',
  (q) => q.where('complete', '!=', false)
);

But you can still use useQuery directly where you have to pass in the client for every function call. Let me know what you think :)