Table.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. package DB
  2. import (
  3. "TsDB2/DB/core"
  4. "TsDB2/DB/core/types"
  5. "encoding/binary"
  6. "fmt"
  7. "time"
  8. )
  9. // Table 泛型表封装。
  10. //
  11. // T 必须内嵌 DB.BaseModel / DB.PrimaryModel / DB.TimeSeriesModel —— 由 UseTable 在
  12. // 建表之前强制校验 (见 types.go 的 requireBase), 所以拿到一个 *Table[T] 就意味着
  13. // T 一定有对象头部的增删改查。
  14. type Table[T any] struct {
  15. coreTable *core.Table
  16. model *ModelInfo
  17. name string // 表名
  18. activeColumns map[string]bool // 当前 DB schema 活跃列集合
  19. }
  20. // refreshActiveColumns 从 core table 刷新活跃列集合
  21. func (t *Table[T]) refreshActiveColumns() {
  22. t.activeColumns = make(map[string]bool)
  23. for _, name := range t.coreTable.GetActiveFieldNames() {
  24. t.activeColumns[name] = true
  25. }
  26. }
  27. // SchemaColumns 返回当前 DB 中的所有活跃列名
  28. func (t *Table[T]) SchemaColumns() []string {
  29. names := make([]string, 0, len(t.activeColumns))
  30. for name := range t.activeColumns {
  31. names = append(names, name)
  32. }
  33. return names
  34. }
  35. // Insert 插入一条记录
  36. //
  37. // 顺带把对象绑定到本表, 这样即使对象是外部构造的, 插完之后也能直接用头部的
  38. // Update / Delete / Reload (见 model.go); 同时把引擎分配的行号带回对象, 之后
  39. // obj.Update() / obj.Delete() 才能精确到"这一行"。
  40. func (t *Table[T]) Insert(obj *T) error {
  41. t.bindModel(obj)
  42. // 主键显式给了就用它; 没给 (==0) 就向引擎要一个自增号。
  43. // 旧实现无条件用 TotalRows+1 覆盖: 一是调用方填的 _id 被改写 → "按 _id 插入的行
  44. // 按 _id 查不到"; 二是删除会让行数回退 → 号回退并撞上仍存活的 pkID (探针 T4)。
  45. // 现在号一律来自 core 的只增不减游标, 拿到号后再序列化, 保证主键列与 pkID 一致。
  46. // 主键字段可以是内嵌 BaseModel 的 ID, 也可以是用户用 vrtx:"pk" 指定的普通字段。
  47. //
  48. // 时序表是唯一的例外, 见下面 IsTimeSeries 分支。
  49. pkID := uint64(0)
  50. if t.model.IsTimeSeries {
  51. // 时间键不是行号, 两者必须分开: 同一个时间戳下允许有多行 (同一时刻的多个
  52. // 测点 / 多次事件), 这是时序数据的常态。若沿用"时间键即行号", 第二行会被
  53. // 当成重复主键拒掉 —— 数据直接丢, 而这正是引入行号要解决的问题。
  54. // 所以时序表永远向引擎要一个新行号, 时间键保持用户给的原值, 只当索引键用。
  55. pkID = t.coreTable.AllocPKID()
  56. if t.model.PKInStruct {
  57. ts, err := getPKValue(obj, t.model)
  58. if err != nil {
  59. return fmt.Errorf("tsdb: insert: %w", err)
  60. }
  61. if ts == 0 {
  62. // 完全没给时间键: 补一个"写入这一刻"的纳秒级时间戳。
  63. //
  64. // 时序键就是时间戳本身, 默认值必须与显式传入的时间戳同量纲 (纳秒),
  65. // 否则它会成为一个远小于真实时间戳的怪值, 顺序写入下立刻被判为乱序。
  66. // 同一纳秒内连插多行的 TS 会相同, 这是允许的 —— 同刻多行由行号区分。
  67. setPKValue(obj, t.model, uint64(time.Now().UnixNano()))
  68. }
  69. }
  70. } else if t.model.PKInStruct {
  71. var err error
  72. if pkID, err = getPKValue(obj, t.model); err != nil {
  73. return fmt.Errorf("tsdb: insert: %w", err)
  74. }
  75. if pkID == 0 {
  76. pkID = t.coreTable.AllocPKID()
  77. setPKValue(obj, t.model, pkID)
  78. }
  79. }
  80. fvs, err := structToFieldValues(obj, t.model, t.activeColumns)
  81. if err != nil {
  82. return fmt.Errorf("tsdb: insert: %w", err)
  83. }
  84. // pkID == 0 (结构体没有主键字段) 时由 core 自行分配
  85. assigned, err := t.coreTable.InsertRowWithID(pkID, fvs)
  86. if err != nil {
  87. return fmt.Errorf("tsdb: insert: %w", err)
  88. }
  89. setRowIDOf(obj, assigned)
  90. return nil
  91. }
  92. // BatchInsert 批量插入
  93. func (t *Table[T]) BatchInsert(objs []*T) error {
  94. for _, obj := range objs {
  95. if err := t.Insert(obj); err != nil {
  96. return err
  97. }
  98. }
  99. return nil
  100. }
  101. // Update 更新一条记录
  102. //
  103. // 优先按对象携带的引擎行号定位 (从表里读出来或插入过的对象都有), 这样同一时间戳
  104. // 下有多行时改的确实是"自己那一行"; 行号未知时退回按主键列定位 (旧行为)。
  105. func (t *Table[T]) Update(obj *T) error {
  106. t.bindModel(obj)
  107. fvs, err := structToFieldValues(obj, t.model, t.activeColumns)
  108. if err != nil {
  109. return fmt.Errorf("tsdb: update: %w", err)
  110. }
  111. if id := rowIDOf(obj); id != 0 {
  112. return t.coreTable.UpdateRowByPK(id, fvs)
  113. }
  114. pk, err := getPKValue(obj, t.model)
  115. if err != nil {
  116. return fmt.Errorf("tsdb: update: %w", err)
  117. }
  118. if pk == 0 {
  119. return fmt.Errorf("tsdb: update: primary key is 0")
  120. }
  121. return t.coreTable.UpdateRow(t.pkIndexName(), encodePKKey(pk), fvs)
  122. }
  123. // Delete 按主键删除一条记录
  124. func (t *Table[T]) Delete(id uint64) error {
  125. return t.coreTable.DeleteRow(t.pkIndexName(), encodePKKey(id))
  126. }
  127. // Find 按主键查找一条记录
  128. func (t *Table[T]) Find(id uint64) (*T, error) {
  129. // SearchByIndexWithPK 与 SearchByIndex 取的是同一行 (同一条索引键 → 同一次定位),
  130. // 只是额外把行的引擎行号带回来 —— 没有它就没法对同刻多行做精确的改 / 删。
  131. pkID, row, err := t.coreTable.SearchByIndexWithPK(t.pkIndexName(), encodePKKey(id))
  132. if err != nil {
  133. return nil, err
  134. }
  135. obj := new(T)
  136. if err := fieldValuesToStruct(row, t.model, obj); err != nil {
  137. return nil, err
  138. }
  139. setRowIDOf(obj, pkID)
  140. t.bindModel(obj)
  141. return obj, nil
  142. }
  143. // FindAll 返回所有记录
  144. func (t *Table[T]) FindAll() ([]*T, error) {
  145. return t.Query().Find()
  146. }
  147. // Count 返回总行数
  148. func (t *Table[T]) Count() (int64, error) {
  149. return t.coreTable.Query().Count()
  150. }
  151. // Select 流式遍历所有记录
  152. func (t *Table[T]) Select(callback func(*T) bool) error {
  153. return t.coreTable.Query().ScanWithPKID(func(pkID uint64, row []types.FieldValue) bool {
  154. obj := new(T)
  155. if err := fieldValuesToStruct(row, t.model, obj); err != nil {
  156. return true
  157. }
  158. // 行号随手带回对象: 回调里拿到的对象可以直接 Update / Delete, 精确到自己那一行。
  159. setRowIDOf(obj, pkID)
  160. t.bindModel(obj)
  161. return callback(obj)
  162. })
  163. }
  164. // Where 开始条件查询
  165. func (t *Table[T]) Where(field string, op string, value interface{}) *Query[T] {
  166. q := &Query[T]{table: t}
  167. q.addWhere(field, op, value)
  168. return q
  169. }
  170. // OrderBy 排序
  171. func (t *Table[T]) OrderBy(field string, desc ...bool) *Query[T] {
  172. q := &Query[T]{table: t}
  173. q.OrderBy(field, desc...)
  174. return q
  175. }
  176. // Limit 限制返回行数
  177. func (t *Table[T]) Limit(n int) *Query[T] {
  178. q := &Query[T]{table: t}
  179. q.Limit(n)
  180. return q
  181. }
  182. // Offset 跳过行数
  183. func (t *Table[T]) Offset(n int) *Query[T] {
  184. q := &Query[T]{table: t}
  185. q.Offset(n)
  186. return q
  187. }
  188. // Query 创建一个新的查询构建器
  189. func (t *Table[T]) Query() *Query[T] {
  190. return &Query[T]{table: t}
  191. }
  192. func (t *Table[T]) pkIndexName() string {
  193. return pkIndexPrefix + t.name
  194. }
  195. // ===== 模型绑定: 头部增删改查的入口 =====
  196. // Bind 把对象绑定到本表 —— 绑定之后才能用对象头部的 Insert / Update / Delete /
  197. // Save / Load / Reload。Insert / Update / Find / FindAll / Select / 条件查询的返回值
  198. // 都会自动绑定, 所以只有"外部手工构造、且第一件事就是 Update/Delete/Reload"的对象
  199. // 需要显式绑一次 (那种情况下用 New 更省事)。
  200. //
  201. // 注意: 绑定信息 (属于哪张表、外层对象是谁) 存在对象内部, 因此
  202. //
  203. // u2 := *u // 拷贝一个已绑定的对象
  204. // u2.Update() // 更新的是 u, 不是 u2
  205. //
  206. // 会更新原对象。需要一份独立的对象请用 Table.New + Load, 或 Table.Find。
  207. func (t *Table[T]) Bind(obj *T) error {
  208. if !t.bindModel(obj) {
  209. // UseTable 已经把没有基类的 T 挡在门外, 走到这里只可能是 T 的绑定器被特殊的
  210. // 嵌入方式挡住了 (例如把基类嵌在一个指针结构体里)。给同样的错误, 别让它静默失效。
  211. return fmt.Errorf("tsdb: %w: %T 需要内嵌 DB.BaseModel / DB.PrimaryModel / "+
  212. "DB.TimeSeriesModel 才能使用头部方法", ErrNotModel, obj)
  213. }
  214. return nil
  215. }
  216. // New 创建一个已经绑定到本表的新对象, 随后可以直接 obj.Load(pk) 读入。
  217. //
  218. // 与"手写 &T{} 再 Bind"的区别: 后者要先拿到 T 的类型; 在泛型代码里 (不知道 T 的具体
  219. // 类型时) 只有 Table 能造出 T, New 就是那个入口。
  220. func (t *Table[T]) New() *T {
  221. obj := new(T)
  222. t.bindModel(obj)
  223. return obj
  224. }
  225. // bindModel 把"这个对象属于哪张表"写回对象内嵌的表基类, 返回是否绑定成功。
  226. //
  227. // 走接口断言而不是反射: 每条被读写的记录都要过一遍, 反射在这里是白付的成本。
  228. // 内嵌的表基类会把 modelBinder 提升到 *T 上, 所以一次类型断言就够了。
  229. func (t *Table[T]) bindModel(obj *T) bool {
  230. b, ok := any(obj).(modelBinder)
  231. if !ok {
  232. return false
  233. }
  234. b.bindTo(t, obj)
  235. return true
  236. }
  237. // ===== session: Table[T] 的类型擦除视图 =====
  238. //
  239. // 模型基类不认识 T, 头部方法只能把请求交回这里; 这一层认识 T, 于是把参数断言回 *T。
  240. // 断言失败只可能是"把 A 表的对象交给了 B 表", 所以返回错误而不是 panic。
  241. // sessionObj 断言出 *T, 并顺手重新绑定 —— 对象可能是刚从一个临时副本拷过来的。
  242. func (t *Table[T]) sessionObj(op string, obj any) (*T, error) {
  243. o, ok := obj.(*T)
  244. if !ok {
  245. return nil, fmt.Errorf("tsdb: %s: 表 %s 收到了 %T, 类型不匹配", op, t.name, obj)
  246. }
  247. t.bindModel(o)
  248. return o, nil
  249. }
  250. func (t *Table[T]) insert(obj any) error {
  251. o, err := t.sessionObj("insert", obj)
  252. if err != nil {
  253. return err
  254. }
  255. return t.Insert(o)
  256. }
  257. func (t *Table[T]) update(obj any) error {
  258. o, err := t.sessionObj("update", obj)
  259. if err != nil {
  260. return err
  261. }
  262. return t.Update(o)
  263. }
  264. func (t *Table[T]) pkOf(obj any) (uint64, error) {
  265. o, err := t.sessionObj("pk", obj)
  266. if err != nil {
  267. return 0, err
  268. }
  269. return getPKValue(o, t.model)
  270. }
  271. // loadInto 把主键 pk 对应的整行读进 obj 指向的对象。
  272. //
  273. // 用 *o = *got 整块赋值而不是逐字段搬: 两边是同一个 T, 字段集合一致, 省掉一次反射。
  274. // 代价是 got 的绑定信息也被拷了过来 (self 还指着 got), 所以紧接着必须重新绑定到 o。
  275. func (t *Table[T]) loadInto(pk uint64, obj any) error {
  276. o, err := t.sessionObj("load", obj)
  277. if err != nil {
  278. return err
  279. }
  280. got, err := t.Find(pk)
  281. if err != nil {
  282. return err
  283. }
  284. *o = *got
  285. t.bindModel(o)
  286. return nil
  287. }
  288. // reload 重新读一遍 obj 所在的那一行。
  289. //
  290. // 行号已知 → 按行号读 (同刻多行也不会读串); 行号未知 → 退回按可见主键读。
  291. func (t *Table[T]) reload(obj any) error {
  292. o, err := t.sessionObj("reload", obj)
  293. if err != nil {
  294. return err
  295. }
  296. if id := rowIDOf(o); id != 0 {
  297. return t.loadByRowID(id, o)
  298. }
  299. pk, err := getPKValue(o, t.model)
  300. if err != nil {
  301. return fmt.Errorf("tsdb: reload: %w", err)
  302. }
  303. return t.loadInto(pk, o)
  304. }
  305. // loadByRowID 把行号 pkID 对应的整行读进 obj 指向的对象。
  306. func (t *Table[T]) loadByRowID(pkID uint64, obj any) error {
  307. o, err := t.sessionObj("load", obj)
  308. if err != nil {
  309. return err
  310. }
  311. got, err := t.findByRowID(pkID)
  312. if err != nil {
  313. return err
  314. }
  315. *o = *got
  316. t.bindModel(o)
  317. return nil
  318. }
  319. // findByRowID 按引擎行号读出一个新对象 (行号是内部句柄, 所以不对外暴露)。
  320. func (t *Table[T]) findByRowID(pkID uint64) (*T, error) {
  321. row, err := t.coreTable.FindByPK(pkID)
  322. if err != nil {
  323. return nil, err
  324. }
  325. obj := new(T)
  326. if err := fieldValuesToStruct(row, t.model, obj); err != nil {
  327. return nil, err
  328. }
  329. setRowIDOf(obj, pkID)
  330. t.bindModel(obj)
  331. return obj, nil
  332. }
  333. func (t *Table[T]) deleteByPK(pk uint64) error { return t.Delete(pk) }
  334. // deleteByRowID 按引擎行号删除一行 —— 同刻多行时唯一能精确指认"这一行"的方式。
  335. func (t *Table[T]) deleteByRowID(pkID uint64) error { return t.coreTable.DeleteRowByPK(pkID) }
  336. func (t *Table[T]) tableName() string { return t.name }
  337. func encodePKKey(pk uint64) []byte {
  338. buf := make([]byte, 8)
  339. binary.BigEndian.PutUint64(buf, pk)
  340. return buf
  341. }