SplitTest.mjs 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. import mongoose from '../infrastructure/Mongoose.mjs'
  2. const { Schema } = mongoose
  3. const { ObjectId } = Schema
  4. const MIN_NAME_LENGTH = 3
  5. const MAX_NAME_LENGTH = 200
  6. const MIN_VARIANT_NAME_LENGTH = 3
  7. const MAX_VARIANT_NAME_LENGTH = 255
  8. const NAME_REGEX = /^[a-z0-9-]+$/
  9. const RolloutPercentType = {
  10. type: Number,
  11. default: 0,
  12. min: [0, 'Rollout percentage must be between 0 and 100, got {VALUE}'],
  13. max: [100, 'Rollout percentage must be between 0 and 100, got {VALUE}'],
  14. required: true,
  15. }
  16. const BadgeSchema = new Schema(
  17. {
  18. tooltipText: {
  19. type: String,
  20. required: false,
  21. },
  22. url: {
  23. type: String,
  24. required: false,
  25. },
  26. },
  27. { _id: false }
  28. )
  29. const BadgeInfoSchema = new Schema(
  30. {
  31. alpha: BadgeSchema,
  32. beta: BadgeSchema,
  33. release: BadgeSchema,
  34. },
  35. { _id: false }
  36. )
  37. const VariantSchema = new Schema(
  38. {
  39. name: {
  40. type: String,
  41. minLength: MIN_VARIANT_NAME_LENGTH,
  42. maxLength: MAX_VARIANT_NAME_LENGTH,
  43. required: true,
  44. validate: {
  45. validator: function (input) {
  46. return input !== null && input !== 'default' && NAME_REGEX.test(input)
  47. },
  48. message: `invalid, cannot be 'default' and must match: ${NAME_REGEX}, got {VALUE}`,
  49. },
  50. },
  51. rolloutPercent: RolloutPercentType,
  52. rolloutStripes: [
  53. {
  54. start: RolloutPercentType,
  55. end: RolloutPercentType,
  56. },
  57. ],
  58. userLimit: {
  59. type: Number,
  60. min: [0, 'User limit must be 0 or greater, got {VALUE}'],
  61. required: false,
  62. },
  63. userCount: {
  64. type: Number,
  65. min: [0, 'User count must be 0 or greater, got {VALUE}'],
  66. required: false,
  67. },
  68. },
  69. { _id: false }
  70. )
  71. const VersionSchema = new Schema(
  72. {
  73. versionNumber: {
  74. type: Number,
  75. default: 1,
  76. min: [1, 'must be 1 or higher, got {VALUE}'],
  77. required: true,
  78. },
  79. phase: {
  80. type: String,
  81. default: 'alpha',
  82. enum: ['alpha', 'beta', 'release'],
  83. required: true,
  84. },
  85. active: {
  86. type: Boolean,
  87. default: true,
  88. required: true,
  89. },
  90. analyticsEnabled: {
  91. type: Boolean,
  92. default: true,
  93. required: true,
  94. },
  95. variants: [VariantSchema],
  96. createdAt: {
  97. type: Date,
  98. default: Date.now,
  99. },
  100. author: { type: ObjectId, ref: 'User' },
  101. comment: {
  102. type: String,
  103. required: false,
  104. },
  105. },
  106. { _id: false }
  107. )
  108. export const SplitTestSchema = new Schema(
  109. {
  110. name: {
  111. type: String,
  112. minLength: MIN_NAME_LENGTH,
  113. maxlength: MAX_NAME_LENGTH,
  114. required: true,
  115. unique: true,
  116. validate: {
  117. validator: function (input) {
  118. return input !== null && NAME_REGEX.test(input)
  119. },
  120. message: `invalid, must match: ${NAME_REGEX}`,
  121. },
  122. },
  123. versions: [VersionSchema],
  124. forbidReleasePhase: {
  125. type: Boolean,
  126. required: false,
  127. },
  128. description: {
  129. type: String,
  130. required: false,
  131. },
  132. expectedEndDate: {
  133. type: Date,
  134. required: false,
  135. },
  136. requiredCohortSize: {
  137. type: Number,
  138. required: false,
  139. },
  140. expectedUplift: {
  141. type: Number,
  142. required: false,
  143. },
  144. ticketUrl: {
  145. type: String,
  146. required: false,
  147. },
  148. reportsUrls: {
  149. type: [String],
  150. required: false,
  151. default: [],
  152. },
  153. winningVariant: {
  154. type: String,
  155. required: false,
  156. },
  157. archived: {
  158. type: Boolean,
  159. required: false,
  160. },
  161. archivedAt: {
  162. type: Date,
  163. required: false,
  164. },
  165. archivedBy: { type: ObjectId, ref: 'User' },
  166. badgeInfo: {
  167. type: BadgeInfoSchema,
  168. required: false,
  169. },
  170. },
  171. { minimize: false }
  172. )
  173. export const SplitTest = mongoose.model('SplitTest', SplitTestSchema)