src/users/users.oxl
use super.model.*
use std.orm { Db }
// Таблица ORM: схема и миграции выводятся из этого объявления
@table("users") @index(.email)
pub(api) data User {
@pk pub(api) id: UserId // первичный ключ
pub(api) name: Name
pub(api) email: Email
pub(api) createdAt: Time = now() // значение по умолчанию вычисляется при создании
}
// Контракт сервиса: из него генерируются сервер, клиенты и .proto
@v(1) pub(api) service Users {
@readonly rpc get(id: UserId) -> User | NotFound // readonly: безопасно повторять и кэшировать
@idempotent rpc register(name: Name, email: Email) -> User | EmailTaken // повтор с тем же ключом вернёт первый ответ
}
impl Users {
dep db: Db // зависимость, её даёт provide в cluster.oxl
// Типы параметров берутся из контракта сервиса
rpc get(id) { db.find(User, id) ?? fail NotFound{ what: "user", id: id.raw } }
rpc register(name, email) {
// Запрос компилируется в SQL при сборке
let taken = from u in db.User where u.email == email take 1
if !taken.isEmpty() { fail EmailTaken{} }
let u = User{ id: UserId(cluster.ids.next() as u64), name, email } // уникальный id
db.insert(u)
u
}
}
// Доступ для внешних вызовов: по умолчанию всё запрещено.
// На этапе 3 политики разбираются, но не применяются (STAGE3_PLAN, решение 1).
policy Users {
allow get(id) if caller.isUser("{id}") || caller.has(role: .Support) // свой профиль или поддержка
allow register if caller is .Anonymous // регистрация — без входа
}Исходник: examples/shop/src/users/users.oxl