2
0

table.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710
  1. package storage
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "strings"
  6. )
  7. // Row represents a database row.
  8. type Row map[string]interface{}
  9. // TableManager manages table data operations.
  10. type TableManager struct {
  11. pool *KVPool
  12. schema *SchemaManager
  13. database string
  14. }
  15. // NewTableManager creates a new table manager.
  16. func NewTableManager(pool *KVPool, schema *SchemaManager, database string) *TableManager {
  17. return &TableManager{
  18. pool: pool,
  19. schema: schema,
  20. database: database,
  21. }
  22. }
  23. // dataKey returns the key for a row.
  24. func (m *TableManager) dataKey(table, pk string) string {
  25. return fmt.Sprintf("%s:_data:%s:%s", m.database, strings.ToLower(table), pk)
  26. }
  27. // dataPrefix returns the prefix for all rows in a table.
  28. func (m *TableManager) dataPrefix(table string) string {
  29. return fmt.Sprintf("%s:_data:%s:", m.database, strings.ToLower(table))
  30. }
  31. // Insert inserts a new row.
  32. func (m *TableManager) Insert(table string, row Row) error {
  33. schema, err := m.schema.GetSchema(table)
  34. if err != nil {
  35. return err
  36. }
  37. // Get primary key value
  38. pkValue, ok := row[schema.PrimaryKey]
  39. if !ok {
  40. // Try case-insensitive lookup
  41. for k, v := range row {
  42. if strings.EqualFold(k, schema.PrimaryKey) {
  43. pkValue = v
  44. ok = true
  45. break
  46. }
  47. }
  48. }
  49. // Check if PK is INTEGER PRIMARY KEY (implicit ROWID alias)
  50. pkCol, _ := schema.GetColumn(schema.PrimaryKey)
  51. isIntegerPK := pkCol != nil && isIntegerType(pkCol.Type)
  52. // Auto-generate ROWID if no primary key provided or if it's INTEGER PRIMARY KEY
  53. var rowid int64
  54. if !ok || pkValue == nil {
  55. if isIntegerPK || !ok {
  56. // Generate ROWID
  57. rowid, err = m.schema.GetNextRowID(table)
  58. if err != nil {
  59. return err
  60. }
  61. pkValue = rowid
  62. row[schema.PrimaryKey] = rowid
  63. ok = true
  64. } else {
  65. return fmt.Errorf("missing primary key: %s", schema.PrimaryKey)
  66. }
  67. } else if isIntegerPK {
  68. // User provided INTEGER PRIMARY KEY value - track it
  69. switch v := pkValue.(type) {
  70. case int64:
  71. rowid = v
  72. case float64:
  73. rowid = int64(v)
  74. case int:
  75. rowid = int64(v)
  76. default:
  77. rowid = 0
  78. }
  79. if rowid > 0 {
  80. m.schema.UpdateMaxRowID(table, rowid)
  81. }
  82. }
  83. pk := fmt.Sprintf("%v", pkValue)
  84. // Check for duplicate
  85. key := m.dataKey(table, pk)
  86. err = m.pool.WithClient(func(c *KVClient) error {
  87. _, err := c.Read(key)
  88. return err
  89. })
  90. if err == nil {
  91. return fmt.Errorf("duplicate primary key: %s", pk)
  92. }
  93. // Validate required columns
  94. for _, col := range schema.Columns {
  95. if !col.Nullable && col.Default == nil {
  96. val, hasVal := row[col.Name]
  97. if !hasVal {
  98. // Try case-insensitive lookup
  99. for k, v := range row {
  100. if strings.EqualFold(k, col.Name) {
  101. val = v
  102. hasVal = true
  103. break
  104. }
  105. }
  106. }
  107. if !hasVal || val == nil {
  108. return fmt.Errorf("missing required column: %s", col.Name)
  109. }
  110. }
  111. }
  112. // Normalize column names to match schema
  113. normalizedRow := make(Row)
  114. for _, col := range schema.Columns {
  115. for k, v := range row {
  116. if strings.EqualFold(k, col.Name) {
  117. normalizedRow[col.Name] = v
  118. break
  119. }
  120. }
  121. }
  122. // Apply defaults
  123. for _, col := range schema.Columns {
  124. if _, ok := normalizedRow[col.Name]; !ok && col.Default != nil {
  125. normalizedRow[col.Name] = col.Default
  126. }
  127. }
  128. // Store ROWID (use PK value for INTEGER PRIMARY KEY, otherwise generate)
  129. if rowid > 0 {
  130. normalizedRow["_rowid_"] = rowid
  131. } else {
  132. // Generate ROWID for non-integer primary keys
  133. newRowID, _ := m.schema.GetNextRowID(table)
  134. normalizedRow["_rowid_"] = newRowID
  135. }
  136. // Serialize row
  137. data, err := json.Marshal(normalizedRow)
  138. if err != nil {
  139. return fmt.Errorf("failed to serialize row: %w", err)
  140. }
  141. // Write row
  142. err = m.pool.WithClient(func(c *KVClient) error {
  143. return c.Write(key, string(data))
  144. })
  145. if err != nil {
  146. return err
  147. }
  148. // Update indexes
  149. m.updateIndexesForRow(table, normalizedRow, true)
  150. return nil
  151. }
  152. // updateIndexesForRow adds or removes index entries for a row.
  153. func (m *TableManager) updateIndexesForRow(table string, row Row, add bool) {
  154. indexes, err := m.schema.ListTableIndexes(table)
  155. if err != nil || len(indexes) == 0 {
  156. return
  157. }
  158. rowid, ok := row["_rowid_"].(float64)
  159. if !ok {
  160. if rid, ok := row["_rowid_"].(int64); ok {
  161. rowid = float64(rid)
  162. } else {
  163. return
  164. }
  165. }
  166. for _, idx := range indexes {
  167. columns := make([]string, len(idx.Columns))
  168. for i, col := range idx.Columns {
  169. columns[i] = col.Name
  170. }
  171. colValue := m.buildIndexValue(row, columns)
  172. if add {
  173. m.AddIndexEntry(idx.Name, colValue, int64(rowid))
  174. } else {
  175. m.RemoveIndexEntry(idx.Name, colValue, int64(rowid))
  176. }
  177. }
  178. }
  179. // Select retrieves rows from a table.
  180. func (m *TableManager) Select(table string, filter func(Row) bool) ([]Row, error) {
  181. if !m.schema.TableExists(table) {
  182. return nil, fmt.Errorf("table not found: %s", table)
  183. }
  184. prefix := m.dataPrefix(table)
  185. var values []string
  186. err := m.pool.WithClient(func(c *KVClient) error {
  187. var err error
  188. values, err = c.Reads(prefix)
  189. return err
  190. })
  191. if err != nil {
  192. return nil, err
  193. }
  194. rows := make([]Row, 0, len(values))
  195. for _, data := range values {
  196. var row Row
  197. if err := json.Unmarshal([]byte(data), &row); err != nil {
  198. continue // Skip invalid rows
  199. }
  200. if filter == nil || filter(row) {
  201. rows = append(rows, row)
  202. }
  203. }
  204. return rows, nil
  205. }
  206. // SelectWithLimit retrieves rows with limit and offset.
  207. func (m *TableManager) SelectWithLimit(table string, filter func(Row) bool, limit, offset int) ([]Row, error) {
  208. rows, err := m.Select(table, filter)
  209. if err != nil {
  210. return nil, err
  211. }
  212. // Apply offset
  213. if offset > 0 {
  214. if offset >= len(rows) {
  215. return nil, nil
  216. }
  217. rows = rows[offset:]
  218. }
  219. // Apply limit
  220. if limit > 0 && limit < len(rows) {
  221. rows = rows[:limit]
  222. }
  223. return rows, nil
  224. }
  225. // Update updates rows matching the filter.
  226. func (m *TableManager) Update(table string, updates Row, filter func(Row) bool) (int, error) {
  227. schema, err := m.schema.GetSchema(table)
  228. if err != nil {
  229. return 0, err
  230. }
  231. // Get all rows
  232. rows, err := m.Select(table, filter)
  233. if err != nil {
  234. return 0, err
  235. }
  236. count := 0
  237. for _, row := range rows {
  238. // Remove old index entries before update
  239. m.updateIndexesForRow(table, row, false)
  240. // Apply updates
  241. for k, v := range updates {
  242. // Normalize column name
  243. for _, col := range schema.Columns {
  244. if strings.EqualFold(k, col.Name) {
  245. row[col.Name] = v
  246. break
  247. }
  248. }
  249. }
  250. // Get primary key
  251. pkValue := row[schema.PrimaryKey]
  252. pk := fmt.Sprintf("%v", pkValue)
  253. // Serialize row
  254. data, err := json.Marshal(row)
  255. if err != nil {
  256. continue
  257. }
  258. // Write back
  259. key := m.dataKey(table, pk)
  260. err = m.pool.WithClient(func(c *KVClient) error {
  261. return c.Write(key, string(data))
  262. })
  263. if err == nil {
  264. // Add new index entries after update
  265. m.updateIndexesForRow(table, row, true)
  266. count++
  267. }
  268. }
  269. return count, nil
  270. }
  271. // UpdateFunc updates rows matching the filter using a function to compute new values.
  272. // The updateFn receives the current row and returns the updates to apply.
  273. func (m *TableManager) UpdateFunc(table string, updateFn func(Row) (Row, error), filter func(Row) bool) (int, error) {
  274. schema, err := m.schema.GetSchema(table)
  275. if err != nil {
  276. return 0, err
  277. }
  278. // Get all rows
  279. rows, err := m.Select(table, filter)
  280. if err != nil {
  281. return 0, err
  282. }
  283. count := 0
  284. for _, row := range rows {
  285. // Remove old index entries before update
  286. m.updateIndexesForRow(table, row, false)
  287. // Compute updates using the provided function
  288. updates, err := updateFn(row)
  289. if err != nil {
  290. return count, err
  291. }
  292. // Apply updates
  293. for k, v := range updates {
  294. // Normalize column name
  295. for _, col := range schema.Columns {
  296. if strings.EqualFold(k, col.Name) {
  297. row[col.Name] = v
  298. break
  299. }
  300. }
  301. }
  302. // Get primary key
  303. pkValue := row[schema.PrimaryKey]
  304. pk := fmt.Sprintf("%v", pkValue)
  305. // Serialize row
  306. data, err := json.Marshal(row)
  307. if err != nil {
  308. continue
  309. }
  310. // Write back
  311. key := m.dataKey(table, pk)
  312. err = m.pool.WithClient(func(c *KVClient) error {
  313. return c.Write(key, string(data))
  314. })
  315. if err == nil {
  316. // Add new index entries after update
  317. m.updateIndexesForRow(table, row, true)
  318. count++
  319. }
  320. }
  321. return count, nil
  322. }
  323. // Delete deletes rows matching the filter.
  324. func (m *TableManager) Delete(table string, filter func(Row) bool) (int, error) {
  325. schema, err := m.schema.GetSchema(table)
  326. if err != nil {
  327. return 0, err
  328. }
  329. // Get all rows
  330. rows, err := m.Select(table, filter)
  331. if err != nil {
  332. return 0, err
  333. }
  334. count := 0
  335. for _, row := range rows {
  336. // Remove index entries before deleting row
  337. m.updateIndexesForRow(table, row, false)
  338. pkValue := row[schema.PrimaryKey]
  339. pk := fmt.Sprintf("%v", pkValue)
  340. key := m.dataKey(table, pk)
  341. err = m.pool.WithClient(func(c *KVClient) error {
  342. return c.Delete(key)
  343. })
  344. if err == nil {
  345. count++
  346. }
  347. }
  348. return count, nil
  349. }
  350. // GetByPK retrieves a row by primary key.
  351. func (m *TableManager) GetByPK(table string, pk string) (Row, error) {
  352. if !m.schema.TableExists(table) {
  353. return nil, fmt.Errorf("table not found: %s", table)
  354. }
  355. key := m.dataKey(table, pk)
  356. var data string
  357. err := m.pool.WithClient(func(c *KVClient) error {
  358. var err error
  359. data, err = c.Read(key)
  360. return err
  361. })
  362. if err != nil {
  363. if err == ErrKeyNotFound {
  364. return nil, fmt.Errorf("row not found: %s", pk)
  365. }
  366. return nil, err
  367. }
  368. var row Row
  369. if err := json.Unmarshal([]byte(data), &row); err != nil {
  370. return nil, fmt.Errorf("failed to parse row: %w", err)
  371. }
  372. return row, nil
  373. }
  374. // Count returns the number of rows in a table.
  375. func (m *TableManager) Count(table string, filter func(Row) bool) (int, error) {
  376. rows, err := m.Select(table, filter)
  377. if err != nil {
  378. return 0, err
  379. }
  380. return len(rows), nil
  381. }
  382. // Truncate removes all rows from a table.
  383. func (m *TableManager) Truncate(table string) (int, error) {
  384. return m.Delete(table, nil)
  385. }
  386. // isIntegerType checks if a type name is an integer type.
  387. func isIntegerType(typeName string) bool {
  388. t := strings.ToUpper(typeName)
  389. switch t {
  390. case "INTEGER", "INT", "SMALLINT", "BIGINT", "TINYINT", "MEDIUMINT":
  391. return true
  392. }
  393. return false
  394. }
  395. // IsRowIDColumn checks if a column name is a ROWID alias.
  396. func IsRowIDColumn(name string) bool {
  397. n := strings.ToLower(name)
  398. return n == "rowid" || n == "oid" || n == "_rowid_"
  399. }
  400. // Index entry methods - leveraging radix trie for prefix-based lookups
  401. // Format: {database}:idx:{index_name}:{column_value} → JSON array of rowids
  402. // indexEntryKey returns the key for an index entry.
  403. func (m *TableManager) indexEntryKey(indexName string, colValue interface{}) string {
  404. // Format the value without scientific notation
  405. var valueStr string
  406. switch v := colValue.(type) {
  407. case float64:
  408. // Check if it's actually an integer value
  409. if v == float64(int64(v)) {
  410. valueStr = fmt.Sprintf("%d", int64(v))
  411. } else {
  412. valueStr = fmt.Sprintf("%f", v)
  413. }
  414. case int64:
  415. valueStr = fmt.Sprintf("%d", v)
  416. case int:
  417. valueStr = fmt.Sprintf("%d", v)
  418. default:
  419. valueStr = fmt.Sprintf("%v", v)
  420. }
  421. return fmt.Sprintf("%s:idx:%s:%s", m.database, strings.ToLower(indexName), valueStr)
  422. }
  423. // indexPrefix returns the prefix for all entries of an index.
  424. func (m *TableManager) indexPrefix(indexName string) string {
  425. return fmt.Sprintf("%s:idx:%s:", m.database, strings.ToLower(indexName))
  426. }
  427. // AddIndexEntry adds a rowid to an index entry.
  428. func (m *TableManager) AddIndexEntry(indexName string, colValue interface{}, rowid int64) error {
  429. key := m.indexEntryKey(indexName, colValue)
  430. // Read existing rowids
  431. var rowids []int64
  432. err := m.pool.WithClient(func(c *KVClient) error {
  433. data, err := c.Read(key)
  434. if err == nil && data != "" {
  435. json.Unmarshal([]byte(data), &rowids)
  436. }
  437. return nil // Ignore not found errors
  438. })
  439. if err != nil {
  440. return err
  441. }
  442. // Add new rowid if not already present
  443. for _, r := range rowids {
  444. if r == rowid {
  445. return nil // Already exists
  446. }
  447. }
  448. rowids = append(rowids, rowid)
  449. // Write back
  450. data, _ := json.Marshal(rowids)
  451. return m.pool.WithClient(func(c *KVClient) error {
  452. return c.Write(key, string(data))
  453. })
  454. }
  455. // RemoveIndexEntry removes a rowid from an index entry.
  456. func (m *TableManager) RemoveIndexEntry(indexName string, colValue interface{}, rowid int64) error {
  457. key := m.indexEntryKey(indexName, colValue)
  458. // Read existing rowids
  459. var rowids []int64
  460. err := m.pool.WithClient(func(c *KVClient) error {
  461. data, err := c.Read(key)
  462. if err != nil {
  463. return err
  464. }
  465. json.Unmarshal([]byte(data), &rowids)
  466. return nil
  467. })
  468. if err != nil {
  469. return nil // Entry doesn't exist
  470. }
  471. // Remove rowid
  472. newRowids := make([]int64, 0, len(rowids))
  473. for _, r := range rowids {
  474. if r != rowid {
  475. newRowids = append(newRowids, r)
  476. }
  477. }
  478. if len(newRowids) == 0 {
  479. // Delete the entry entirely
  480. return m.pool.WithClient(func(c *KVClient) error {
  481. return c.Delete(key)
  482. })
  483. }
  484. // Write back
  485. data, _ := json.Marshal(newRowids)
  486. return m.pool.WithClient(func(c *KVClient) error {
  487. return c.Write(key, string(data))
  488. })
  489. }
  490. // LookupIndex returns rowids matching a column value using the index.
  491. func (m *TableManager) LookupIndex(indexName string, colValue interface{}) ([]int64, error) {
  492. key := m.indexEntryKey(indexName, colValue)
  493. var rowids []int64
  494. err := m.pool.WithClient(func(c *KVClient) error {
  495. data, err := c.Read(key)
  496. if err != nil {
  497. return err
  498. }
  499. return json.Unmarshal([]byte(data), &rowids)
  500. })
  501. if err != nil {
  502. return nil, nil // Return empty if not found
  503. }
  504. return rowids, nil
  505. }
  506. // ClearIndex removes all entries for an index by scanning table and removing entries.
  507. func (m *TableManager) ClearIndex(indexName, tableName string, columns []string) error {
  508. rows, err := m.Select(tableName, nil)
  509. if err != nil {
  510. return err
  511. }
  512. for _, row := range rows {
  513. colValue := m.buildIndexValue(row, columns)
  514. key := m.indexEntryKey(indexName, colValue)
  515. m.pool.WithClient(func(c *KVClient) error {
  516. return c.Delete(key)
  517. })
  518. }
  519. return nil
  520. }
  521. // BuildIndex builds index entries for all existing rows in a table.
  522. func (m *TableManager) BuildIndex(indexName, tableName string, columns []string) error {
  523. rows, err := m.Select(tableName, nil)
  524. if err != nil {
  525. return err
  526. }
  527. for _, row := range rows {
  528. rowid, ok := row["_rowid_"].(float64)
  529. if !ok {
  530. continue
  531. }
  532. // Build composite key value for multi-column indexes
  533. colValue := m.buildIndexValue(row, columns)
  534. if err := m.AddIndexEntry(indexName, colValue, int64(rowid)); err != nil {
  535. return err
  536. }
  537. }
  538. return nil
  539. }
  540. // buildIndexValue creates the index key value from row columns.
  541. func (m *TableManager) buildIndexValue(row Row, columns []string) string {
  542. formatValue := func(v interface{}) string {
  543. switch val := v.(type) {
  544. case float64:
  545. // Check if it's actually an integer value
  546. if val == float64(int64(val)) {
  547. return fmt.Sprintf("%d", int64(val))
  548. }
  549. return fmt.Sprintf("%f", val)
  550. case int64:
  551. return fmt.Sprintf("%d", val)
  552. case int:
  553. return fmt.Sprintf("%d", val)
  554. default:
  555. return fmt.Sprintf("%v", val)
  556. }
  557. }
  558. if len(columns) == 1 {
  559. return formatValue(row[columns[0]])
  560. }
  561. // Multi-column index: concatenate values with separator
  562. var parts []string
  563. for _, col := range columns {
  564. parts = append(parts, formatValue(row[col]))
  565. }
  566. return strings.Join(parts, "\x00")
  567. }
  568. // SelectByIndex retrieves rows using an index lookup.
  569. func (m *TableManager) SelectByIndex(table, indexName string, colValue interface{}) ([]Row, error) {
  570. rowids, err := m.LookupIndex(indexName, colValue)
  571. if err != nil {
  572. return nil, err
  573. }
  574. // If no rowids found, return empty result
  575. if len(rowids) == 0 {
  576. return []Row{}, nil
  577. }
  578. schema, err := m.schema.GetSchema(table)
  579. if err != nil {
  580. return nil, err
  581. }
  582. // Check if primary key is INTEGER type (in which case rowid == pk)
  583. pkCol, _ := schema.GetColumn(schema.PrimaryKey)
  584. isPKInteger := pkCol != nil && isIntegerType(pkCol.Type)
  585. rows := make([]Row, 0, len(rowids))
  586. for _, rowid := range rowids {
  587. var row Row
  588. // For INTEGER PRIMARY KEY, the rowid IS the primary key
  589. if isPKInteger {
  590. row, err = m.GetByPK(table, fmt.Sprintf("%d", rowid))
  591. if err == nil {
  592. rows = append(rows, row)
  593. continue
  594. }
  595. }
  596. // For non-INTEGER primary keys or if PK lookup fails, look up by _rowid_
  597. allRows, _ := m.Select(table, func(r Row) bool {
  598. if rid, ok := r["_rowid_"].(float64); ok {
  599. return int64(rid) == rowid
  600. }
  601. if rid, ok := r["_rowid_"].(int64); ok {
  602. return rid == rowid
  603. }
  604. return false
  605. })
  606. if len(allRows) > 0 {
  607. rows = append(rows, allRows[0])
  608. }
  609. }
  610. return rows, nil
  611. }