schema.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. package memdb
  2. import "fmt"
  3. // DBSchema is the schema to use for the full database with a MemDB instance.
  4. //
  5. // MemDB will require a valid schema. Schema validation can be tested using
  6. // the Validate function. Calling this function is recommended in unit tests.
  7. type DBSchema struct {
  8. // Tables is the set of tables within this database. The key is the
  9. // table name and must match the Name in TableSchema.
  10. Tables map[string]*TableSchema
  11. }
  12. // Validate validates the schema.
  13. func (s *DBSchema) Validate() error {
  14. if s == nil {
  15. return fmt.Errorf("schema is nil")
  16. }
  17. if len(s.Tables) == 0 {
  18. return fmt.Errorf("schema has no tables defined")
  19. }
  20. for name, table := range s.Tables {
  21. if name != table.Name {
  22. return fmt.Errorf("table name mis-match for '%s'", name)
  23. }
  24. if err := table.Validate(); err != nil {
  25. return fmt.Errorf("table %q: %s", name, err)
  26. }
  27. }
  28. return nil
  29. }
  30. // TableSchema is the schema for a single table.
  31. type TableSchema struct {
  32. // Name of the table. This must match the key in the Tables map in DBSchema.
  33. Name string
  34. // Indexes is the set of indexes for querying this table. The key
  35. // is a unique name for the index and must match the Name in the
  36. // IndexSchema.
  37. Indexes map[string]*IndexSchema
  38. }
  39. // Validate is used to validate the table schema
  40. func (s *TableSchema) Validate() error {
  41. if s.Name == "" {
  42. return fmt.Errorf("missing table name")
  43. }
  44. if len(s.Indexes) == 0 {
  45. return fmt.Errorf("missing table indexes for '%s'", s.Name)
  46. }
  47. if _, ok := s.Indexes["id"]; !ok {
  48. return fmt.Errorf("must have id index")
  49. }
  50. if !s.Indexes["id"].Unique {
  51. return fmt.Errorf("id index must be unique")
  52. }
  53. if _, ok := s.Indexes["id"].Indexer.(SingleIndexer); !ok {
  54. return fmt.Errorf("id index must be a SingleIndexer")
  55. }
  56. for name, index := range s.Indexes {
  57. if name != index.Name {
  58. return fmt.Errorf("index name mis-match for '%s'", name)
  59. }
  60. if err := index.Validate(); err != nil {
  61. return fmt.Errorf("index %q: %s", name, err)
  62. }
  63. }
  64. return nil
  65. }
  66. // IndexSchema is the schema for an index. An index defines how a table is
  67. // queried.
  68. type IndexSchema struct {
  69. // Name of the index. This must be unique among a tables set of indexes.
  70. // This must match the key in the map of Indexes for a TableSchema.
  71. Name string
  72. // AllowMissing if true ignores this index if it doesn't produce a
  73. // value. For example, an index that extracts a field that doesn't
  74. // exist from a structure.
  75. AllowMissing bool
  76. Unique bool
  77. Indexer Indexer
  78. }
  79. func (s *IndexSchema) Validate() error {
  80. if s.Name == "" {
  81. return fmt.Errorf("missing index name")
  82. }
  83. if s.Indexer == nil {
  84. return fmt.Errorf("missing index function for '%s'", s.Name)
  85. }
  86. switch s.Indexer.(type) {
  87. case SingleIndexer:
  88. case MultiIndexer:
  89. default:
  90. return fmt.Errorf("indexer for '%s' must be a SingleIndexer or MultiIndexer", s.Name)
  91. }
  92. return nil
  93. }