Files
overleaf-cep/services/web/app/src/models/SplitTest.js
Alexandre Bourdin ddd9334bd6 Merge pull request #14951 from overleaf/ab-split-test-calculator
[web] Split test calculator

GitOrigin-RevId: 53a84a64d69c47d692f215dee351af635a5dcceb
2024-01-15 09:04:22 +00:00

175 lines
3.5 KiB
JavaScript

const mongoose = require('../infrastructure/Mongoose')
const { Schema } = mongoose
const { ObjectId } = Schema
const MIN_NAME_LENGTH = 3
const MAX_NAME_LENGTH = 200
const MIN_VARIANT_NAME_LENGTH = 3
const MAX_VARIANT_NAME_LENGTH = 255
const NAME_REGEX = /^[a-z0-9-]+$/
const RolloutPercentType = {
type: Number,
default: 0,
min: [0, 'Rollout percentage must be between 0 and 100, got {VALUE}'],
max: [100, 'Rollout percentage must be between 0 and 100, got {VALUE}'],
required: true,
}
const BadgeSchema = new Schema(
{
tooltipText: {
type: String,
required: false,
},
url: {
type: String,
required: false,
},
},
{ _id: false }
)
const BadgeInfoSchema = new Schema(
{
alpha: BadgeSchema,
beta: BadgeSchema,
release: BadgeSchema,
},
{ _id: false }
)
const VariantSchema = new Schema(
{
name: {
type: String,
minLength: MIN_VARIANT_NAME_LENGTH,
maxLength: MAX_VARIANT_NAME_LENGTH,
required: true,
validate: {
validator: function (input) {
return input !== null && input !== 'default' && NAME_REGEX.test(input)
},
message: `invalid, cannot be 'default' and must match: ${NAME_REGEX}, got {VALUE}`,
},
},
rolloutPercent: RolloutPercentType,
rolloutStripes: [
{
start: RolloutPercentType,
end: RolloutPercentType,
},
],
},
{ _id: false }
)
const VersionSchema = new Schema(
{
versionNumber: {
type: Number,
default: 1,
min: [1, 'must be 1 or higher, got {VALUE}'],
required: true,
},
phase: {
type: String,
default: 'alpha',
enum: ['alpha', 'beta', 'release'],
required: true,
},
active: {
type: Boolean,
default: true,
required: true,
},
analyticsEnabled: {
type: Boolean,
default: true,
required: true,
},
variants: [VariantSchema],
createdAt: {
type: Date,
default: Date.now,
},
author: { type: ObjectId, ref: 'User' },
comment: {
type: String,
required: false,
},
},
{ _id: false }
)
const SplitTestSchema = new Schema(
{
name: {
type: String,
minLength: MIN_NAME_LENGTH,
maxlength: MAX_NAME_LENGTH,
required: true,
unique: true,
validate: {
validator: function (input) {
return input !== null && NAME_REGEX.test(input)
},
message: `invalid, must match: ${NAME_REGEX}`,
},
},
versions: [VersionSchema],
forbidReleasePhase: {
type: Boolean,
required: false,
},
description: {
type: String,
required: false,
},
expectedEndDate: {
type: Date,
required: false,
},
requiredCohortSize: {
type: Number,
required: false,
},
expectedUplift: {
type: Number,
required: false,
},
ticketUrl: {
type: String,
required: false,
},
reportsUrls: {
type: [String],
required: false,
default: [],
},
winningVariant: {
type: String,
required: false,
},
archived: {
type: Boolean,
required: false,
},
archivedAt: {
type: Date,
required: false,
},
archivedBy: { type: ObjectId, ref: 'User' },
badgeInfo: {
type: BadgeInfoSchema,
required: false,
},
},
{ minimize: false }
)
module.exports = {
SplitTest: mongoose.model('SplitTest', SplitTestSchema),
SplitTestSchema,
}