@naturalcycles/abba 1.6.0 → 1.9.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.
Files changed (55) hide show
  1. package/dist/abba.d.ts +15 -29
  2. package/dist/abba.js +56 -107
  3. package/dist/dao/bucket.dao.d.ts +5 -0
  4. package/dist/dao/bucket.dao.js +15 -0
  5. package/dist/dao/experiment.dao.d.ts +10 -0
  6. package/dist/dao/experiment.dao.js +19 -0
  7. package/dist/dao/userAssignment.dao.d.ts +5 -0
  8. package/dist/dao/userAssignment.dao.js +15 -0
  9. package/dist/index.d.ts +0 -1
  10. package/dist/index.js +1 -1
  11. package/dist/migrations/init.sql +47 -0
  12. package/dist/types.d.ts +30 -7
  13. package/dist/util.d.ts +5 -5
  14. package/package.json +7 -8
  15. package/readme.md +14 -15
  16. package/src/abba.ts +90 -134
  17. package/src/dao/bucket.dao.ts +13 -0
  18. package/src/dao/experiment.dao.ts +22 -0
  19. package/src/dao/userAssignment.dao.ts +13 -0
  20. package/src/index.ts +0 -3
  21. package/src/migrations/init.sql +47 -0
  22. package/src/types.ts +33 -7
  23. package/src/util.ts +5 -5
  24. package/dist/prisma-output/index-browser.js +0 -141
  25. package/dist/prisma-output/index.d.ts +0 -5521
  26. package/dist/prisma-output/index.js +0 -199
  27. package/dist/prisma-output/libquery_engine-darwin-arm64.dylib.node +0 -0
  28. package/dist/prisma-output/libquery_engine-darwin.dylib.node +0 -0
  29. package/dist/prisma-output/libquery_engine-debian-openssl-1.1.x.so.node +0 -0
  30. package/dist/prisma-output/runtime/esm/index-browser.mjs +0 -2370
  31. package/dist/prisma-output/runtime/esm/index.mjs +0 -40587
  32. package/dist/prisma-output/runtime/esm/proxy.mjs +0 -113
  33. package/dist/prisma-output/runtime/index-browser.d.ts +0 -269
  34. package/dist/prisma-output/runtime/index-browser.js +0 -2621
  35. package/dist/prisma-output/runtime/index.d.ts +0 -1373
  36. package/dist/prisma-output/runtime/index.js +0 -52855
  37. package/dist/prisma-output/runtime/proxy.d.ts +0 -1373
  38. package/dist/prisma-output/runtime/proxy.js +0 -13717
  39. package/dist/prisma-output/schema.prisma +0 -47
  40. package/src/prisma-output/index-browser.js +0 -141
  41. package/src/prisma-output/index.d.ts +0 -5521
  42. package/src/prisma-output/index.js +0 -199
  43. package/src/prisma-output/libquery_engine-darwin-arm64.dylib.node +0 -0
  44. package/src/prisma-output/libquery_engine-darwin.dylib.node +0 -0
  45. package/src/prisma-output/libquery_engine-debian-openssl-1.1.x.so.node +0 -0
  46. package/src/prisma-output/runtime/esm/index-browser.mjs +0 -2370
  47. package/src/prisma-output/runtime/esm/index.mjs +0 -40587
  48. package/src/prisma-output/runtime/esm/proxy.mjs +0 -113
  49. package/src/prisma-output/runtime/index-browser.d.ts +0 -269
  50. package/src/prisma-output/runtime/index-browser.js +0 -2621
  51. package/src/prisma-output/runtime/index.d.ts +0 -1373
  52. package/src/prisma-output/runtime/index.js +0 -52855
  53. package/src/prisma-output/runtime/proxy.d.ts +0 -1373
  54. package/src/prisma-output/runtime/proxy.js +0 -13717
  55. package/src/prisma-output/schema.prisma +0 -47
package/dist/abba.d.ts CHANGED
@@ -1,8 +1,11 @@
1
- import { UserAssignment } from './prisma-output';
2
- import { BucketInput, ExperimentWithBuckets, ExperimentInput, SegmentationData, AssignmentStatistics } from '.';
1
+ import { Saved } from '@naturalcycles/js-lib';
2
+ import { AbbaConfig, Bucket, Experiment, ExperimentWithBuckets, UserAssignment } from './types';
3
+ import { SegmentationData, AssignmentStatistics } from '.';
3
4
  export declare class Abba {
4
- private client;
5
- constructor(dbUrl?: string);
5
+ private experimentDao;
6
+ private bucketDao;
7
+ private userAssignmentDao;
8
+ constructor({ db }: AbbaConfig);
6
9
  /**
7
10
  * Returns all experiments
8
11
  *
@@ -16,7 +19,7 @@ export declare class Abba {
16
19
  * @param buckets
17
20
  * @returns
18
21
  */
19
- createExperiment(experiment: ExperimentInput, buckets: BucketInput[]): Promise<ExperimentWithBuckets>;
22
+ createExperiment(experiment: Experiment, buckets: Bucket[]): Promise<ExperimentWithBuckets>;
20
23
  /**
21
24
  * Update experiment information, will also validate the buckets ratio if experiment.active is true
22
25
  *
@@ -26,7 +29,7 @@ export declare class Abba {
26
29
  * @param buckets
27
30
  * @returns
28
31
  */
29
- saveExperiment(id: number, experiment: ExperimentInput, buckets: BucketInput[]): Promise<ExperimentWithBuckets>;
32
+ saveExperiment(id: number, experiment: Experiment, buckets: Bucket[]): Promise<ExperimentWithBuckets>;
30
33
  /**
31
34
  * Delete an experiment. Removes all user assignments and buckets
32
35
  *
@@ -38,18 +41,18 @@ export declare class Abba {
38
41
  *
39
42
  * @param experimentId
40
43
  * @param userId
41
- * @param createNew
42
- * @param segmentationData
44
+ * @param existingOnly Do not generate any new assignments for this experiment
45
+ * @param segmentationData Required if existingOnly is false
43
46
  * @returns
44
47
  */
45
- getUserAssignment(experimentId: number, userId: string, existingOnly: boolean, segmentationData?: SegmentationData): Promise<UserAssignment | null>;
48
+ getUserAssignment(experimentId: number, userId: string, existingOnly: boolean, segmentationData?: SegmentationData): Promise<Saved<UserAssignment> | null>;
46
49
  /**
47
50
  * Get all existing user assignments
48
51
  *
49
- * @param userId G
52
+ * @param userId
50
53
  * @returns
51
54
  */
52
- getAllExistingUserAssignments(userId: string): Promise<UserAssignment[]>;
55
+ getAllExistingUserAssignments(userId: string): Promise<Saved<UserAssignment>[]>;
53
56
  /**
54
57
  * Generate user assignments for all active experiments. Will return any existing and attempt to generate any new assignments.
55
58
  *
@@ -57,7 +60,7 @@ export declare class Abba {
57
60
  * @param segmentationData
58
61
  * @returns
59
62
  */
60
- generateUserAssignments(userId: string, segmentationData: SegmentationData): Promise<UserAssignment[]>;
63
+ generateUserAssignments(userId: string, segmentationData: SegmentationData): Promise<Saved<UserAssignment>[]>;
61
64
  /**
62
65
  * Get assignment statistics for an experiment
63
66
  *
@@ -82,21 +85,4 @@ export declare class Abba {
82
85
  * @returns
83
86
  */
84
87
  private getExistingUserAssignment;
85
- /**
86
- * Update experiment information
87
- *
88
- * @param id
89
- * @param experiment
90
- * @param rules
91
- * @returns
92
- */
93
- private updateExperiment;
94
- /**
95
- * Upserts bucket info
96
- *
97
- * @param id
98
- * @param experiment
99
- * @returns
100
- */
101
- private saveBuckets;
102
88
  }
package/dist/abba.js CHANGED
@@ -1,32 +1,38 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Abba = void 0;
4
- const prisma_output_1 = require("./prisma-output");
4
+ const js_lib_1 = require("@naturalcycles/js-lib");
5
5
  const types_1 = require("./types");
6
6
  const util_1 = require("./util");
7
- // Note: Schema currently contains an output dir which generates all the files to the prisma dir
8
- // it would be tidier not to include it here when possible later on:
9
- // Explanation is here: https://github.com/prisma/prisma/issues/9435#issuecomment-960290681
7
+ const experiment_dao_1 = require("./dao/experiment.dao");
8
+ const userAssignment_dao_1 = require("./dao/userAssignment.dao");
9
+ const bucket_dao_1 = require("./dao/bucket.dao");
10
10
  class Abba {
11
- constructor(dbUrl) {
12
- this.client = new prisma_output_1.PrismaClient({
13
- datasources: {
14
- db: {
15
- url: dbUrl,
16
- },
17
- },
18
- });
11
+ constructor({ db }) {
12
+ this.experimentDao = (0, experiment_dao_1.experimentDao)(db);
13
+ this.bucketDao = (0, bucket_dao_1.bucketDao)(db);
14
+ this.userAssignmentDao = (0, userAssignment_dao_1.userAssignmentDao)(db);
19
15
  }
16
+ // TODO: Cache me
20
17
  /**
21
18
  * Returns all experiments
22
19
  *
23
20
  * @returns
24
21
  */
25
22
  async getAllExperiments(excludeInactive = false) {
26
- return await this.client.experiment.findMany({
27
- where: excludeInactive ? { NOT: { status: types_1.AssignmentStatus.Inactive } } : undefined,
28
- include: { buckets: true },
29
- });
23
+ const query = this.experimentDao.query();
24
+ if (excludeInactive) {
25
+ query.filter('status', '!=', types_1.AssignmentStatus.Inactive);
26
+ }
27
+ const experiments = await this.experimentDao.runQuery(query);
28
+ const buckets = await this.bucketDao
29
+ .query()
30
+ .filter('experimentId', 'in', experiments.map(e => e.id))
31
+ .runQuery();
32
+ return experiments.map(experiment => ({
33
+ ...experiment,
34
+ buckets: buckets.filter(bucket => bucket.experimentId === experiment.id),
35
+ }));
30
36
  }
31
37
  /**
32
38
  * Creates a new experiment
@@ -39,21 +45,11 @@ class Abba {
39
45
  if (experiment.status === types_1.AssignmentStatus.Active) {
40
46
  (0, util_1.validateTotalBucketRatio)(buckets);
41
47
  }
42
- const created = await this.client.experiment.create({
43
- data: {
44
- ...experiment,
45
- rules: experiment.rules,
46
- buckets: {
47
- createMany: {
48
- data: buckets,
49
- },
50
- },
51
- },
52
- include: {
53
- buckets: true,
54
- },
55
- });
56
- return created;
48
+ const created = await this.experimentDao.save(experiment);
49
+ return {
50
+ ...created,
51
+ buckets: await this.bucketDao.saveBatch(buckets.map(b => ({ ...b, experimentId: created.id }))),
52
+ };
57
53
  }
58
54
  /**
59
55
  * Update experiment information, will also validate the buckets ratio if experiment.active is true
@@ -68,11 +64,13 @@ class Abba {
68
64
  if (experiment.status === types_1.AssignmentStatus.Active) {
69
65
  (0, util_1.validateTotalBucketRatio)(buckets);
70
66
  }
71
- const updatedExperiment = await this.updateExperiment(id, experiment);
72
- const updatedBuckets = await this.saveBuckets(buckets);
67
+ const updated = await this.experimentDao.save({
68
+ ...experiment,
69
+ id,
70
+ });
73
71
  return {
74
- ...updatedExperiment,
75
- buckets: updatedBuckets,
72
+ ...updated,
73
+ buckets: await this.bucketDao.saveBatch(buckets.map(b => ({ ...b, experimentId: id }))),
76
74
  };
77
75
  }
78
76
  /**
@@ -81,24 +79,22 @@ class Abba {
81
79
  * @param id
82
80
  */
83
81
  async deleteExperiment(id) {
84
- await this.client.experiment.delete({ where: { id } });
82
+ await this.experimentDao.deleteById(id);
85
83
  }
86
84
  /**
87
85
  * Get an assignment for a given user. If existingOnly is false, it will attempt generate a new assignment
88
86
  *
89
87
  * @param experimentId
90
88
  * @param userId
91
- * @param createNew
92
- * @param segmentationData
89
+ * @param existingOnly Do not generate any new assignments for this experiment
90
+ * @param segmentationData Required if existingOnly is false
93
91
  * @returns
94
92
  */
95
93
  async getUserAssignment(experimentId, userId, existingOnly, segmentationData) {
96
- const experiment = await this.client.experiment.findUnique({
97
- where: { id: experimentId },
98
- include: { buckets: true },
99
- });
94
+ const experiment = await this.experimentDao.requireById(experimentId);
100
95
  if (!experiment)
101
96
  throw new Error('Experiment not found');
97
+ const buckets = await this.bucketDao.getBy('experimentId', experimentId);
102
98
  const existing = await this.getExistingUserAssignment(experimentId, userId);
103
99
  if (existing)
104
100
  return existing;
@@ -106,16 +102,16 @@ class Abba {
106
102
  return null;
107
103
  if (!segmentationData)
108
104
  throw new Error('Segmentation data required when creating a new assignment');
109
- return await this.generateUserAssignment(experiment, userId, segmentationData);
105
+ return await this.generateUserAssignment({ ...experiment, buckets }, userId, segmentationData);
110
106
  }
111
107
  /**
112
108
  * Get all existing user assignments
113
109
  *
114
- * @param userId G
110
+ * @param userId
115
111
  * @returns
116
112
  */
117
113
  async getAllExistingUserAssignments(userId) {
118
- return await this.client.userAssignment.findMany({ where: { userId } });
114
+ return await this.userAssignmentDao.getBy('userId', userId);
119
115
  }
120
116
  /**
121
117
  * Generate user assignments for all active experiments. Will return any existing and attempt to generate any new assignments.
@@ -151,19 +147,16 @@ class Abba {
151
147
  */
152
148
  async getExperimentAssignmentStatistics(experimentId) {
153
149
  const statistics = {
154
- sampled: await this.client.userAssignment.count({ where: { experimentId } }),
150
+ sampled: await this.userAssignmentDao
151
+ .query()
152
+ .filterEq('experimentId', experimentId)
153
+ .runQueryCount(),
155
154
  buckets: {},
156
155
  };
157
- const buckets = await this.client.bucket.findMany({ where: { experimentId } });
158
- const assignmentCounts = await this.client.userAssignment.groupBy({
159
- where: { experimentId },
160
- by: ['bucketId'],
161
- _count: {
162
- _all: true,
163
- },
164
- });
165
- buckets.forEach(({ id }) => {
166
- statistics.buckets[`${id}`] = assignmentCounts.find(i => i.bucketId === id)?._count?._all || 0;
156
+ const buckets = await this.bucketDao.getBy('experimentId', experimentId);
157
+ await (0, js_lib_1.pMap)(buckets, async (bucket) => {
158
+ const count = this.userAssignmentDao.query().filterEq('bucketId', bucket.id);
159
+ statistics[bucket.id] = await this.userAssignmentDao.runQueryCount(count);
167
160
  });
168
161
  return statistics;
169
162
  }
@@ -179,9 +172,10 @@ class Abba {
179
172
  const segmentationMatch = (0, util_1.validateSegmentationRules)(experiment.rules, segmentationData);
180
173
  if (!segmentationMatch)
181
174
  return null;
182
- const bucketId = (0, util_1.determineAssignment)(experiment.sampling, experiment.buckets);
183
- return await this.client.userAssignment.create({
184
- data: { userId, experimentId: experiment.id, bucketId },
175
+ return await this.userAssignmentDao.save({
176
+ userId,
177
+ experimentId: experiment.id,
178
+ bucketId: (0, util_1.determineAssignment)(experiment.sampling, experiment.buckets),
185
179
  });
186
180
  }
187
181
  /**
@@ -192,54 +186,9 @@ class Abba {
192
186
  * @returns
193
187
  */
194
188
  async getExistingUserAssignment(experimentId, userId) {
195
- return await this.client.userAssignment.findFirst({ where: { userId, experimentId } });
196
- }
197
- /**
198
- * Update experiment information
199
- *
200
- * @param id
201
- * @param experiment
202
- * @param rules
203
- * @returns
204
- */
205
- async updateExperiment(id, experiment) {
206
- return await this.client.experiment.update({
207
- where: { id },
208
- data: {
209
- ...experiment,
210
- rules: experiment.rules,
211
- },
212
- });
213
- }
214
- /**
215
- * Upserts bucket info
216
- *
217
- * @param id
218
- * @param experiment
219
- * @returns
220
- */
221
- async saveBuckets(buckets) {
222
- const savedBuckets = [];
223
- for (const bucket of buckets) {
224
- const { id, ...data } = bucket;
225
- if (id) {
226
- savedBuckets.push(this.client.bucket.update({ where: { id }, data }));
227
- }
228
- else {
229
- savedBuckets.push(this.client.bucket.create({
230
- data: {
231
- key: data.key,
232
- ratio: data.ratio,
233
- experiment: {
234
- connect: {
235
- id: data.experimentId,
236
- },
237
- },
238
- },
239
- }));
240
- }
241
- }
242
- return await Promise.all(savedBuckets);
189
+ const assignments = await this.userAssignmentDao.getBy('userId', userId);
190
+ const assignment = assignments.find(assignment => assignment.experimentId === experimentId);
191
+ return assignment || null;
243
192
  }
244
193
  }
245
194
  exports.Abba = Abba;
@@ -0,0 +1,5 @@
1
+ import { CommonDao, CommonDB } from '@naturalcycles/db-lib';
2
+ import { Bucket } from '../types';
3
+ export declare class BucketDao extends CommonDao<Bucket> {
4
+ }
5
+ export declare const bucketDao: (db: CommonDB) => BucketDao;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.bucketDao = exports.BucketDao = void 0;
4
+ const db_lib_1 = require("@naturalcycles/db-lib");
5
+ class BucketDao extends db_lib_1.CommonDao {
6
+ }
7
+ exports.BucketDao = BucketDao;
8
+ const bucketDao = (db) => new BucketDao({
9
+ db,
10
+ table: 'Bucket',
11
+ createId: false,
12
+ idType: 'number',
13
+ assignGeneratedIds: true,
14
+ });
15
+ exports.bucketDao = bucketDao;
@@ -0,0 +1,10 @@
1
+ import { CommonDao, CommonDB } from '@naturalcycles/db-lib';
2
+ import { Saved } from '@naturalcycles/js-lib';
3
+ import { BaseExperiment, Experiment } from '../types';
4
+ declare type ExperimentDBM = Saved<BaseExperiment> & {
5
+ rules: string | null;
6
+ };
7
+ export declare class ExperimentDao extends CommonDao<Experiment, ExperimentDBM> {
8
+ }
9
+ export declare const experimentDao: (db: CommonDB) => ExperimentDao;
10
+ export {};
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.experimentDao = exports.ExperimentDao = void 0;
4
+ const db_lib_1 = require("@naturalcycles/db-lib");
5
+ class ExperimentDao extends db_lib_1.CommonDao {
6
+ }
7
+ exports.ExperimentDao = ExperimentDao;
8
+ const experimentDao = (db) => new ExperimentDao({
9
+ db,
10
+ table: 'Experiment',
11
+ createId: false,
12
+ idType: 'number',
13
+ assignGeneratedIds: true,
14
+ hooks: {
15
+ beforeBMToDBM: bm => ({ ...bm, rules: bm.rules.length ? JSON.stringify(bm.rules) : null }),
16
+ beforeDBMToBM: dbm => ({ ...dbm, rules: dbm.rules && JSON.parse(dbm.rules) }),
17
+ },
18
+ });
19
+ exports.experimentDao = experimentDao;
@@ -0,0 +1,5 @@
1
+ import { CommonDao, CommonDB } from '@naturalcycles/db-lib';
2
+ import { UserAssignment } from '../types';
3
+ export declare class UserAssignmentDao extends CommonDao<UserAssignment> {
4
+ }
5
+ export declare const userAssignmentDao: (db: CommonDB) => UserAssignmentDao;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.userAssignmentDao = exports.UserAssignmentDao = void 0;
4
+ const db_lib_1 = require("@naturalcycles/db-lib");
5
+ class UserAssignmentDao extends db_lib_1.CommonDao {
6
+ }
7
+ exports.UserAssignmentDao = UserAssignmentDao;
8
+ const userAssignmentDao = (db) => new UserAssignmentDao({
9
+ db,
10
+ table: 'UserAssignment',
11
+ createId: false,
12
+ idType: 'number',
13
+ assignGeneratedIds: true,
14
+ });
15
+ exports.userAssignmentDao = userAssignmentDao;
package/dist/index.d.ts CHANGED
@@ -1,3 +1,2 @@
1
- export type { Bucket, Experiment, UserAssignment } from './prisma-output';
2
1
  export * from './types';
3
2
  export { Abba } from './abba';
package/dist/index.js CHANGED
@@ -2,6 +2,6 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Abba = void 0;
4
4
  const tslib_1 = require("tslib");
5
- (0, tslib_1.__exportStar)(require("./types"), exports);
5
+ tslib_1.__exportStar(require("./types"), exports);
6
6
  var abba_1 = require("./abba");
7
7
  Object.defineProperty(exports, "Abba", { enumerable: true, get: function () { return abba_1.Abba; } });
@@ -0,0 +1,47 @@
1
+ -- CreateTable
2
+ CREATE TABLE IF NOT EXISTS `Bucket` (
3
+ `id` INTEGER NOT NULL AUTO_INCREMENT,
4
+ `experimentId` INTEGER NOT NULL,
5
+ `key` VARCHAR(10) NOT NULL,
6
+ `ratio` INTEGER NOT NULL,
7
+ `created` INTEGER(11) NOT NULL,
8
+ `updated` INTEGER(11) NOT NULL,
9
+
10
+ PRIMARY KEY (`id`)
11
+ ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
12
+
13
+ -- CreateTable
14
+ CREATE TABLE IF NOT EXISTS `Experiment` (
15
+ `id` INTEGER NOT NULL AUTO_INCREMENT,
16
+ `name` VARCHAR(191) NOT NULL,
17
+ `status` INTEGER NOT NULL,
18
+ `sampling` INTEGER NOT NULL,
19
+ `description` VARCHAR(240) NULL,
20
+ `created` INTEGER(11) NOT NULL,
21
+ `updated` INTEGER(11) NOT NULL,
22
+ `rules` JSON NULL,
23
+
24
+ PRIMARY KEY (`id`)
25
+ ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
26
+
27
+ -- CreateTable
28
+ CREATE TABLE IF NOT EXISTS `UserAssignment` (
29
+ `id` INTEGER NOT NULL AUTO_INCREMENT,
30
+ `userId` VARCHAR(191) NOT NULL,
31
+ `experimentId` INTEGER NOT NULL,
32
+ `bucketId` INTEGER NULL,
33
+ `created` INTEGER(11) NOT NULL,
34
+ `updated` INTEGER(11) NOT NULL,
35
+
36
+ UNIQUE INDEX `UserAssignment_userId_experimentId_key`(`userId`, `experimentId`),
37
+ PRIMARY KEY (`id`)
38
+ ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
39
+
40
+ -- AddForeignKey
41
+ ALTER TABLE `Bucket` ADD CONSTRAINT `Bucket_experimentId_fkey` FOREIGN KEY (`experimentId`) REFERENCES `Experiment`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
42
+
43
+ -- AddForeignKey
44
+ ALTER TABLE `UserAssignment` ADD CONSTRAINT `UserAssignment_bucketId_fkey` FOREIGN KEY (`bucketId`) REFERENCES `Bucket`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
45
+
46
+ -- AddForeignKey
47
+ ALTER TABLE `UserAssignment` ADD CONSTRAINT `UserAssignment_experimentId_fkey` FOREIGN KEY (`experimentId`) REFERENCES `Experiment`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
package/dist/types.d.ts CHANGED
@@ -1,12 +1,35 @@
1
- import { Bucket, Experiment } from './prisma-output';
2
- export declare type Unsaved<T> = Omit<T, 'createdAt' | 'updatedAt'> & {
3
- id?: number;
1
+ import { CommonDB } from '@naturalcycles/db-lib';
2
+ import { BaseDBEntity, Saved } from '@naturalcycles/js-lib';
3
+ export interface AbbaConfig {
4
+ db: CommonDB;
5
+ }
6
+ export declare type BaseExperiment = BaseDBEntity<number> & {
7
+ name: string;
8
+ status: number;
9
+ sampling: number;
10
+ description: string | null;
11
+ };
12
+ export declare type Experiment = BaseExperiment & {
13
+ rules: SegmentationRule[];
14
+ };
15
+ export declare type ExperimentWithBuckets = Saved<Experiment> & {
16
+ buckets: Saved<Bucket>[];
17
+ };
18
+ export interface BucketInput {
19
+ experimentId: number;
20
+ key: string;
21
+ ratio: number;
22
+ }
23
+ export declare type Bucket = BaseDBEntity<number> & {
24
+ experimentId: number;
25
+ key: string;
26
+ ratio: number;
4
27
  };
5
- export declare type ExperimentWithBuckets = Experiment & {
6
- buckets: Bucket[];
28
+ export declare type UserAssignment = BaseDBEntity<number> & {
29
+ userId: string;
30
+ experimentId: number;
31
+ bucketId: number | null;
7
32
  };
8
- export declare type ExperimentInput = Unsaved<Experiment>;
9
- export declare type BucketInput = Unsaved<Bucket>;
10
33
  export declare type SegmentationData = Record<string, string | boolean | number>;
11
34
  export declare enum AssignmentStatus {
12
35
  Active = 1,
package/dist/util.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { Bucket } from './prisma-output';
2
- import { BucketInput, SegmentationData, SegmentationRule } from '.';
1
+ import { Saved } from '@naturalcycles/js-lib';
2
+ import { Bucket, SegmentationData, SegmentationRule } from './types';
3
3
  /**
4
4
  * Generate a random number between 0 and 100
5
5
  *
@@ -13,21 +13,21 @@ export declare const rollDie: () => number;
13
13
  * @param buckets
14
14
  * @returns
15
15
  */
16
- export declare const determineAssignment: (sampling: number, buckets: Bucket[]) => number | null;
16
+ export declare const determineAssignment: (sampling: number, buckets: Saved<Bucket>[]) => number | null;
17
17
  /**
18
18
  * Determines which bucket a user assignment will recieve
19
19
  *
20
20
  * @param buckets
21
21
  * @returns
22
22
  */
23
- export declare const determineBucket: (buckets: Bucket[]) => number;
23
+ export declare const determineBucket: (buckets: Saved<Bucket>[]) => number;
24
24
  /**
25
25
  * Validate the total ratio of the buckets equals 100
26
26
  *
27
27
  * @param buckets
28
28
  * @returns
29
29
  */
30
- export declare const validateTotalBucketRatio: (buckets: BucketInput[]) => void;
30
+ export declare const validateTotalBucketRatio: (buckets: Bucket[]) => void;
31
31
  /**
32
32
  * Validate a users segmentation data against multiple rules. Returns false if any fail
33
33
  *
package/package.json CHANGED
@@ -1,22 +1,21 @@
1
1
  {
2
2
  "name": "@naturalcycles/abba",
3
- "version": "1.6.0",
3
+ "version": "1.9.0",
4
4
  "scripts": {
5
5
  "prepare": "husky install",
6
- "build": "build && npm run copy-prisma-output",
7
- "build-prod": "build-prod && npm run copy-prisma-output",
8
- "copy-prisma-output": "cp -R src/prisma-output dist"
6
+ "build": "build",
7
+ "build-prod": "build-prod"
9
8
  },
10
9
  "dependencies": {
11
- "@prisma/client": "^3.9.2",
10
+ "@naturalcycles/db-lib": "^8.40.1",
11
+ "@naturalcycles/js-lib": "^14.98.2",
12
12
  "semver": "^7.3.5"
13
13
  },
14
14
  "devDependencies": {
15
- "@naturalcycles/dev-lib": "^12.0.0",
15
+ "@naturalcycles/dev-lib": "^12.19.2",
16
16
  "@types/node": "^16.0.0",
17
17
  "@types/semver": "^7.3.9",
18
- "jest": "^27.5.1",
19
- "prisma": "^3.9.2"
18
+ "jest": "^27.5.1"
20
19
  },
21
20
  "files": [
22
21
  "dist",
package/readme.md CHANGED
@@ -44,7 +44,7 @@
44
44
 
45
45
  ### Built With
46
46
 
47
- - [Prisma](https://www.prisma.io/)
47
+ - [@naturalcycles/db-lib](https://github.com/NaturalCycles/db-lib)
48
48
 
49
49
  <p align="right">(<a href="#top">back to top</a>)</p>
50
50
 
@@ -77,9 +77,8 @@ 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
81
- [sql script found here](https://github.com/NaturalCycles/abba/blob/master/prisma/migrations/20220218075343_init/migration.sql)
82
- to generate the required DB Schema
80
+ 2. Install the schema into your MySQL db instance using the migration script found
81
+ [here](https://github.com/NaturalCycles/abba/blob/master/src/migrations/init.sql).
83
82
 
84
83
  <p align="right">(<a href="#top">back to top</a>)</p>
85
84
 
@@ -91,14 +90,14 @@ This template doesn't rely on any external dependencies or services._
91
90
 
92
91
  ### Create an instance of Abba
93
92
 
94
- Creates an instance of Abba. You can pass in the database url in the constructor. If it does not
95
- exist it will fallback to trying to use the `ABBA_DB_URL` which must be added to your environment
96
- variables.
93
+ (Currently supports MySQL, probably all DocumentDBs but not verified.)
97
94
 
98
95
  ```js
99
- const abba = new Abba('url')
100
- // or reading from process.env.ABBA_DB_URL
101
- const abba = new Abba()
96
+ type AbbaConfig = {
97
+ db: CommonDB // from @naturalcycles/db-lib
98
+ }
99
+
100
+ const abba = new Abba(config: AbbaConfig)
102
101
  ```
103
102
 
104
103
  ### Create a new experiment
@@ -109,7 +108,7 @@ Creates a new experiment
109
108
  async createExperiment(
110
109
  input: ExperimentInput,
111
110
  buckets: BucketInput[]
112
- ): Promise<Experiment>
111
+ ): Promise<Saved<Experiment>>
113
112
  ```
114
113
 
115
114
  ### Update an experiment
@@ -121,7 +120,7 @@ async updateExperiment(
121
120
  id: number,
122
121
  input: ExperimentInput,
123
122
  buckets: BucketInput[]
124
- ): Promise<Experiment>
123
+ ): Promise<Saved<Experiment>>
125
124
  ```
126
125
 
127
126
  ### Delete an experiment
@@ -141,7 +140,7 @@ Gets all existing user assignments
141
140
  ```js
142
141
  async getAllExistingUserAssignments(
143
142
  userId: string
144
- ): Promise<UserAssignment[]>
143
+ ): Promise<Saved<UserAssignment>[]>
145
144
  ```
146
145
 
147
146
  ### Get a users assignment
@@ -155,7 +154,7 @@ async getUserAssignment(
155
154
  userId: string,
156
155
  existingOnly: boolean,
157
156
  segmentationData?: SegmentationData,
158
- ): Promise<UserAssignment | null>
157
+ ): Promise<Saved<UserAssignment> | null>
159
158
  ```
160
159
 
161
160
  ### Generate user assignments
@@ -167,7 +166,7 @@ attempt to generate new assignments.
167
166
  async generateUserAssignments(
168
167
  userId: string,
169
168
  segmentationData: SegmentationData,
170
- ): Promise<UserAssignment[]>
169
+ ): Promise<Saved<UserAssignment>[]>
171
170
  ```
172
171
 
173
172
  ### Getting assignment statistics