Giao diện
Tham chiếu kỹ thuật
FormulaField và calculate()
FormulaField là field type đăng ký vào database ORM, với method chính:
FormulaField.calculate(record)
→ Lấy expression từ field options
→ Trích giá trị các field tham chiếu trong record
→ Gọi evaluator engine tương ứng
→ Trả về kết quả đã tính| Thuộc tính | Mô tả |
|---|---|
expression | Chuỗi biểu thức công thức |
engine | Tên engine: mathjs hoặc formula (excel-like) |
dataType | Kiểu dữ liệu cột DB cho kết quả |
Evaluator Engine — @digiforce-nc/evaluators
Package @digiforce-nc/evaluators cung cấp các engine tính toán:
| Engine | Module | Mô tả |
|---|---|---|
mathjs | mathjs library | Biểu thức toán học: +, -, *, /, ^, sqrt, abs... |
formula | Excel-like parser | Hàm dạng Excel: IF, SUM, CONCAT, ROUND, MAX, MIN... |
Cách gọi evaluator
evaluate(engine, expression, scope)
- engine: tên engine
- expression: chuỗi biểu thức
- scope: object chứa giá trị các field { price: 100, quantity: 5 }Evaluator xử lý:
- Parse expression thành AST.
- Thay thế tên field bằng giá trị từ scope.
- Tính toán và trả về kết quả.
Typed Column từ dataType
Khi tạo field formula, hệ thống tạo cột DB theo dataType:
| dataType | Column type DB | Ví dụ |
|---|---|---|
double | DOUBLE PRECISION | 1500.50 |
integer | INTEGER | 42 |
bigInt | BIGINT | 9999999999 |
string | VARCHAR | "Nguyễn Văn A" |
date | DATE | 2024-01-15 |
Nếu kết quả tính toán không khớp kiểu dữ liệu cột, sẽ bị ép kiểu (cast) hoặc báo lỗi.
Server Hooks
afterSave — Tính khi lưu bản ghi
Bản ghi được create/update
→ afterSave hook trigger
→ Tìm tất cả formula fields trong collection
→ Với mỗi formula field: calculate(record)
→ Cập nhật giá trị formula vào DBHook chạy sau khi bản ghi đã được lưu, đảm bảo tất cả field đã có giá trị mới nhất trước khi tính.
bulkCreate — Tính khi tạo hàng loạt
bulkCreate([record1, record2, ...])
→ Lưu tất cả bản ghi vào DB
→ Với mỗi bản ghi: calculate(record)
→ Batch update kết quả formulafields.afterUpdate — Recompute khi sửa công thức
Admin sửa formula expression hoặc engine
→ fields.afterUpdate hook trigger
→ Lấy tất cả bản ghi trong collection
→ Với mỗi bản ghi: calculate(record) với expression mới
→ Batch update toàn bộĐây là thao tác nặng nhất — cần lưu ý với collection lớn.
Expression Syntax
Tham chiếu field
Dùng tên field trực tiếp trong expression:
price * quantity → tham chiếu field "price" và "quantity"
IF(status == "paid", 1, 0) → tham chiếu field "status"Các phép toán (mathjs)
| Phép toán | Ký hiệu |
|---|---|
| Cộng, trừ, nhân, chia | +, -, *, / |
| Lũy thừa | ^ |
| Modulo | % |
| Hàm | sqrt(), abs(), round(), ceil(), floor() |
Các hàm (excel-like)
| Hàm | Mô tả |
|---|---|
IF(condition, trueVal, falseVal) | Điều kiện |
SUM(a, b, c) | Tổng |
CONCAT(a, b) | Nối chuỗi |
ROUND(num, digits) | Làm tròn |
MAX(a, b) / MIN(a, b) | Lớn nhất / nhỏ nhất |
Sơ đồ kiến trúc tổng quan
┌──────────────┐ expression ┌──────────────┐ result ┌──────────┐
│ Expression │ ─────────────────→ │ FormulaField │ ────────────→ │ Database │
│ Editor (UI) │ │ calculate() │ │ (typed) │
└──────────────┘ └──────┬───────┘ └──────────┘
│
┌──────┴───────┐
│ Evaluator │
│ (mathjs/ │
│ excel-like) │
└──────────────┘