@naturalcycles/abba 1.2.0 → 1.3.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.
- package/dist/abba.js +2 -2
- package/dist/prisma-output/index-browser.js +0 -5
- package/dist/prisma-output/index.d.ts +0 -11
- package/dist/prisma-output/index.js +2 -7
- package/dist/prisma-output/schema.prisma +2 -2
- package/dist/util.d.ts +7 -14
- package/dist/util.js +18 -29
- package/package.json +1 -2
- package/readme.md +8 -8
- package/src/abba.ts +3 -3
- package/src/prisma-output/index-browser.js +0 -5
- package/src/prisma-output/index.d.ts +0 -11
- package/src/prisma-output/index.js +2 -7
- package/src/prisma-output/schema.prisma +2 -2
- package/src/util.ts +12 -20
package/dist/util.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { Bucket
|
|
1
|
+
import { Bucket } from './prisma-output';
|
|
2
2
|
import { BucketInput, SegmentationData, SegmentationRule } from '.';
|
|
3
3
|
/**
|
|
4
4
|
* Generate a random number between 0 and 100
|
|
5
5
|
*
|
|
6
6
|
* @returns
|
|
7
7
|
*/
|
|
8
|
-
export declare
|
|
8
|
+
export declare const rollDie: () => number;
|
|
9
9
|
/**
|
|
10
10
|
* Determines a users assignment for this experiment. Returns null if they are not considered to be in the sampling group
|
|
11
11
|
*
|
|
@@ -13,28 +13,21 @@ export declare function rollDie(): number;
|
|
|
13
13
|
* @param buckets
|
|
14
14
|
* @returns
|
|
15
15
|
*/
|
|
16
|
-
export declare
|
|
17
|
-
/**
|
|
18
|
-
* Determines whether a user will be considered for a bucket assignment based on the experiment sampling rate
|
|
19
|
-
*
|
|
20
|
-
* @param experiment
|
|
21
|
-
* @returns
|
|
22
|
-
*/
|
|
23
|
-
export declare function determineExperiment(experiment: Experiment): boolean;
|
|
16
|
+
export declare const determineAssignment: (sampling: number, buckets: Bucket[]) => number | null;
|
|
24
17
|
/**
|
|
25
18
|
* Determines which bucket a user assignment will recieve
|
|
26
19
|
*
|
|
27
20
|
* @param buckets
|
|
28
21
|
* @returns
|
|
29
22
|
*/
|
|
30
|
-
export declare
|
|
23
|
+
export declare const determineBucket: (buckets: Bucket[]) => number;
|
|
31
24
|
/**
|
|
32
25
|
* Validate the total ratio of the buckets equals 100
|
|
33
26
|
*
|
|
34
27
|
* @param buckets
|
|
35
28
|
* @returns
|
|
36
29
|
*/
|
|
37
|
-
export declare
|
|
30
|
+
export declare const validateTotalBucketRatio: (buckets: BucketInput[]) => void;
|
|
38
31
|
/**
|
|
39
32
|
* Validate a users segmentation data against multiple rules. Returns false if any fail
|
|
40
33
|
*
|
|
@@ -42,7 +35,7 @@ export declare function validateBuckets(buckets: BucketInput[]): void;
|
|
|
42
35
|
* @param segmentationData
|
|
43
36
|
* @returns
|
|
44
37
|
*/
|
|
45
|
-
export declare
|
|
38
|
+
export declare const validateSegmentationRules: (rules: SegmentationRule[], segmentationData: SegmentationData) => boolean;
|
|
46
39
|
/**
|
|
47
40
|
* Validate a users segmentation data against a single rule
|
|
48
41
|
*
|
|
@@ -50,4 +43,4 @@ export declare function validateSegmentationRules(rules: SegmentationRule[], seg
|
|
|
50
43
|
* @param segmentationData
|
|
51
44
|
* @returns
|
|
52
45
|
*/
|
|
53
|
-
export declare
|
|
46
|
+
export declare const validateSegmentationRule: (rule: SegmentationRule, data: SegmentationData) => boolean;
|
package/dist/util.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.validateSegmentationRule = exports.validateSegmentationRules = exports.
|
|
3
|
+
exports.validateSegmentationRule = exports.validateSegmentationRules = exports.validateTotalBucketRatio = exports.determineBucket = exports.determineAssignment = exports.rollDie = void 0;
|
|
4
4
|
const semver_1 = require("semver");
|
|
5
5
|
/**
|
|
6
6
|
* Generate a random number between 0 and 100
|
|
7
7
|
*
|
|
8
8
|
* @returns
|
|
9
9
|
*/
|
|
10
|
-
|
|
10
|
+
const rollDie = () => {
|
|
11
11
|
return Math.random() * 100;
|
|
12
|
-
}
|
|
12
|
+
};
|
|
13
13
|
exports.rollDie = rollDie;
|
|
14
14
|
/**
|
|
15
15
|
* Determines a users assignment for this experiment. Returns null if they are not considered to be in the sampling group
|
|
@@ -18,34 +18,23 @@ exports.rollDie = rollDie;
|
|
|
18
18
|
* @param buckets
|
|
19
19
|
* @returns
|
|
20
20
|
*/
|
|
21
|
-
|
|
21
|
+
const determineAssignment = (sampling, buckets) => {
|
|
22
22
|
// Should this person be considered for the experiment?
|
|
23
|
-
|
|
24
|
-
if (!isIncludedInSample) {
|
|
23
|
+
if ((0, exports.rollDie)() > sampling) {
|
|
25
24
|
return null;
|
|
26
25
|
}
|
|
27
26
|
// get their bucket
|
|
28
|
-
return determineBucket(buckets);
|
|
29
|
-
}
|
|
27
|
+
return (0, exports.determineBucket)(buckets);
|
|
28
|
+
};
|
|
30
29
|
exports.determineAssignment = determineAssignment;
|
|
31
|
-
/**
|
|
32
|
-
* Determines whether a user will be considered for a bucket assignment based on the experiment sampling rate
|
|
33
|
-
*
|
|
34
|
-
* @param experiment
|
|
35
|
-
* @returns
|
|
36
|
-
*/
|
|
37
|
-
function determineExperiment(experiment) {
|
|
38
|
-
return rollDie() <= experiment.sampling; // between 0 and 100
|
|
39
|
-
}
|
|
40
|
-
exports.determineExperiment = determineExperiment;
|
|
41
30
|
/**
|
|
42
31
|
* Determines which bucket a user assignment will recieve
|
|
43
32
|
*
|
|
44
33
|
* @param buckets
|
|
45
34
|
* @returns
|
|
46
35
|
*/
|
|
47
|
-
|
|
48
|
-
const bucketRoll = rollDie();
|
|
36
|
+
const determineBucket = (buckets) => {
|
|
37
|
+
const bucketRoll = (0, exports.rollDie)();
|
|
49
38
|
let range;
|
|
50
39
|
const bucket = buckets.find(b => {
|
|
51
40
|
if (!range) {
|
|
@@ -62,7 +51,7 @@ function determineBucket(buckets) {
|
|
|
62
51
|
throw new Error('Could not detetermine bucket from ratios');
|
|
63
52
|
}
|
|
64
53
|
return bucket.id;
|
|
65
|
-
}
|
|
54
|
+
};
|
|
66
55
|
exports.determineBucket = determineBucket;
|
|
67
56
|
/**
|
|
68
57
|
* Validate the total ratio of the buckets equals 100
|
|
@@ -70,13 +59,13 @@ exports.determineBucket = determineBucket;
|
|
|
70
59
|
* @param buckets
|
|
71
60
|
* @returns
|
|
72
61
|
*/
|
|
73
|
-
|
|
62
|
+
const validateTotalBucketRatio = (buckets) => {
|
|
74
63
|
const bucketSum = buckets.reduce((sum, current) => sum + current.ratio, 0);
|
|
75
64
|
if (bucketSum !== 100) {
|
|
76
65
|
throw new Error('Total bucket ratio must be 100 before you can activate an experiment');
|
|
77
66
|
}
|
|
78
|
-
}
|
|
79
|
-
exports.
|
|
67
|
+
};
|
|
68
|
+
exports.validateTotalBucketRatio = validateTotalBucketRatio;
|
|
80
69
|
/**
|
|
81
70
|
* Validate a users segmentation data against multiple rules. Returns false if any fail
|
|
82
71
|
*
|
|
@@ -84,13 +73,13 @@ exports.validateBuckets = validateBuckets;
|
|
|
84
73
|
* @param segmentationData
|
|
85
74
|
* @returns
|
|
86
75
|
*/
|
|
87
|
-
|
|
76
|
+
const validateSegmentationRules = (rules, segmentationData) => {
|
|
88
77
|
for (const rule of rules) {
|
|
89
|
-
if (!validateSegmentationRule(rule, segmentationData))
|
|
78
|
+
if (!(0, exports.validateSegmentationRule)(rule, segmentationData))
|
|
90
79
|
return false;
|
|
91
80
|
}
|
|
92
81
|
return true;
|
|
93
|
-
}
|
|
82
|
+
};
|
|
94
83
|
exports.validateSegmentationRules = validateSegmentationRules;
|
|
95
84
|
/**
|
|
96
85
|
* Validate a users segmentation data against a single rule
|
|
@@ -99,7 +88,7 @@ exports.validateSegmentationRules = validateSegmentationRules;
|
|
|
99
88
|
* @param segmentationData
|
|
100
89
|
* @returns
|
|
101
90
|
*/
|
|
102
|
-
|
|
91
|
+
const validateSegmentationRule = (rule, data) => {
|
|
103
92
|
const { key, value, operator } = rule;
|
|
104
93
|
if (operator === '==') {
|
|
105
94
|
return data[key] === value;
|
|
@@ -119,5 +108,5 @@ function validateSegmentationRule(rule, data) {
|
|
|
119
108
|
else {
|
|
120
109
|
return false;
|
|
121
110
|
}
|
|
122
|
-
}
|
|
111
|
+
};
|
|
123
112
|
exports.validateSegmentationRule = validateSegmentationRule;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@naturalcycles/abba",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"prepare": "husky install",
|
|
6
6
|
"build": "build && npm run copy-prisma-output",
|
|
@@ -13,7 +13,6 @@
|
|
|
13
13
|
},
|
|
14
14
|
"devDependencies": {
|
|
15
15
|
"@naturalcycles/dev-lib": "^12.0.0",
|
|
16
|
-
"@types/json-logic-js": "^1.2.1",
|
|
17
16
|
"@types/node": "^16.0.0",
|
|
18
17
|
"@types/semver": "^7.3.9",
|
|
19
18
|
"jest": "^27.5.1",
|
package/readme.md
CHANGED
|
@@ -77,16 +77,16 @@ This template doesn't rely on any external dependencies or services._
|
|
|
77
77
|
npm install @naturalcyles/abba
|
|
78
78
|
```
|
|
79
79
|
|
|
80
|
-
2. Execute the [sql script found here](/src/prisma/migrations/
|
|
81
|
-
Schema
|
|
80
|
+
2. Execute the [sql script found here](/src/prisma/migrations/20220218075343_init/migration.sql) to
|
|
81
|
+
generate the required DB Schema
|
|
82
82
|
|
|
83
83
|
3. Create a `.env` file add add your Database Url using the following key:
|
|
84
84
|
```sh
|
|
85
|
-
|
|
85
|
+
ABBA_DB_URL="{{insert your instance url}}"
|
|
86
86
|
```
|
|
87
|
-
4. Create a new instance of the
|
|
87
|
+
4. Create a new instance of the Abba class
|
|
88
88
|
```js
|
|
89
|
-
const
|
|
89
|
+
const abba = new Abba()
|
|
90
90
|
```
|
|
91
91
|
|
|
92
92
|
<p align="right">(<a href="#top">back to top</a>)</p>
|
|
@@ -102,7 +102,7 @@ This template doesn't rely on any external dependencies or services._
|
|
|
102
102
|
Creates a new experiment
|
|
103
103
|
|
|
104
104
|
```js
|
|
105
|
-
async
|
|
105
|
+
async createExperiment(
|
|
106
106
|
input: ExperimentInput,
|
|
107
107
|
buckets: BucketInput[]
|
|
108
108
|
): Promise<Experiment>
|
|
@@ -113,7 +113,7 @@ async manager.createExperiment(
|
|
|
113
113
|
Updates an existing experiment.
|
|
114
114
|
|
|
115
115
|
```js
|
|
116
|
-
async
|
|
116
|
+
async updateExperiment(
|
|
117
117
|
id: number,
|
|
118
118
|
input: ExperimentInput,
|
|
119
119
|
buckets: BucketInput[]
|
|
@@ -125,7 +125,7 @@ async manager.updateExperiment(
|
|
|
125
125
|
Delete an experiment. Removes all users assignments and buckets
|
|
126
126
|
|
|
127
127
|
```js
|
|
128
|
-
async
|
|
128
|
+
async deleteExperiment(
|
|
129
129
|
id: number
|
|
130
130
|
): Promise<void>
|
|
131
131
|
```
|
package/src/abba.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Bucket, Experiment, Prisma, PrismaClient, UserAssignment } from './prisma-output'
|
|
2
2
|
import { AssignmentStatus } from './types'
|
|
3
|
-
import { determineAssignment, validateSegmentationRules,
|
|
3
|
+
import { determineAssignment, validateSegmentationRules, validateTotalBucketRatio } from './util'
|
|
4
4
|
import {
|
|
5
5
|
BucketInput,
|
|
6
6
|
ExperimentWithBuckets,
|
|
@@ -44,7 +44,7 @@ export class Abba {
|
|
|
44
44
|
buckets: BucketInput[],
|
|
45
45
|
): Promise<ExperimentWithBuckets> {
|
|
46
46
|
if (experiment.status === AssignmentStatus.Active) {
|
|
47
|
-
|
|
47
|
+
validateTotalBucketRatio(buckets)
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
const created = await this.client.experiment.create({
|
|
@@ -79,7 +79,7 @@ export class Abba {
|
|
|
79
79
|
buckets: BucketInput[],
|
|
80
80
|
): Promise<ExperimentWithBuckets> {
|
|
81
81
|
if (experiment.status === AssignmentStatus.Active) {
|
|
82
|
-
|
|
82
|
+
validateTotalBucketRatio(buckets)
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
const updatedExperiment = await this.updateExperiment(id, experiment)
|
|
@@ -113,11 +113,6 @@ exports.Prisma.NullableJsonNullValueInput = makeEnum({
|
|
|
113
113
|
JsonNull: 'JsonNull',
|
|
114
114
|
})
|
|
115
115
|
|
|
116
|
-
exports.Prisma.QueryMode = makeEnum({
|
|
117
|
-
default: 'default',
|
|
118
|
-
insensitive: 'insensitive',
|
|
119
|
-
})
|
|
120
|
-
|
|
121
116
|
exports.Prisma.JsonNullValueFilter = makeEnum({
|
|
122
117
|
DbNull: 'DbNull',
|
|
123
118
|
JsonNull: 'JsonNull',
|
|
@@ -3920,13 +3920,6 @@ export namespace Prisma {
|
|
|
3920
3920
|
export type NullableJsonNullValueInput =
|
|
3921
3921
|
typeof NullableJsonNullValueInput[keyof typeof NullableJsonNullValueInput]
|
|
3922
3922
|
|
|
3923
|
-
export const QueryMode: {
|
|
3924
|
-
default: 'default'
|
|
3925
|
-
insensitive: 'insensitive'
|
|
3926
|
-
}
|
|
3927
|
-
|
|
3928
|
-
export type QueryMode = typeof QueryMode[keyof typeof QueryMode]
|
|
3929
|
-
|
|
3930
3923
|
export const JsonNullValueFilter: {
|
|
3931
3924
|
DbNull: 'DbNull'
|
|
3932
3925
|
JsonNull: 'JsonNull'
|
|
@@ -4338,7 +4331,6 @@ export namespace Prisma {
|
|
|
4338
4331
|
contains?: string
|
|
4339
4332
|
startsWith?: string
|
|
4340
4333
|
endsWith?: string
|
|
4341
|
-
mode?: QueryMode
|
|
4342
4334
|
not?: NestedStringFilter | string
|
|
4343
4335
|
}
|
|
4344
4336
|
|
|
@@ -4434,7 +4426,6 @@ export namespace Prisma {
|
|
|
4434
4426
|
contains?: string
|
|
4435
4427
|
startsWith?: string
|
|
4436
4428
|
endsWith?: string
|
|
4437
|
-
mode?: QueryMode
|
|
4438
4429
|
not?: NestedStringWithAggregatesFilter | string
|
|
4439
4430
|
_count?: NestedIntFilter
|
|
4440
4431
|
_min?: NestedStringFilter
|
|
@@ -4466,7 +4457,6 @@ export namespace Prisma {
|
|
|
4466
4457
|
contains?: string
|
|
4467
4458
|
startsWith?: string
|
|
4468
4459
|
endsWith?: string
|
|
4469
|
-
mode?: QueryMode
|
|
4470
4460
|
not?: NestedStringNullableFilter | string | null
|
|
4471
4461
|
}
|
|
4472
4462
|
export type JsonNullableFilter =
|
|
@@ -4548,7 +4538,6 @@ export namespace Prisma {
|
|
|
4548
4538
|
contains?: string
|
|
4549
4539
|
startsWith?: string
|
|
4550
4540
|
endsWith?: string
|
|
4551
|
-
mode?: QueryMode
|
|
4552
4541
|
not?: NestedStringNullableWithAggregatesFilter | string | null
|
|
4553
4542
|
_count?: NestedIntNullableFilter
|
|
4554
4543
|
_min?: NestedStringNullableFilter
|