index.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. // SPDX-FileCopyrightText: Adam Evyčędo
  2. //
  3. // SPDX-License-Identifier: AGPL-3.0-or-later
  4. package traffic
  5. import (
  6. "database/sql"
  7. "errors"
  8. "fmt"
  9. "path/filepath"
  10. "strings"
  11. )
  12. var indices map[string]map[string]*sql.DB
  13. func OpenIndices(context Context) error {
  14. indexDbName := filepath.Join(context.DataHome, context.FeedID, string(context.Version), FILE_INDEX_DB)
  15. indexDb, err := sql.Open("sqlite3", indexDbName)
  16. if err != nil {
  17. return fmt.Errorf("while opening index: %w", err)
  18. }
  19. if indices == nil {
  20. indices = map[string]map[string]*sql.DB{}
  21. }
  22. if indices[context.FeedID] == nil {
  23. indices[context.FeedID] = map[string]*sql.DB{}
  24. }
  25. indices[context.FeedID][string(context.Version)] = indexDb
  26. return nil
  27. }
  28. func ExistsStopForCode(code string, context Context) (bool, error) {
  29. return existsOffsetForID(code, context, INDEX_STOP_CODE)
  30. }
  31. func existsOffsetForID(id string, context Context, table string) (bool, error) {
  32. _, err := getOffsetByID(id, context, table)
  33. if err == nil {
  34. return true, nil
  35. } else {
  36. if errors.Is(err, sql.ErrNoRows) {
  37. return false, nil
  38. } else {
  39. return false, err
  40. }
  41. }
  42. }
  43. func getLineOffsetByID(id string, context Context) (uint, error) {
  44. return getOffsetByID(id, context, INDEX_LINE_CODE)
  45. }
  46. func getStopOffsetByCode(id string, context Context) (uint, error) {
  47. return getOffsetByID(id, context, INDEX_STOP_CODE)
  48. }
  49. func getTripOffset(id string, context Context) (uint, error) {
  50. return getOffsetByID(id, context, INDEX_TRIPS)
  51. }
  52. func getOffsetByID(id string, context Context, table string) (uint, error) {
  53. indexDb := indices[context.FeedID][string(context.Version)]
  54. row := indexDb.QueryRow("select offset from "+table+" where code == ?", id)
  55. var offset uint
  56. err := row.Scan(&offset)
  57. return offset, err
  58. }
  59. func getTripsOffsets(ids []string, context Context) ([]uint, error) {
  60. return getOffsetsByIDs(ids, context, INDEX_TRIPS)
  61. }
  62. func getOffsetsByIDs(ids []string, context Context, table string) ([]uint, error) {
  63. indexDb := indices[context.FeedID][string(context.Version)]
  64. offsets := []uint{}
  65. placeholders := make([]string, len(ids))
  66. idValues := make([]any, len(ids))
  67. for i := range ids {
  68. placeholders[i] = "?"
  69. idValues[i] = ids[i]
  70. }
  71. rows, err := indexDb.Query("select offset from "+table+" where code in ("+strings.Join(placeholders, ", ")+")", idValues...)
  72. if err != nil {
  73. return offsets, fmt.Errorf("while selecting: %w", err)
  74. }
  75. for rows.Next() {
  76. var offset uint
  77. err := rows.Scan(&offset)
  78. if err != nil {
  79. return offsets, fmt.Errorf("while scanning: %w", err)
  80. }
  81. offsets = append(offsets, offset)
  82. }
  83. return offsets, err
  84. }
  85. func getLineOffsetsByName(name string, context Context) ([]uint, error) {
  86. indexDb := indices[context.FeedID][string(context.Version)]
  87. offsets := []uint{}
  88. rows, err := indexDb.Query("select offset from "+INDEX_LINES+" where name == ?", name)
  89. if err != nil {
  90. return offsets, fmt.Errorf("while selecting: %w", err)
  91. }
  92. for rows.Next() {
  93. var offset uint
  94. err := rows.Scan(&offset)
  95. if err != nil {
  96. return offsets, fmt.Errorf("while scanning: %w", err)
  97. }
  98. offsets = append(offsets, offset)
  99. }
  100. return offsets, err
  101. }
  102. func getNameIndex(feedID string, validity Validity) (NameIndexDB, error) {
  103. indexDb := indices[feedID][string(validity)]
  104. tx, err := indexDb.Begin()
  105. if err != nil {
  106. return NameIndexDB{}, fmt.Errorf("while beginnging transaction: %w", err)
  107. }
  108. return NameIndexDB{
  109. tx: tx,
  110. table: INDEX_LINES,
  111. }, nil
  112. }
  113. func getLineOffsetByRowID(i int, context Context) (uint, error) {
  114. return getOffsetByRowID(i, context, INDEX_LINES)
  115. }
  116. func getStopOffsetByRowID(i int, context Context) (uint, error) {
  117. return getOffsetByRowID(i, context, INDEX_STOPS)
  118. }
  119. func getOffsetByRowID(i int, context Context, table string) (uint, error) {
  120. indexDb := indices[context.FeedID][string(context.Version)]
  121. row := indexDb.QueryRow("select offset from "+table+" where rowid == ?", i+1)
  122. var offset uint
  123. err := row.Scan(&offset)
  124. return offset, err
  125. }