1+ /* eslint-disable @typescript-eslint/member-ordering */
12import type { ChangeFn } from "@automerge/automerge"
23import { NO_OP } from "lib/constants"
3- import { $ , E , type Types } from "lib/Effect"
4+ import { E , type Types } from "lib/Effect"
45import type { Root , RootEncoded } from "schema/Root"
56import type { KeyNotFoundError } from "./Errors"
67import { NonUniqueIndex , UniqueIndex } from "./Indexes"
@@ -67,7 +68,7 @@ export abstract class Collection<
6768
6869 constructor (
6970 /** The initial items to populate the collection with */
70- items : Item [ ] | Record < string , Item > ,
71+ items : Item [ ] | Record < string , Item > = [ ] ,
7172
7273 /**
7374 * The automerge-repo change function returned by useDoc<Root>.
@@ -79,13 +80,71 @@ export abstract class Collection<
7980 this . index = new UniqueIndex ( items , "id" as StringKeyOf < Item > )
8081 }
8182
83+ // NON-EFFECTFUL (SYNC) API FOR USE BY APPLICATION
84+
8285 /** Returns all items in the collection. */
8386 all ( ) {
84- return this . index . all ( )
87+ return E . runSync ( this . effect_all ( ) )
8588 }
8689
8790 /** Finds an item by its ID. */
8891 find ( id : string ) {
92+ return E . runSync ( this . effect_find ( id ) )
93+ }
94+
95+ /**
96+ * Finds an item or items using an index.
97+ * - If the index is unique (first overload), returns a single item, and throws if none is found.
98+ * - If the index is non-unique (second overload), returns an array zero or more of items.
99+ *
100+ * @example `contactCollection.findBy("userName", "alice")` // returns one contact
101+ * @example `contactCollection.findBy("company", "DevResults")` // returns an array of contacts
102+ */
103+ findBy ( ...args : Parameters < typeof this . effect_findBy > ) {
104+ return E . runSync ( this . effect_findBy ( ...args ) )
105+ }
106+
107+ /** Adds an item to the collection */
108+ add ( arg : Item | Item [ ] ) {
109+ return E . runSync ( this . effect_add ( arg ) )
110+ }
111+
112+ /** Updates an item given an object containing its ID and one or more updated properties. */
113+ update ( item : { id : IdOf < Item > } & Partial < Item > ) {
114+ E . runSync ( this . effect_update ( item ) )
115+ }
116+
117+ /** Removes an item from a collection, given its ID. */
118+ destroy ( id : IdOf < Item > ) {
119+ E . runSync ( this . effect_destroy ( id ) )
120+ }
121+
122+ /** Removes all items from the collection. */
123+ destroyAll ( ) {
124+ E . runSync ( this . effect_destroyAll ( ) )
125+ }
126+
127+ // EFFECTFUL API FOR USE WITHIN DATA LAYER
128+
129+ public effect = {
130+ all : this . effect_all . bind ( this ) ,
131+ find : this . effect_find . bind ( this ) ,
132+ findBy : this . effect_findBy . bind ( this ) ,
133+ add : this . effect_add . bind ( this ) ,
134+ update : this . effect_update . bind ( this ) ,
135+ destroy : this . effect_destroy . bind ( this ) ,
136+ destroyAll : this . effect_destroyAll . bind ( this ) ,
137+ }
138+
139+ // PRIVATE
140+
141+ /** Returns all items in the collection. Returns an effect. */
142+ private effect_all ( ) {
143+ return this . index . all ( )
144+ }
145+
146+ /** Finds an item by its ID. Returns an effect. */
147+ private effect_find ( id : string ) {
89148 return this . index . find ( id )
90149 }
91150
@@ -96,24 +155,26 @@ export abstract class Collection<
96155 *
97156 * @example `contactCollection.findBy("userName", "alice")` // returns one contact
98157 * @example `contactCollection.findBy("company", "DevResults")` // returns an array of contacts
158+ *
159+ * Returns an effect.
99160 */
100- findBy < IndexName extends UniqueIndexName < this> > (
161+ private effect_findBy < IndexName extends UniqueIndexName < this> > (
101162 indexName : IndexName ,
102163 value : any ,
103164 ) : E . Effect < never , KeyNotFoundError > | E . Effect < Item >
104165
105- findBy < IndexName extends NonUniqueIndexName < this> > (
166+ private effect_findBy < IndexName extends NonUniqueIndexName < this> > (
106167 indexName : IndexName ,
107168 value : any ,
108169 ) : E . Effect < Item [ ] >
109170
110- findBy < IndexName extends AnyIndexName < this> > ( indexName : IndexName , value : any ) {
171+ private effect_findBy < IndexName extends AnyIndexName < this> > ( indexName : IndexName , value : any ) {
111172 const index = this . getIndex ( indexName )
112173 return index . find ( String ( value ) )
113174 }
114175
115- /** Adds an item to the collection */
116- add ( arg : Item | Item [ ] ) {
176+ /** Adds an item to the collection. Returns an effect. */
177+ private effect_add ( arg : Item | Item [ ] ) {
117178 const items = Array . isArray ( arg ) ? arg : [ arg ]
118179
119180 return E . gen ( this , function * ( ) {
@@ -134,10 +195,10 @@ export abstract class Collection<
134195 } )
135196 }
136197
137- /** Updates an item given an object containing its ID and one or more updated properties. */
138- update ( item : { id : IdOf < Item > } & Partial < Item > ) {
198+ /** Updates an item given an object containing its ID and one or more updated properties. Returns an effect. */
199+ private effect_update ( item : { id : IdOf < Item > } & Partial < Item > ) {
139200 return E . gen ( this , function * ( ) {
140- const prevValue = yield * this . find ( item . id )
201+ const prevValue = yield * this . effect_find ( item . id )
141202 const newValue : Item = { ...prevValue , ...item }
142203
143204 // update the item in all indexes
@@ -155,10 +216,10 @@ export abstract class Collection<
155216 } )
156217 }
157218
158- /** Removes an item from a collection, given its ID. */
159- destroy ( id : IdOf < Item > ) {
219+ /** Removes an item from a collection, given its ID. Returns an effect. */
220+ private effect_destroy ( id : IdOf < Item > ) {
160221 return E . gen ( this , function * ( ) {
161- const item = yield * this . find ( id )
222+ const item = yield * this . effect_find ( id )
162223
163224 // remove the item from all indexes
164225 for ( const index of this . allIndexes ) {
@@ -173,8 +234,8 @@ export abstract class Collection<
173234 } )
174235 }
175236
176- /** Removes all items from the collection. */
177- destroyAll ( ) {
237+ /** Removes all items from the collection. Returns an effect. */
238+ private effect_destroyAll ( ) {
178239 return E . gen ( this , function * ( ) {
179240 // remove all items from all indexes
180241 for ( const index of this . allIndexes ) {
@@ -188,8 +249,6 @@ export abstract class Collection<
188249 } )
189250 }
190251
191- // PRIVATE
192-
193252 /** Returns an array containing all indexes in the collection */
194253 private get allIndexes ( ) {
195254 return [
@@ -207,7 +266,7 @@ export abstract class Collection<
207266
208267 // create the index on demand
209268 if ( ! ( name in indexes ) ) {
210- const items = $ ( this . all ( ) )
269+ const items = E . runSync ( this . effect_all ( ) )
211270 const index =
212271 unique ?
213272 new UniqueIndex ( items , key , name ) //
0 commit comments