164 lines
4.2 KiB
Markdown
164 lines
4.2 KiB
Markdown
|
|
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**:
|
|||
|
|
|
|||
|
|
```js
|
|||
|
|
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:
|
|||
|
|
|
|||
|
|
```js
|
|||
|
|
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
|
|||
|
|
|
|||
|
|
```js
|
|||
|
|
async click() {
|
|||
|
|
const form = this.parents('userEdit');
|
|||
|
|
await form.save(); // automatically writes username & email
|
|||
|
|
form.hide();
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
And for loading:
|
|||
|
|
|
|||
|
|
```js
|
|||
|
|
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 table’s 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
|
|||
|
|
|
|||
|
|
```js
|
|||
|
|
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.
|