@shaxpir/duiduidui-models 1.5.2 → 1.5.3

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.
@@ -1,8 +1,8 @@
1
- import { MultiTime } from "@shaxpir/shaxpir-common";
1
+ import { CompactDateTime } from "@shaxpir/shaxpir-common";
2
2
  export type ReviewResult = 'FAIL' | 'HARD' | 'GOOD' | 'EASY';
3
3
  export interface ReviewLike {
4
4
  result: ReviewResult;
5
- at: MultiTime;
5
+ at_utc_time: CompactDateTime;
6
6
  }
7
7
  export interface Review extends ReviewLike {
8
8
  text: string;
@@ -3,7 +3,6 @@ import { MultiTime } from "@shaxpir/shaxpir-common";
3
3
  import { ShareSync } from '../repo';
4
4
  import { Content, ContentBody, ContentId, ContentMeta, ContentRef } from "./Content";
5
5
  import { Review } from './Review';
6
- import { ArrayView } from './ArrayView';
7
6
  export interface SessionPayload {
8
7
  start: MultiTime;
9
8
  end: MultiTime;
@@ -11,6 +10,7 @@ export interface SessionPayload {
11
10
  device_id: ContentId;
12
11
  duration_minutes: number;
13
12
  reviews: Review[];
13
+ review_count: number;
14
14
  }
15
15
  export interface SessionBody extends ContentBody {
16
16
  meta: ContentMeta;
@@ -29,7 +29,8 @@ export declare class Session extends Content {
29
29
  get tzOffset(): number;
30
30
  get durationMinutes(): number;
31
31
  get deviceId(): ContentId;
32
- get reviews(): ArrayView<Review>;
33
- modelUpdated(): Promise<void>;
32
+ get reviews(): Review[];
33
+ get reviewCount(): number;
34
34
  addReview(review: Review): void;
35
+ modelUpdated(): Promise<void>;
35
36
  }
@@ -3,12 +3,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Session = void 0;
4
4
  const shaxpir_common_1 = require("@shaxpir/shaxpir-common");
5
5
  const repo_1 = require("../repo");
6
+ const ArrayView_1 = require("./ArrayView");
6
7
  const Content_1 = require("./Content");
7
8
  const ContentKind_1 = require("./ContentKind");
8
9
  const Metric_1 = require("./Metric");
9
10
  const Operation_1 = require("./Operation");
10
11
  const Workspace_1 = require("./Workspace");
11
- const ArrayView_1 = require("./ArrayView");
12
12
  class Session extends Content_1.Content {
13
13
  constructor(doc, shouldAcquire, shareSync) {
14
14
  super(doc, shouldAcquire, shareSync);
@@ -40,7 +40,8 @@ class Session extends Content_1.Content {
40
40
  tz_offset: (new Date()).getTimezoneOffset(),
41
41
  duration_minutes: 0,
42
42
  device_id: deviceId,
43
- reviews: []
43
+ reviews: [],
44
+ review_count: 0
44
45
  }
45
46
  });
46
47
  }
@@ -79,20 +80,41 @@ class Session extends Content_1.Content {
79
80
  this.checkDisposed("Session.deviceId");
80
81
  return this.payload.device_id;
81
82
  }
83
+ // NOTE: We are not offering a getter for the `_reviewsView` because ArrayView offers its own mutator
84
+ // methods (push, etc), and we don't want to circumvent the `addReview` method, which has important
85
+ // constraints and side effects.
82
86
  get reviews() {
83
- this.checkDisposed("Session.reviews");
84
- return this._reviewsView;
87
+ this.checkDisposed("Session.getReviews");
88
+ return this._reviewsView.values;
89
+ }
90
+ get reviewCount() {
91
+ this.checkDisposed("Session.getReviewCount");
92
+ return this._reviewsView.length;
93
+ }
94
+ addReview(review) {
95
+ this.checkDisposed("Session.addReview");
96
+ if (review.hasOwnProperty('context') && review.hasOwnProperty('weight')) {
97
+ throw new Error("Implied reviews cannot be added to a Session");
98
+ }
99
+ this._reviewsView.push({
100
+ text: review.text,
101
+ sense_rank: review.sense_rank,
102
+ result: review.result,
103
+ at_utc_time: review.at_utc_time
104
+ });
105
+ const batch = new Operation_1.BatchOperation(this);
106
+ batch.setPathValue(['payload', 'review_count'], this._reviewsView.length);
107
+ batch.commit();
85
108
  }
86
109
  async modelUpdated() {
87
110
  this.checkDisposed("Session.modelUpdated");
88
111
  await super.modelUpdated();
89
112
  const shareSync = this.shareSync;
90
- const sessionId = this.id;
91
113
  const userId = this.owner;
92
114
  const date = shaxpir_common_1.Time.dateFrom(this.createdAt.local_time);
93
115
  const workspaceId = Workspace_1.Workspace.makeWorkspaceId(userId);
94
116
  const workspace = await this.shareSync.acquire(ContentKind_1.ContentKind.WORKSPACE, workspaceId);
95
- const sessionsOnDate = await workspace.acquireSessionsFromDate(sessionId, date);
117
+ const sessionsOnDate = await workspace.acquireSessionsFromDate(date);
96
118
  workspace.release();
97
119
  let minutesStudyingOnDate = 0;
98
120
  let reviewCountOnDate = 0;
@@ -113,9 +135,5 @@ class Session extends Content_1.Content {
113
135
  reviewCountMetric.setDateAmount(date, reviewCountOnDate);
114
136
  reviewCountMetric.release();
115
137
  }
116
- addReview(review) {
117
- this.checkDisposed("Session.addReview");
118
- this._reviewsView.push(review);
119
- }
120
138
  }
121
139
  exports.Session = Session;
@@ -1,10 +1,10 @@
1
1
  import { Doc } from '@shaxpir/sharedb/lib/client';
2
2
  import { CompactDateTime } from "@shaxpir/shaxpir-common";
3
+ import { ShareSync } from '../repo';
3
4
  import { BayesianScore } from './BayesianScore';
4
5
  import { Content, ContentBody, ContentId, ContentMeta } from "./Content";
5
6
  import { BuiltInPhrase, Phrase, PhraseExample } from './Phrase';
6
- import { ReviewLike } from "./Review";
7
- import { ShareSync } from '../repo';
7
+ import { ImpliedReview, ReviewLike } from "./Review";
8
8
  export interface TermSummary {
9
9
  text: string;
10
10
  sense_rank: number;
@@ -16,6 +16,7 @@ export interface TermSummary {
16
16
  theta: number;
17
17
  uncertainty: number;
18
18
  review_count: number;
19
+ implied_review_count: number;
19
20
  last_review_utc: CompactDateTime;
20
21
  }
21
22
  export interface TermPayload extends BayesianScore {
@@ -32,6 +33,8 @@ export interface TermPayload extends BayesianScore {
32
33
  reviews: ReviewLike[];
33
34
  review_count: number;
34
35
  last_review_utc: CompactDateTime;
36
+ implied_reviews: ImpliedReview[];
37
+ implied_review_count: number;
35
38
  hanzi_count?: number;
36
39
  pinyin?: string;
37
40
  pinyin_tokenized?: string;
@@ -49,23 +52,26 @@ export interface TermBody extends ContentBody {
49
52
  export declare class Term extends Content {
50
53
  static makeTermId(userId: ContentId, text: string, senseRank: number): ContentId;
51
54
  private _reviewsView;
55
+ private _impliedReviewsView;
52
56
  constructor(doc: Doc, shouldAcquire: boolean, shareSync: ShareSync);
53
57
  static forUserPhrase(userId: ContentId, text: string, senseRank: number, difficulty: number, phraseId?: number): Term;
54
58
  static forUserPhrase(userId: ContentId, phrase: Phrase): Term;
55
59
  static forBuiltinPhrase(userId: ContentId, phrase: BuiltInPhrase): Term;
56
60
  get payload(): TermPayload;
57
- getText(): string;
58
- getSenseRank(): number;
59
- getDifficulty(): number;
60
- getAlpha(): number;
61
- getBeta(): number;
62
- getTheta(): number;
63
- getUncertainty(): number;
64
- getReviews(): ReviewLike[];
65
- getStarredAt(): CompactDateTime | null;
61
+ get text(): string;
62
+ get senseRank(): number;
63
+ get difficulty(): number;
64
+ get alpha(): number;
65
+ get beta(): number;
66
+ get theta(): number;
67
+ get uncertainty(): number;
68
+ get starredAt(): CompactDateTime | null;
69
+ get lastReviewUtc(): CompactDateTime | null;
66
70
  setStarredAt(value: CompactDateTime | null): void;
67
71
  updateBayesianScore(alpha: number, beta: number, theta: number): void;
72
+ get reviews(): ReviewLike[];
73
+ get impliedReviews(): ImpliedReview[];
74
+ get reviewCount(): number;
75
+ get impliedReviewCount(): number;
68
76
  addReview(review: ReviewLike): void;
69
- getReviewCount(): number;
70
- getLastReviewUtc(): CompactDateTime | null;
71
77
  }
@@ -2,12 +2,12 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Term = void 0;
4
4
  const shaxpir_common_1 = require("@shaxpir/shaxpir-common");
5
+ const repo_1 = require("../repo");
6
+ const ArrayView_1 = require("./ArrayView");
5
7
  const BayesianScore_1 = require("./BayesianScore");
6
8
  const Content_1 = require("./Content");
7
9
  const ContentKind_1 = require("./ContentKind");
8
- const repo_1 = require("../repo");
9
10
  const Operation_1 = require("./Operation");
10
- const ArrayView_1 = require("./ArrayView");
11
11
  class Term extends Content_1.Content {
12
12
  static makeTermId(userId, text, senseRank) {
13
13
  return shaxpir_common_1.CachingHasher.makeMd5Base62Hash(`${ContentKind_1.ContentKind.TERM}-${userId}-${text}-${senseRank}`);
@@ -15,6 +15,7 @@ class Term extends Content_1.Content {
15
15
  constructor(doc, shouldAcquire, shareSync) {
16
16
  super(doc, shouldAcquire, shareSync);
17
17
  this._reviewsView = new ArrayView_1.ArrayView(this, ['payload', 'reviews']);
18
+ this._impliedReviewsView = new ArrayView_1.ArrayView(this, ['payload', 'implied_reviews']);
18
19
  }
19
20
  static forUserPhrase(userId, textOrPhrase, senseRank, difficulty, phraseId) {
20
21
  const now = shaxpir_common_1.ClockService.getClock().now();
@@ -71,7 +72,9 @@ class Term extends Content_1.Content {
71
72
  uncertainty: BayesianScore_1.BayesianScoreModel.calculateUncertainty(0.5, 0.5),
72
73
  reviews: [],
73
74
  review_count: 0,
74
- last_review_utc: null
75
+ last_review_utc: null,
76
+ implied_reviews: [],
77
+ implied_review_count: 0,
75
78
  }
76
79
  });
77
80
  }
@@ -100,7 +103,9 @@ class Term extends Content_1.Content {
100
103
  uncertainty: BayesianScore_1.BayesianScoreModel.calculateUncertainty(0.5, 0.5),
101
104
  reviews: [],
102
105
  review_count: 0,
103
- last_review_utc: null
106
+ last_review_utc: null,
107
+ implied_reviews: [],
108
+ implied_review_count: 0,
104
109
  }
105
110
  });
106
111
  }
@@ -108,42 +113,42 @@ class Term extends Content_1.Content {
108
113
  this.checkDisposed("Term.payload");
109
114
  return this.doc.data.payload;
110
115
  }
111
- getText() {
112
- this.checkDisposed("Term.getText");
116
+ get text() {
117
+ this.checkDisposed("Term.text");
113
118
  return this.payload.text;
114
119
  }
115
- getSenseRank() {
116
- this.checkDisposed("Term.getSenseRank");
120
+ get senseRank() {
121
+ this.checkDisposed("Term.senseRank");
117
122
  return this.payload.sense_rank;
118
123
  }
119
- getDifficulty() {
120
- this.checkDisposed("Term.getDifficulty");
124
+ get difficulty() {
125
+ this.checkDisposed("Term.difficulty");
121
126
  return this.payload.difficulty;
122
127
  }
123
- getAlpha() {
124
- this.checkDisposed("Term.getAlpha");
128
+ get alpha() {
129
+ this.checkDisposed("Term.alpha");
125
130
  return this.payload.alpha;
126
131
  }
127
- getBeta() {
128
- this.checkDisposed("Term.getBeta");
132
+ get beta() {
133
+ this.checkDisposed("Term.beta");
129
134
  return this.payload.beta;
130
135
  }
131
- getTheta() {
132
- this.checkDisposed("Term.getTheta");
136
+ get theta() {
137
+ this.checkDisposed("Term.theta");
133
138
  return this.payload.theta;
134
139
  }
135
- getUncertainty() {
136
- this.checkDisposed("Term.getUncertainty");
140
+ get uncertainty() {
141
+ this.checkDisposed("Term.uncertainty");
137
142
  return this.payload.uncertainty;
138
143
  }
139
- getReviews() {
140
- this.checkDisposed("Term.getReviews");
141
- return this.payload.reviews;
142
- }
143
- getStarredAt() {
144
- this.checkDisposed("Term.getStarredAt");
144
+ get starredAt() {
145
+ this.checkDisposed("Term.starredAt");
145
146
  return this.payload.starred_at;
146
147
  }
148
+ get lastReviewUtc() {
149
+ this.checkDisposed("Term.lastReviewUtc");
150
+ return this.payload.last_review_utc;
151
+ }
147
152
  setStarredAt(value) {
148
153
  this.checkDisposed("Term.setStarredAt");
149
154
  if (this.payload.starred_at !== value) {
@@ -161,34 +166,56 @@ class Term extends Content_1.Content {
161
166
  batch.setPathValue(['payload', 'uncertainty'], BayesianScore_1.BayesianScoreModel.calculateUncertainty(alpha, beta));
162
167
  batch.commit();
163
168
  }
169
+ // NOTE: We are not offering a getter for the `_reviewsView` because ArrayView offers its own mutator
170
+ // methods (push, etc), and we don't want to circumvent the `addReview` method, which has important
171
+ // constraints and side effects.
172
+ get reviews() {
173
+ this.checkDisposed("Session.reviews");
174
+ return this._reviewsView.values;
175
+ }
176
+ // NOTE: We are not offering a getter for the `_impliedReviewsView` because ArrayView offers its own
177
+ // mutator methods (push, etc), and we don't want to circumvent the `addReview` method, which has
178
+ // important constraints and side effects.
179
+ get impliedReviews() {
180
+ this.checkDisposed("Term.impliedReviews");
181
+ return this._impliedReviewsView.values;
182
+ }
183
+ get reviewCount() {
184
+ this.checkDisposed("Term.reviewCount");
185
+ return this.payload.review_count;
186
+ }
187
+ get impliedReviewCount() {
188
+ this.checkDisposed("Term.impliedReviewCount");
189
+ return this.payload.implied_review_count;
190
+ }
191
+ // Add either an implied or explicit review
164
192
  addReview(review) {
165
193
  this.checkDisposed("Term.addReview");
166
- this._reviewsView.push(review);
167
- // Count reviews again.
168
- let reviewCount = 0;
169
- let lastReviewUtc = null;
170
- this._reviewsView.forEach((idx, r) => {
171
- // We only count *actual* reviews, not implied reviews...
172
- if (!r.hasOwnProperty('context') && !r.hasOwnProperty('weight')) {
173
- const reviewUtc = r.at.utc_time;
174
- if (!lastReviewUtc || shaxpir_common_1.Time.isDateTimeAfter(reviewUtc, lastReviewUtc)) {
175
- lastReviewUtc = reviewUtc;
176
- }
177
- reviewCount++;
194
+ if (review.hasOwnProperty('context') &&
195
+ review.hasOwnProperty('weight')) {
196
+ const r = review;
197
+ this._impliedReviewsView.push({
198
+ result: r.result,
199
+ at_utc_time: r.at_utc_time,
200
+ context: r.context,
201
+ weight: r.weight
202
+ });
203
+ const batch = new Operation_1.BatchOperation(this);
204
+ batch.setPathValue(['payload', 'implied_review_count'], this._impliedReviewsView.length);
205
+ batch.commit();
206
+ }
207
+ else {
208
+ this._reviewsView.push({
209
+ result: review.result,
210
+ at_utc_time: review.at_utc_time
211
+ });
212
+ const batch = new Operation_1.BatchOperation(this);
213
+ batch.setPathValue(['payload', 'review_count'], this._reviewsView.length);
214
+ if (this.lastReviewUtc == null || shaxpir_common_1.Time.isDateTimeAfter(review.at_utc_time, this.lastReviewUtc)) {
215
+ batch.setPathValue(['payload', 'last_review_utc'], review.at_utc_time);
178
216
  }
179
- });
180
- const batch = new Operation_1.BatchOperation(this);
181
- batch.setPathValue(['payload', 'review_count'], reviewCount);
182
- batch.setPathValue(['payload', 'last_review_utc'], lastReviewUtc);
183
- batch.commit();
184
- }
185
- getReviewCount() {
186
- this.checkDisposed("Term.getReviewCount");
187
- return this.payload.review_count;
188
- }
189
- getLastReviewUtc() {
190
- this.checkDisposed("Term.getLastReviewUtc");
191
- return this.payload.last_review_utc;
217
+ batch.commit();
218
+ }
192
219
  }
193
220
  }
194
221
  exports.Term = Term;
@@ -31,7 +31,8 @@ export declare class Workspace extends Content {
31
31
  static create(userId: ContentId, payload: WorkspacePayload): Workspace;
32
32
  get sessions(): ArrayView<MultiTime>;
33
33
  get devices(): ArrayView<ContentId>;
34
- acquireSessionsFromDate(sessionId: ContentId, localDate: CompactDate): Promise<Session[]>;
34
+ acquireSessionForUtcTime(utcTime: CompactDateTime): Promise<Session | null>;
35
+ acquireSessionsFromDate(localDate: CompactDate): Promise<Session[]>;
35
36
  hasJourneyDate(journeyKey: string): boolean;
36
37
  getJourneyDate(journeyKey: string): CompactDateTime;
37
38
  setJourneyDate(journeyKey: string, journeyDate: CompactDateTime): void;
@@ -49,7 +49,26 @@ class Workspace extends Content_1.Content {
49
49
  this.checkDisposed("Workspace.devices");
50
50
  return this._devicesView;
51
51
  }
52
- async acquireSessionsFromDate(sessionId, localDate) {
52
+ async acquireSessionForUtcTime(utcTime) {
53
+ this.checkDisposed("Workspace.acquireSessionForUtcTime");
54
+ const shareSync = repo_1.ShareSyncFactory.get();
55
+ for (let i = 0, len = this.sessions.length; i < len; i++) {
56
+ const sessionCreatedAt = this.sessions.get(i);
57
+ if (shaxpir_common_1.Time.isDateTimeBefore(sessionCreatedAt.utc_time, utcTime)) {
58
+ const sessionRef = Session_1.Session.makeSessionRef(this.owner, sessionCreatedAt);
59
+ const session = await shareSync.acquire(ContentKind_1.ContentKind.SESSION, sessionRef);
60
+ const sessionUpdatedAt = session.updatedAt;
61
+ if (shaxpir_common_1.Time.isDateTimeAfter(sessionUpdatedAt.utc_time, utcTime)) {
62
+ return session;
63
+ }
64
+ else {
65
+ session.release();
66
+ }
67
+ }
68
+ }
69
+ return null;
70
+ }
71
+ async acquireSessionsFromDate(localDate) {
53
72
  this.checkDisposed("Workspace.loadSessionsFromDate");
54
73
  const shareSync = repo_1.ShareSyncFactory.get();
55
74
  const sessions = [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shaxpir/duiduidui-models",
3
- "version": "1.5.2",
3
+ "version": "1.5.3",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/shaxpir/duiduidui-models"