Files
Unify/Tables.md
2025-12-25 11:16:59 +01:00

4.2 KiB
Raw Blame History

Here is a fully rewritten version of the entire Tables + Columns + Floating Mapping section — accurate, simplified, and without over-emphasizing the “floating” term, while still explaining why it matters.


Tables & Columns

Automatic SQL Mapping from UI Components

In Unify, your UI defines your data model.

Every data entity in an application is a table object:

import table from '/unify/table.js';

export default class user extends table {

    username = new username();   // column
    email    = new email();      // column
    groups   = new groups();     // relation
}

Any child object that extends column is automatically treated as a database column belonging to its nearest table ancestor.

There is no need to write schemas, migrations, or model config files. Unify inspects the structure at runtime and understands:

  • Table name → class name (user)
  • Column names → field names (username, email, …)
  • Relationships → nested collections
  • Permissions → defined on the table

No duplication. No ORM setup. Your UI code is your data model.


Columns Can Live Anywhere in the UI Tree

Columns do not need to be direct children of the table.

You can design your UI freely:

export default class userEditPanel extends panel {
    accountPanel     = new accountPanel();
    contactPanel     = new contactPanel();
}

class accountPanel extends panel {
    username = new username();   // column
}

class contactPanel extends panel {
    email = new email();         // column
}

Unify automatically discovers these fields because they appear under a table instance in the object tree.

So you are free to:

  • Split a screen into panels
  • Reuse complex component hierarchies
  • Move UI structure without refactoring SQL code

This enables UI-first design without breaking the data layer.


CRUD Without CRUD Code

Unify provides two primary data operations:

Action Developer code Result
Save await user.save() INSERT or UPDATE depending on id
Load await user.sync() SELECT + populate all child columns

Example: Editing a profile

async click() {
    const form = this.parents('userEdit');
    await form.save();    // automatically writes username & email
    form.hide();
}

And for loading:

user.id = 42;
await user.sync(); // loads username/email into the UI automatically

No setters. No binding boilerplate. No DTOs. No form libraries.

The table object is both:

  • Data source
  • UI container
  • Binding layer

Why This Matters

Traditional Full-Stack With Unify
Write database schema Skip — inferred
Write backend model Skip — inferred
Write API controllers Skip — RPC auto-generation
Write validation logic Built into column objects
Build UI → manually connect UI is the data model
Keep everything in sync .sync() + .save()

This eliminates the friction between backend + frontend and replaces it with one unified codebase.


Minimal Mental Model

A table object represents a database row. Any column object inside that tables UI subtree automatically becomes a database column. sync() loads data into the UI. save() writes UI data back to SQL.

Nothing more is needed to build and ship real applications.


Example Recap

user.id = 7;
await user.sync();   // load existing row → UI updates

user.username.value = "kaj";
await user.save();   // update DB row with new values

One line to fetch, one line to commit.


If you'd like, the next chapter can flow directly into Render Collections & Lists, since they demonstrate the same philosophy at scale:

  • UI defines queries (pagination, filtering)
  • Changes propagate automatically across the app

Should I continue with:

A) Render Collections + Filtering/Searching B) Permissions (groups, scopes, READ/WRITE/DELETE) C) Routing + Animated Page State D) Server RPC Communication Model (socket commands)

Just tell me which one comes next.