orm: update readme with more specifics (#21697)

This commit is contained in:
Skylear 2024-06-18 22:53:21 -05:00 committed by GitHub
parent 72a3fd6f02
commit aaa23bb058
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -1,32 +1,45 @@
# ORM
## Null
V has a powerful, concise ORM baked in! Create tables, insert records, manage relationships, all
regardless of the DB driver you decide to use.
Use option fields in V structs for fields which can be NULL. Regular,
non-option fields are defied as NOT NULL when creating tables.
## Nullable
For a nullable column, use an option field. If the field is non-option, the column will be defined
with `NOT NULL` at table creation.
```v ignore
struct Foo {
notnull string
nullable ?string
}
```
## Attributes
### Structs
- `[table: 'name']` sets a custom table name
- `[table: 'name']` explicitly sets the name of the table for the struct
### Fields
- `[primary]` sets the field as the primary key
- `[unique]` sets the field as unique
- `[unique: 'foo']` adds the field to a unique group
- `[unique]` gives the field a `UNIQUE` constraint
- `[unique: 'foo']` adds the field to a `UNIQUE` group
- `[skip]` or `[sql: '-']` field will be skipped
- `[sql: type]` where `type` is a V type such as `int` or `f64`
- `[sql: serial]` lets the DB backend choose a column type for a auto-increment field
- `[sql: serial]` lets the DB backend choose a column type for an auto-increment field
- `[sql: 'name']` sets a custom column name for the field
- `[sql_type: 'SQL TYPE']` sets the sql type which is used in sql
- `[default: 'raw_sql]` inserts `raw_sql` verbatim in a "DEFAULT" clause when
create a new table, allowing for values like `CURRENT_TIME`
- `[sql_type: 'SQL TYPE']` explicitly sets the type in SQL
- `[default: 'raw_sql']` inserts `raw_sql` verbatim in a "DEFAULT" clause when
creating a new table, allowing for SQL functions like `CURRENT_TIME`. For raw strings,
surround `raw_sql` with backticks (`).
- `[fkey: 'parent_id']` sets foreign key for an field which holds an array
## Usage
Here are a couple example structs showing most of the features outlined above.
```v ignore
import time
@ -47,23 +60,55 @@ struct Child {
}
```
### Create
To use the ORM, there is a special interface that lets you use the structs and V itself in queries.
This interface takes the database instance as an argument.
```v ignore
import db.sqlite
db := sqlite.connect(':memory:')!
sql db {
create table Foo
// query; see below
}!
```
### Drop
When you need to reference the table, simply pass the struct itself.
```v ignore
import models.Foo
struct Bar {
id int @[primary; sql: serial]
}
sql db {
drop table Foo
create table models.Foo
create table Bar
}!
```
### Insert
### Create & Drop Tables
You can create and drop tables by passing the struct to `create table` and `drop table`.
```v ignore
import models.Foo
struct Bar {
id int @[primary; sql: serial]
}
sql db {
create table models.Foo
drop table Bar
}!
```
### Insert Records
To insert a record, create a struct and pass the variable to the query. Again, reference the struct
as the table.
```v ignore
foo := Foo{
@ -86,19 +131,48 @@ foo_id := sql db {
}!
```
If the `id` field is marked as `serial` and `primary`, the insert expression
If the `id` field is marked as `sql: serial` and `primary`, the insert expression
returns the database ID of the newly added object. Getting an ID of a newly
added DB row is often useful.
When inserting, `[sql: serial]` fields, and fields with a `[default: 'raw_sql']`
attribute are not sent to the database when the value being sent is the default
attribute, are not sent to the database when the value being sent is the default
for the V struct field (e.g., 0 int, or an empty string). This allows the
database to insert default values for auto-increment fields and where you have
specified a default.
### Select
You can select rows from the database by passing the struct as the table, and
use V syntax and functions for expressions. Selecting returns an array of the
results.
```v ignore
result := sql db {
select from Foo where id == 1
}!
foo := result.first()
```
```v ignore
result := sql db {
select from Foo where id > 1 && name != 'lasanha' limit 5
}!
```
```v ignore
result := sql db {
select from Foo where id > 1 order by id
}!
```
### Update
You can update fields in a row using V syntax and functions. Again, pass the struct
as the table.
```v ignore
sql db {
update Foo set updated_at = time.now() where name == 'abc' && updated_at is none
@ -108,30 +182,25 @@ sql db {
Note that `is none` and `!is none` can be used to select for NULL fields.
### Delete
You can delete rows using V syntax and functions. Again, pass the struct
as the table.
```v ignore
sql db {
delete from Foo where id > 10
}!
```
### Select
```v ignore
result := sql db {
select from Foo where id == 1
}!
```
```v ignore
result := sql db {
select from Foo where id > 1 && name != 'lasanha' limit 5
}!
```
```v ignore
result := sql db {
select from Foo where id > 1 order by id
}!
```
### time.Time Fields
It's definitely useful to cast a field as `time.Time` so you can use V's built-in time functions;
however, this is handled a bit differently than expected in the ORM. `time.Time` fields are
created as integer columns in the database. Because of this, the usual time functions
(`current_timestamp`, `NOW()`, etc) in SQL do not work as defaults.
## Example
### Example
```v ignore
import db.pg