Bỏ qua, đến nội dung

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ínhMô tả
expressionChuỗi biểu thức công thức
engineTên engine: mathjs hoặc formula (excel-like)
dataTypeKiể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:

EngineModuleMô tả
mathjsmathjs libraryBiểu thức toán học: +, -, *, /, ^, sqrt, abs...
formulaExcel-like parserHà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ý:

  1. Parse expression thành AST.
  2. Thay thế tên field bằng giá trị từ scope.
  3. 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:

dataTypeColumn type DBVí dụ
doubleDOUBLE PRECISION1500.50
integerINTEGER42
bigIntBIGINT9999999999
stringVARCHAR"Nguyễn Văn A"
dateDATE2024-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 DB

Hook 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ả formula

fields.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ánKý hiệu
Cộng, trừ, nhân, chia+, -, *, /
Lũy thừa^
Modulo%
Hàmsqrt(), abs(), round(), ceil(), floor()

Các hàm (excel-like)

HàmMô 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) │
                                    └──────────────┘