@naturalcycles/abba 1.14.0 → 1.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.experimentDao = exports.ExperimentDao = void 0;
4
4
  const db_lib_1 = require("@naturalcycles/db-lib");
5
+ const js_lib_1 = require("@naturalcycles/js-lib");
5
6
  class ExperimentDao extends db_lib_1.CommonDao {
6
7
  }
7
8
  exports.ExperimentDao = ExperimentDao;
@@ -19,9 +20,22 @@ const experimentDao = (db) => new ExperimentDao({
19
20
  }),
20
21
  beforeDBMToBM: dbm => ({
21
22
  ...dbm,
23
+ startDateIncl: parseMySQLDate(dbm.startDateIncl),
24
+ endDateExcl: parseMySQLDate(dbm.endDateExcl),
22
25
  rules: (dbm.rules && JSON.parse(dbm.rules)) || [],
23
26
  exclusions: (dbm.exclusions && JSON.parse(dbm.exclusions)) || [],
24
27
  }),
25
28
  },
26
29
  });
27
30
  exports.experimentDao = experimentDao;
31
+ /**
32
+ * https://nc1.slack.com/archives/CCNTHJT7V/p1682514277002739
33
+ * MySQL Automatically parses Date fields as Date objects
34
+ * For simplicity let's not do that by having this function...
35
+ */
36
+ function parseMySQLDate(date) {
37
+ // @ts-expect-error
38
+ if (date instanceof Date)
39
+ return (0, js_lib_1.localDate)(date).toISODate();
40
+ return date;
41
+ }
package/dist/types.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { CommonDB } from '@naturalcycles/db-lib';
2
- import { AnyObject, BaseDBEntity, Saved } from '@naturalcycles/js-lib';
2
+ import { AnyObject, BaseDBEntity, IsoDateString, Saved } from '@naturalcycles/js-lib';
3
3
  export interface AbbaConfig {
4
4
  db: CommonDB;
5
5
  }
@@ -8,8 +8,8 @@ export type BaseExperiment = BaseDBEntity<number> & {
8
8
  status: number;
9
9
  sampling: number;
10
10
  description: string | null;
11
- startDateIncl: Date;
12
- endDateExcl: Date;
11
+ startDateIncl: IsoDateString;
12
+ endDateExcl: IsoDateString;
13
13
  };
14
14
  export type Experiment = BaseExperiment & {
15
15
  rules: SegmentationRule[];
package/dist/util.js CHANGED
@@ -116,7 +116,7 @@ exports.validateSegmentationRule = validateSegmentationRule;
116
116
  const canGenerateNewAssignments = (experiment, exclusionSet) => {
117
117
  return (!exclusionSet.has(experiment.id) &&
118
118
  experiment.status === types_1.AssignmentStatus.Active &&
119
- (0, js_lib_1.localDate)().isBetween((0, js_lib_1.localDate)(experiment.startDateIncl.toISOString()), (0, js_lib_1.localDate)(experiment.endDateExcl.toISOString()), '[)'));
119
+ (0, js_lib_1.localDate)().isBetween(experiment.startDateIncl, experiment.endDateExcl, '[)'));
120
120
  };
121
121
  exports.canGenerateNewAssignments = canGenerateNewAssignments;
122
122
  /**
@@ -126,6 +126,10 @@ exports.canGenerateNewAssignments = canGenerateNewAssignments;
126
126
  const getUserExclusionSet = (experiments, existingAssignments) => {
127
127
  const exclusionSet = new Set();
128
128
  existingAssignments.forEach(assignment => {
129
+ // Users who are excluded from an experiment due to sampling
130
+ // should not prevent potential assignment to other mutually exclusive experiments
131
+ if (assignment.bucketId === null)
132
+ return;
129
133
  const experiment = experiments.find(e => e.id === assignment.experimentId);
130
134
  experiment?.exclusions.forEach(experimentId => exclusionSet.add(experimentId));
131
135
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@naturalcycles/abba",
3
- "version": "1.14.0",
3
+ "version": "1.15.0",
4
4
  "scripts": {
5
5
  "prepare": "husky install",
6
6
  "build": "build",
@@ -1,5 +1,5 @@
1
1
  import { CommonDao, CommonDB } from '@naturalcycles/db-lib'
2
- import { Saved } from '@naturalcycles/js-lib'
2
+ import { IsoDateString, localDate, Saved } from '@naturalcycles/js-lib'
3
3
  import { BaseExperiment, Experiment } from '../types'
4
4
 
5
5
  type ExperimentDBM = Saved<BaseExperiment> & {
@@ -24,8 +24,21 @@ export const experimentDao = (db: CommonDB): ExperimentDao =>
24
24
  }),
25
25
  beforeDBMToBM: dbm => ({
26
26
  ...dbm,
27
+ startDateIncl: parseMySQLDate(dbm.startDateIncl),
28
+ endDateExcl: parseMySQLDate(dbm.endDateExcl),
27
29
  rules: (dbm.rules && JSON.parse(dbm.rules)) || [],
28
30
  exclusions: (dbm.exclusions && JSON.parse(dbm.exclusions)) || [],
29
31
  }),
30
32
  },
31
33
  })
34
+
35
+ /**
36
+ * https://nc1.slack.com/archives/CCNTHJT7V/p1682514277002739
37
+ * MySQL Automatically parses Date fields as Date objects
38
+ * For simplicity let's not do that by having this function...
39
+ */
40
+ function parseMySQLDate(date: string): IsoDateString {
41
+ // @ts-expect-error
42
+ if (date instanceof Date) return localDate(date).toISODate()
43
+ return date
44
+ }
package/src/types.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { CommonDB } from '@naturalcycles/db-lib'
2
- import { AnyObject, BaseDBEntity, Saved } from '@naturalcycles/js-lib'
2
+ import { AnyObject, BaseDBEntity, IsoDateString, Saved } from '@naturalcycles/js-lib'
3
3
 
4
4
  export interface AbbaConfig {
5
5
  db: CommonDB
@@ -10,8 +10,8 @@ export type BaseExperiment = BaseDBEntity<number> & {
10
10
  status: number
11
11
  sampling: number
12
12
  description: string | null
13
- startDateIncl: Date
14
- endDateExcl: Date
13
+ startDateIncl: IsoDateString
14
+ endDateExcl: IsoDateString
15
15
  }
16
16
 
17
17
  export type Experiment = BaseExperiment & {
package/src/util.ts CHANGED
@@ -136,11 +136,7 @@ export const canGenerateNewAssignments = (
136
136
  return (
137
137
  !exclusionSet.has(experiment.id) &&
138
138
  experiment.status === AssignmentStatus.Active &&
139
- localDate().isBetween(
140
- localDate(experiment.startDateIncl.toISOString()),
141
- localDate(experiment.endDateExcl.toISOString()),
142
- '[)',
143
- )
139
+ localDate().isBetween(experiment.startDateIncl, experiment.endDateExcl, '[)')
144
140
  )
145
141
  }
146
142
 
@@ -154,6 +150,10 @@ export const getUserExclusionSet = (
154
150
  ): ExclusionSet => {
155
151
  const exclusionSet: ExclusionSet = new Set()
156
152
  existingAssignments.forEach(assignment => {
153
+ // Users who are excluded from an experiment due to sampling
154
+ // should not prevent potential assignment to other mutually exclusive experiments
155
+ if (assignment.bucketId === null) return
156
+
157
157
  const experiment = experiments.find(e => e.id === assignment.experimentId)
158
158
  experiment?.exclusions.forEach(experimentId => exclusionSet.add(experimentId))
159
159
  })