@zykeco/sync-server 0.4.0 → 0.5.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/db/schema.d.ts +1009 -0
- package/dist/db/schema.js +80 -1
- package/dist/db/schema.js.map +1 -1
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -1
- package/dist/routes/daily-stress-burden.d.ts +3 -0
- package/dist/routes/daily-stress-burden.js +24 -0
- package/dist/routes/daily-stress-burden.js.map +1 -0
- package/dist/routes/heart-rate-minute.d.ts +3 -0
- package/dist/routes/heart-rate-minute.js +24 -0
- package/dist/routes/heart-rate-minute.js.map +1 -0
- package/dist/routes/hr-zone-history.d.ts +3 -0
- package/dist/routes/hr-zone-history.js +24 -0
- package/dist/routes/hr-zone-history.js.map +1 -0
- package/dist/routes/user-profile.d.ts +3 -0
- package/dist/routes/user-profile.js +24 -0
- package/dist/routes/user-profile.js.map +1 -0
- package/dist/routes/user-timezones.d.ts +3 -0
- package/dist/routes/user-timezones.js +24 -0
- package/dist/routes/user-timezones.js.map +1 -0
- package/dist/routes/wipe.d.ts +6 -1
- package/dist/routes/wipe.js +16 -2
- package/dist/routes/wipe.js.map +1 -1
- package/dist/stores/daily-stress-burden.d.ts +3 -0
- package/dist/stores/daily-stress-burden.js +58 -0
- package/dist/stores/daily-stress-burden.js.map +1 -0
- package/dist/stores/heart-rate-minute.d.ts +3 -0
- package/dist/stores/heart-rate-minute.js +48 -0
- package/dist/stores/heart-rate-minute.js.map +1 -0
- package/dist/stores/hr-zone-history.d.ts +3 -0
- package/dist/stores/hr-zone-history.js +49 -0
- package/dist/stores/hr-zone-history.js.map +1 -0
- package/dist/stores/user-profile.d.ts +3 -0
- package/dist/stores/user-profile.js +76 -0
- package/dist/stores/user-profile.js.map +1 -0
- package/dist/stores/user-timezones.d.ts +3 -0
- package/dist/stores/user-timezones.js +43 -0
- package/dist/stores/user-timezones.js.map +1 -0
- package/drizzle/0001_sweet_firebird.sql +78 -0
- package/drizzle/meta/0001_snapshot.json +733 -0
- package/drizzle/meta/_journal.json +7 -0
- package/package.json +3 -3
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { inArray, sql } from 'drizzle-orm';
|
|
2
|
+
import { userProfile } from '../db/schema.js';
|
|
3
|
+
export function createUserProfileStore(db) {
|
|
4
|
+
return {
|
|
5
|
+
async upsertBatch(rows, _serverNowMs) {
|
|
6
|
+
if (rows.length === 0)
|
|
7
|
+
return [];
|
|
8
|
+
const values = rows.map((r) => ({
|
|
9
|
+
id: r.id,
|
|
10
|
+
name: r.name,
|
|
11
|
+
birthDate: r.birthDate,
|
|
12
|
+
height: r.height,
|
|
13
|
+
weight: r.weight,
|
|
14
|
+
biologicalGender: r.biologicalGender,
|
|
15
|
+
maxHeartRate: r.maxHeartRate,
|
|
16
|
+
maxHeartRateManually: r.maxHeartRateManually,
|
|
17
|
+
restingHeartRate: r.restingHeartRate,
|
|
18
|
+
vo2Max: r.vo2Max,
|
|
19
|
+
heartRateZonesManually: r.heartRateZonesManually,
|
|
20
|
+
hrZone1: r.hrZone1,
|
|
21
|
+
hrZone2: r.hrZone2,
|
|
22
|
+
hrZone3: r.hrZone3,
|
|
23
|
+
hrZone4: r.hrZone4,
|
|
24
|
+
hrZone5: r.hrZone5,
|
|
25
|
+
trainingBackground: r.trainingBackground,
|
|
26
|
+
typicalDay: r.typicalDay,
|
|
27
|
+
sleepGoalMinutes: r.sleepGoalMinutes,
|
|
28
|
+
dataRetentionLevel: r.dataRetentionLevel,
|
|
29
|
+
createdAt: r.createdAt,
|
|
30
|
+
updatedAt: r.updatedAt,
|
|
31
|
+
}));
|
|
32
|
+
await db
|
|
33
|
+
.insert(userProfile)
|
|
34
|
+
.values(values)
|
|
35
|
+
.onConflictDoUpdate({
|
|
36
|
+
target: userProfile.id,
|
|
37
|
+
set: {
|
|
38
|
+
name: sql `excluded.name`,
|
|
39
|
+
birthDate: sql `excluded.birth_date`,
|
|
40
|
+
height: sql `excluded.height`,
|
|
41
|
+
weight: sql `excluded.weight`,
|
|
42
|
+
biologicalGender: sql `excluded.biological_gender`,
|
|
43
|
+
maxHeartRate: sql `excluded.max_heart_rate`,
|
|
44
|
+
maxHeartRateManually: sql `excluded.max_heart_rate_manually`,
|
|
45
|
+
restingHeartRate: sql `excluded.resting_heart_rate`,
|
|
46
|
+
vo2Max: sql `excluded.vo2_max`,
|
|
47
|
+
heartRateZonesManually: sql `excluded.heart_rate_zones_manually`,
|
|
48
|
+
hrZone1: sql `excluded.hr_zone_1`,
|
|
49
|
+
hrZone2: sql `excluded.hr_zone_2`,
|
|
50
|
+
hrZone3: sql `excluded.hr_zone_3`,
|
|
51
|
+
hrZone4: sql `excluded.hr_zone_4`,
|
|
52
|
+
hrZone5: sql `excluded.hr_zone_5`,
|
|
53
|
+
trainingBackground: sql `excluded.training_background`,
|
|
54
|
+
typicalDay: sql `excluded.typical_day`,
|
|
55
|
+
sleepGoalMinutes: sql `excluded.sleep_goal_minutes`,
|
|
56
|
+
dataRetentionLevel: sql `excluded.data_retention_level`,
|
|
57
|
+
createdAt: sql `excluded.created_at`,
|
|
58
|
+
updatedAt: sql `excluded.updated_at`,
|
|
59
|
+
},
|
|
60
|
+
where: sql `excluded.updated_at > ${userProfile.updatedAt}`,
|
|
61
|
+
});
|
|
62
|
+
return rows.map((r) => r.id);
|
|
63
|
+
},
|
|
64
|
+
async deleteBatch(ids) {
|
|
65
|
+
if (ids.length === 0)
|
|
66
|
+
return [];
|
|
67
|
+
await db.delete(userProfile).where(inArray(userProfile.id, [...ids]));
|
|
68
|
+
return [...ids];
|
|
69
|
+
},
|
|
70
|
+
async wipeAll() {
|
|
71
|
+
const result = await db.delete(userProfile);
|
|
72
|
+
return result.rowsAffected;
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=user-profile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"user-profile.js","sourceRoot":"","sources":["../../src/stores/user-profile.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { inArray, sql } from 'drizzle-orm';
|
|
2
|
+
import { userTimezones } from '../db/schema.js';
|
|
3
|
+
export function createUserTimezonesStore(db) {
|
|
4
|
+
return {
|
|
5
|
+
async upsertBatch(rows, _serverNowMs) {
|
|
6
|
+
if (rows.length === 0)
|
|
7
|
+
return [];
|
|
8
|
+
const values = rows.map((r) => ({
|
|
9
|
+
id: r.id,
|
|
10
|
+
timezone: r.timezone,
|
|
11
|
+
type: r.type,
|
|
12
|
+
utcOffsetMinutes: r.utcOffsetMinutes,
|
|
13
|
+
effectiveFrom: r.effectiveFrom,
|
|
14
|
+
}));
|
|
15
|
+
await db
|
|
16
|
+
.insert(userTimezones)
|
|
17
|
+
.values(values)
|
|
18
|
+
.onConflictDoUpdate({
|
|
19
|
+
target: userTimezones.id,
|
|
20
|
+
set: {
|
|
21
|
+
timezone: sql `excluded.timezone`,
|
|
22
|
+
type: sql `excluded.type`,
|
|
23
|
+
utcOffsetMinutes: sql `excluded.utc_offset_minutes`,
|
|
24
|
+
effectiveFrom: sql `excluded.effective_from`,
|
|
25
|
+
},
|
|
26
|
+
// LWW on effectiveFrom (table is append-only; no updatedAt)
|
|
27
|
+
where: sql `excluded.effective_from > ${userTimezones.effectiveFrom}`,
|
|
28
|
+
});
|
|
29
|
+
return rows.map((r) => r.id);
|
|
30
|
+
},
|
|
31
|
+
async deleteBatch(ids) {
|
|
32
|
+
if (ids.length === 0)
|
|
33
|
+
return [];
|
|
34
|
+
await db.delete(userTimezones).where(inArray(userTimezones.id, [...ids]));
|
|
35
|
+
return [...ids];
|
|
36
|
+
},
|
|
37
|
+
async wipeAll() {
|
|
38
|
+
const result = await db.delete(userTimezones);
|
|
39
|
+
return result.rowsAffected;
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=user-timezones.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"user-timezones.js","sourceRoot":"","sources":["../../src/stores/user-timezones.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAG3C,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD,MAAM,UAAU,wBAAwB,CAAC,EAAM;IAC7C,OAAO;QACL,KAAK,CAAC,WAAW,CAAC,IAAkC,EAAE,YAAoB;YACxE,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,EAAE,CAAC;YACjC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBAC9B,EAAE,EAAE,CAAC,CAAC,EAAE;gBACR,QAAQ,EAAE,CAAC,CAAC,QAAQ;gBACpB,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,gBAAgB,EAAE,CAAC,CAAC,gBAAgB;gBACpC,aAAa,EAAE,CAAC,CAAC,aAAa;aAC/B,CAAC,CAAC,CAAC;YACJ,MAAM,EAAE;iBACL,MAAM,CAAC,aAAa,CAAC;iBACrB,MAAM,CAAC,MAAM,CAAC;iBACd,kBAAkB,CAAC;gBAClB,MAAM,EAAE,aAAa,CAAC,EAAE;gBACxB,GAAG,EAAE;oBACH,QAAQ,EAAE,GAAG,CAAA,mBAAmB;oBAChC,IAAI,EAAE,GAAG,CAAA,eAAe;oBACxB,gBAAgB,EAAE,GAAG,CAAA,6BAA6B;oBAClD,aAAa,EAAE,GAAG,CAAA,yBAAyB;iBAC5C;gBACD,4DAA4D;gBAC5D,KAAK,EAAE,GAAG,CAAA,6BAA6B,aAAa,CAAC,aAAa,EAAE;aACrE,CAAC,CAAC;YACL,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC/B,CAAC;QAED,KAAK,CAAC,WAAW,CAAC,GAAsB;YACtC,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,EAAE,CAAC;YAChC,MAAM,EAAE,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,aAAa,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;YAC1E,OAAO,CAAC,GAAG,GAAG,CAAC,CAAC;QAClB,CAAC;QAED,KAAK,CAAC,OAAO;YACX,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;YAC9C,OAAO,MAAM,CAAC,YAAY,CAAC;QAC7B,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
CREATE TABLE `daily_stress_burden` (
|
|
2
|
+
`id` integer PRIMARY KEY NOT NULL,
|
|
3
|
+
`iso_date` text NOT NULL,
|
|
4
|
+
`timezone` text NOT NULL,
|
|
5
|
+
`intervals_relaxed` integer NOT NULL,
|
|
6
|
+
`intervals_balanced` integer NOT NULL,
|
|
7
|
+
`intervals_elevated` integer NOT NULL,
|
|
8
|
+
`intervals_high` integer NOT NULL,
|
|
9
|
+
`intervals_scored` integer NOT NULL,
|
|
10
|
+
`mean_score` real NOT NULL,
|
|
11
|
+
`peak_score` real NOT NULL,
|
|
12
|
+
`peak_score_utc` integer NOT NULL,
|
|
13
|
+
`stress_burden` real NOT NULL,
|
|
14
|
+
`updated_at` integer NOT NULL
|
|
15
|
+
);
|
|
16
|
+
--> statement-breakpoint
|
|
17
|
+
CREATE UNIQUE INDEX `dsb_unique_date_idx` ON `daily_stress_burden` (`iso_date`);--> statement-breakpoint
|
|
18
|
+
CREATE TABLE `heart_rate_minute` (
|
|
19
|
+
`id` integer PRIMARY KEY NOT NULL,
|
|
20
|
+
`minute_start_utc` integer NOT NULL,
|
|
21
|
+
`bpm_mean` real NOT NULL,
|
|
22
|
+
`bpm_min` integer NOT NULL,
|
|
23
|
+
`bpm_max` integer NOT NULL,
|
|
24
|
+
`sample_count` integer NOT NULL,
|
|
25
|
+
`device_id` integer NOT NULL,
|
|
26
|
+
`updated_at` integer NOT NULL
|
|
27
|
+
);
|
|
28
|
+
--> statement-breakpoint
|
|
29
|
+
CREATE INDEX `hrm_minute_idx` ON `heart_rate_minute` (`minute_start_utc`);--> statement-breakpoint
|
|
30
|
+
CREATE UNIQUE INDEX `hrm_unique_minute_per_device_idx` ON `heart_rate_minute` (`minute_start_utc`,`device_id`);--> statement-breakpoint
|
|
31
|
+
CREATE INDEX `hrm_device_updated_idx` ON `heart_rate_minute` (`device_id`,`updated_at`);--> statement-breakpoint
|
|
32
|
+
CREATE TABLE `hr_zone_history` (
|
|
33
|
+
`id` integer PRIMARY KEY NOT NULL,
|
|
34
|
+
`effective_from_iso_date` text NOT NULL,
|
|
35
|
+
`zone1` integer NOT NULL,
|
|
36
|
+
`zone2` integer NOT NULL,
|
|
37
|
+
`zone3` integer NOT NULL,
|
|
38
|
+
`zone4` integer NOT NULL,
|
|
39
|
+
`zone5` integer NOT NULL,
|
|
40
|
+
`created_at` integer NOT NULL
|
|
41
|
+
);
|
|
42
|
+
--> statement-breakpoint
|
|
43
|
+
CREATE UNIQUE INDEX `hrzh_unique_effective_idx` ON `hr_zone_history` (`effective_from_iso_date`);--> statement-breakpoint
|
|
44
|
+
CREATE TABLE `user_profile` (
|
|
45
|
+
`id` integer PRIMARY KEY NOT NULL,
|
|
46
|
+
`name` text NOT NULL,
|
|
47
|
+
`birth_date` text NOT NULL,
|
|
48
|
+
`height` real NOT NULL,
|
|
49
|
+
`weight` real NOT NULL,
|
|
50
|
+
`biological_gender` text NOT NULL,
|
|
51
|
+
`max_heart_rate` integer,
|
|
52
|
+
`max_heart_rate_manually` integer,
|
|
53
|
+
`resting_heart_rate` integer,
|
|
54
|
+
`vo2_max` real,
|
|
55
|
+
`heart_rate_zones_manually` integer,
|
|
56
|
+
`hr_zone_1` integer,
|
|
57
|
+
`hr_zone_2` integer,
|
|
58
|
+
`hr_zone_3` integer,
|
|
59
|
+
`hr_zone_4` integer,
|
|
60
|
+
`hr_zone_5` integer,
|
|
61
|
+
`training_background` text,
|
|
62
|
+
`typical_day` text,
|
|
63
|
+
`sleep_goal_minutes` integer,
|
|
64
|
+
`data_retention_level` text,
|
|
65
|
+
`created_at` integer NOT NULL,
|
|
66
|
+
`updated_at` integer NOT NULL,
|
|
67
|
+
CONSTRAINT "user_profile_singleton" CHECK("user_profile"."id" = 1)
|
|
68
|
+
);
|
|
69
|
+
--> statement-breakpoint
|
|
70
|
+
CREATE TABLE `user_timezones` (
|
|
71
|
+
`id` integer PRIMARY KEY NOT NULL,
|
|
72
|
+
`timezone` text NOT NULL,
|
|
73
|
+
`type` text NOT NULL,
|
|
74
|
+
`utc_offset_minutes` integer NOT NULL,
|
|
75
|
+
`effective_from` integer NOT NULL
|
|
76
|
+
);
|
|
77
|
+
--> statement-breakpoint
|
|
78
|
+
CREATE INDEX `user_tz_effective_from_idx` ON `user_timezones` (`effective_from`);
|