Mirror of https://github.com/roostorg/coop github.com/roostorg/coop
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 168 lines 5.0 kB view raw
1import sequelize, { 2 type HasOneGetAssociationMixin, 3 type InferAttributes, 4 type InferCreationAttributes, 5 type NonAttribute, 6 type Sequelize, 7} from 'sequelize'; 8 9import { type DataTypes } from '../index.js'; 10import { type User } from '../UserModel.js'; 11import { type Rule } from './RuleModel.js'; 12 13const { Model } = sequelize; 14 15export type Backtest = InstanceType<ReturnType<typeof makeBacktestModel>>; 16export enum BacktestStatus { 17 RUNNING = 'RUNNING', 18 COMPLETE = 'COMPLETE', 19 CANCELED = 'CANCELED', 20} 21 22const makeBacktestModel = (sequelize: Sequelize, DataTypes: DataTypes) => { 23 class Backtest extends Model< 24 InferAttributes<Backtest>, 25 InferCreationAttributes< 26 Backtest, 27 // fields that _cannot be set explicitly_ at creation time, b/c they have 28 // db defaults that must always apply (i.e., cannot be overriden) at creation. 29 { 30 omit: 31 | 'contentItemsProcessed' 32 | 'contentItemsMatched' 33 | 'status' 34 | 'createdAt' 35 | 'updatedAt' 36 | 'samplingComplete' 37 | 'sampleActualSize' 38 | 'cancelationDate'; 39 } 40 > 41 > { 42 public declare id: string; 43 44 public declare ruleId: string; 45 public declare rule?: Rule; 46 47 public declare creatorId: string; 48 public declare creator?: User; 49 50 public declare sampleDesiredSize: number; 51 public declare sampleActualSize: number; 52 public declare sampleStartAt: Date; 53 public declare sampleEndAt: Date; 54 55 public declare cancelationDate: Date; 56 public declare samplingComplete: boolean; 57 58 public declare contentItemsProcessed: number; 59 public declare contentItemsMatched: number; 60 61 public declare status: BacktestStatus; 62 63 public declare createdAt: Date; 64 public declare updatedAt: Date; 65 66 declare getRule: HasOneGetAssociationMixin<Rule>; 67 declare getCreator: HasOneGetAssociationMixin<User>; 68 69 // eslint-disable-next-line @typescript-eslint/no-explicit-any 70 static associate(models: { [key: string]: any }) { 71 Backtest.belongsTo(models.User, { as: 'Creator' }); 72 Backtest.belongsTo(models.Rule, { as: 'Rule' }); 73 } 74 75 public static async hasRunningBacktestsForRule(ruleId: string) { 76 // ugh the built-in sequelize query builder sucks. 77 // https://github.com/sequelize/sequelize/issues/10187 78 return Backtest.findOne({ 79 where: { ruleId, status: BacktestStatus.RUNNING }, 80 }).then((it) => it != null); 81 } 82 83 public static async cancelRunningBacktestsForRule(ruleId: string) { 84 return Backtest.update( 85 { cancelationDate: new Date() }, 86 { where: { ruleId, status: BacktestStatus.RUNNING } }, 87 ); 88 } 89 90 public async cancel() { 91 this.cancelationDate = new Date(); 92 await this.save(); 93 return this; 94 } 95 96 /** 97 * Because our queues will deliver sampled content items to be processed 98 * _at least once_, it’s possible that, rarely, contentItemsProcessed will 99 * be greater than sampleActualSize. To mitigate this, we clamp the 100 * exposed value for contentItemsProcessed at sampleActualSize. 101 */ 102 public get correctedContentItemsProcessed(): NonAttribute<number> { 103 return Math.min(this.sampleActualSize, this.contentItemsProcessed); 104 } 105 106 /** 107 * Similar to {@see correctedContentItemsProcessed}, we clamp the exposed 108 * value of contentItemsMatched, since we can't logically have matched more 109 * items than we processed. 110 */ 111 public get correctedContentItemsMatched(): NonAttribute<number> { 112 return Math.min( 113 this.correctedContentItemsProcessed, 114 this.contentItemsMatched, 115 ); 116 } 117 } 118 119 /* Fields */ 120 Backtest.init( 121 { 122 id: { type: DataTypes.STRING, primaryKey: true }, 123 ruleId: { type: DataTypes.STRING, allowNull: false }, 124 creatorId: { type: DataTypes.STRING, allowNull: false }, 125 126 sampleDesiredSize: { type: DataTypes.INTEGER, allowNull: false }, 127 sampleActualSize: { 128 type: DataTypes.INTEGER, 129 allowNull: false, 130 defaultValue: 0, 131 }, 132 sampleStartAt: { type: DataTypes.DATE, allowNull: false }, 133 sampleEndAt: { type: DataTypes.DATE, allowNull: false }, 134 135 cancelationDate: { type: DataTypes.DATE }, 136 samplingComplete: { 137 type: DataTypes.BOOLEAN, 138 allowNull: false, 139 defaultValue: false, 140 }, 141 142 contentItemsProcessed: { 143 type: DataTypes.INTEGER, 144 allowNull: false, 145 defaultValue: 0, 146 }, 147 contentItemsMatched: { 148 type: DataTypes.INTEGER, 149 allowNull: false, 150 defaultValue: 0, 151 }, 152 153 status: { type: DataTypes.STRING }, 154 createdAt: { type: DataTypes.DATE, allowNull: false }, 155 updatedAt: { type: DataTypes.DATE, allowNull: false }, 156 }, 157 { 158 sequelize, 159 modelName: 'backtest', 160 underscored: true, 161 timestamps: true, 162 }, 163 ); 164 165 return Backtest; 166}; 167 168export default makeBacktestModel;