inbound_util.go 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. package service
  2. // sqliteMaxVars is a safe ceiling for the number of bind parameters in a
  3. // single SQL statement. SQLite's SQLITE_MAX_VARIABLE_NUMBER is 999 on builds
  4. // before 3.32 and 32766 after; staying under 999 keeps queries portable
  5. // across forks/old binaries and also bounds per-query memory on truly large
  6. // installs (>32k clients) where even modern SQLite would refuse a single IN.
  7. const sqliteMaxVars = 900
  8. // normalizeSubSortIndex clamps the 1-based subscription sort order. Values
  9. // below 1 arrive from clients that predate the field (omitted form key binds
  10. // to 0) and must not sort ahead of explicitly ranked inbounds.
  11. func normalizeSubSortIndex(v int) int {
  12. if v < 1 {
  13. return 1
  14. }
  15. return v
  16. }
  17. // uniqueNonEmptyStrings returns a deduplicated copy of in with empty strings
  18. // removed, preserving the order of first occurrence.
  19. func uniqueNonEmptyStrings(in []string) []string {
  20. if len(in) == 0 {
  21. return nil
  22. }
  23. seen := make(map[string]struct{}, len(in))
  24. out := make([]string, 0, len(in))
  25. for _, v := range in {
  26. if v == "" {
  27. continue
  28. }
  29. if _, ok := seen[v]; ok {
  30. continue
  31. }
  32. seen[v] = struct{}{}
  33. out = append(out, v)
  34. }
  35. return out
  36. }
  37. // uniqueInts returns a deduplicated copy of in, preserving order of first occurrence.
  38. func uniqueInts(in []int) []int {
  39. if len(in) == 0 {
  40. return nil
  41. }
  42. seen := make(map[int]struct{}, len(in))
  43. out := make([]int, 0, len(in))
  44. for _, v := range in {
  45. if _, ok := seen[v]; ok {
  46. continue
  47. }
  48. seen[v] = struct{}{}
  49. out = append(out, v)
  50. }
  51. return out
  52. }
  53. // chunkStrings splits s into consecutive sub-slices of at most size elements.
  54. // Returns nil for an empty input or non-positive size.
  55. func chunkStrings(s []string, size int) [][]string {
  56. if size <= 0 || len(s) == 0 {
  57. return nil
  58. }
  59. out := make([][]string, 0, (len(s)+size-1)/size)
  60. for i := 0; i < len(s); i += size {
  61. end := min(i+size, len(s))
  62. out = append(out, s[i:end])
  63. }
  64. return out
  65. }
  66. // chunkInts splits s into consecutive sub-slices of at most size elements.
  67. // Returns nil for an empty input or non-positive size.
  68. func chunkInts(s []int, size int) [][]int {
  69. if size <= 0 || len(s) == 0 {
  70. return nil
  71. }
  72. out := make([][]int, 0, (len(s)+size-1)/size)
  73. for i := 0; i < len(s); i += size {
  74. end := min(i+size, len(s))
  75. out = append(out, s[i:end])
  76. }
  77. return out
  78. }