Skip to content

Commit 0c1e727

Browse files
committed
internal systems overhaul init
1 parent 4729768 commit 0c1e727

File tree

15 files changed

+202
-125
lines changed

15 files changed

+202
-125
lines changed

.trunk/trunk.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
version: 0.1
22
cli:
3-
version: 1.14.0
3+
version: 1.14.2
44
plugins:
55
sources:
66
- id: trunk

docs/docs/api-reference/batch.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ Run a function. During that function's execution, any state changes will be batc
2929
<a name="RuntimeInstance+batch"></a>
3030

3131
## .batch(fn)
32-
<p>The batch function allows you to run a series of actions in a single transaction</p>
32+
<p>The batch function allows you to run a series of reactive actions in a single transaction</p>
3333

3434

3535
| Param | Type | Description |

packages/plexus-core/src/collection/collection.ts

Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ export class CollectionInstance<
305305
return Array.from(addedKeys.values())
306306
}
307307
const collectFn = (
308-
data_: typeof data,
308+
dataToCollect: typeof data,
309309
groups?: KeyOfMap<Groups>[] | KeyOfMap<Groups>,
310310
startedFromInnerBatch?: boolean
311311
) => {
@@ -325,13 +325,13 @@ export class CollectionInstance<
325325
'debug',
326326
`Batched collect call fulfilled for collection ${this.instanceId}`
327327
)
328-
return collectFn(data_, groups, true)
328+
return collectFn(dataToCollect, groups, true)
329329
})
330330
return this
331331
}
332332

333333
const addedKeys: any[] = collectItems(
334-
Array.isArray(data_) ? data_ : [data_]
334+
Array.isArray(dataToCollect) ? dataToCollect : [dataToCollect]
335335
)
336336

337337
const defaultGroupName =
@@ -355,12 +355,19 @@ export class CollectionInstance<
355355
}
356356
this._internalStore._internalCalledGroupCollect = false
357357
}
358+
358359
// we only need to call back if the instance is not batching
359360
if (this.config.useBatching) {
361+
// this.instance().runtime.startBatching()
360362
this.instance().runtime.batch(() => collectFn(data, groups))
361363
} else {
362364
collectFn(data, groups)
363365
}
366+
367+
// if (this.config.useBatching) {
368+
// this.instance().runtime.endBatching()
369+
// }
370+
364371
this.mount()
365372
return this
366373
}
@@ -788,10 +795,29 @@ export class CollectionInstance<
788795
this._internalStore._data.delete(key)
789796
}
790797
// if an array, iterate through the keys and remove them each
791-
if (Array.isArray(keys)) {
792-
keys.forEach(rm)
793-
} else {
794-
rm(keys)
798+
keys = Array.isArray(keys) ? keys : [keys]
799+
800+
// if the instance is batching and this collection has batching enabled, add this action to the batchedSetters
801+
if (
802+
// this.instance().runtime.isBatching &&
803+
this.config.useBatching
804+
) {
805+
this.instance().runtime.log(
806+
'debug',
807+
`Batching an delete call for collection ${this.instanceId}`
808+
)
809+
this.instance().runtime.startBatching()
810+
}
811+
// run this remove call
812+
for (const key of keys) {
813+
rm(key)
814+
}
815+
if (this.config.useBatching) {
816+
this.instance().runtime.endBatching()
817+
this.instance().runtime.log(
818+
'debug',
819+
`Batched delete call fulfilled for collection ${this.instanceId}`
820+
)
795821
}
796822
this.mount()
797823
return this
@@ -836,10 +862,9 @@ export class CollectionInstance<
836862
}
837863

838864
// if an array, iterate through the keys and remove them from each associated group
839-
if (Array.isArray(keys)) {
840-
keys.forEach(rm)
841-
} else {
842-
rm(keys)
865+
keys = Array.isArray(keys) ? keys : [keys]
866+
for (let key of keys) {
867+
rm(key)
843868
}
844869
return this
845870
// ! This is commented out because the user may still want to keep the data in the collection. If they want to completely delete the data, they should use `.delete()`
@@ -856,13 +881,9 @@ export class CollectionInstance<
856881
clear(groupNames?: KeyOfMap<Groups> | KeyOfMap<Groups>[]): this {
857882
// this means we want to clear a group, not the whole collection
858883
if (groupNames) {
859-
if (Array.isArray(groupNames)) {
860-
groupNames.forEach(
861-
(groupName) =>
862-
this.isCreatedGroup(groupName) && this.getGroup(groupName).clear()
863-
)
864-
} else {
865-
this.isCreatedGroup(groupNames) && this.getGroup(groupNames).clear()
884+
groupNames = Array.isArray(groupNames) ? groupNames : [groupNames]
885+
for (const groupName of groupNames) {
886+
this.isCreatedGroup(groupName) && this.getGroup(groupName).clear()
866887
}
867888
} else {
868889
this.delete(Array.from(this._internalStore._data.keys()))

packages/plexus-core/src/instance/engine.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,19 @@ export class EventEngine {
2020
halt() {
2121
this.batching = true
2222
return () => {
23-
this.batching = false
24-
this.pendingEventPayloads.forEach((args, eventId) => {
25-
this.emit(eventId, args)
26-
})
27-
this.pendingEventPayloads.clear()
23+
this.release()
2824
}
2925
}
26+
/**
27+
* Emit all stored concatenated events and resume normal event emitting.
28+
*/
29+
release() {
30+
this.batching = false
31+
this.pendingEventPayloads.forEach((args, eventId) => {
32+
this.emit(eventId, args)
33+
})
34+
this.pendingEventPayloads.clear()
35+
}
3036

3137
on(eventId: string, listener: PlexusInternalWatcher, origin?: string) {
3238
if (!eventId || eventId === '') {

packages/plexus-core/src/instance/runtime.ts

Lines changed: 42 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ export class RuntimeInstance {
213213
}
214214

215215
/**
216-
* The batch function allows you to run a series of actions in a single transaction
216+
* The batch function allows you to run a series of reactive actions in a single transaction
217217
* @param {Function} fn The function to run
218218
*/
219219
batch<BatchFunction extends () => any | Promise<any>>(
@@ -227,40 +227,22 @@ export class RuntimeInstance {
227227
return fn()
228228
}
229229

230-
// hold the reactivity engine and start storing changes
231-
// const unhalt = this.engine.halt()
232-
this.batching = true
230+
this.startBatching()
233231
this.instance().runtime.log('info', 'Batch function started!')
234-
const releaseBatch = () => {
235-
// if we aren't batching anymore, just return
236-
if (this.batching === false) {
237-
return
238-
}
239-
// stop storing changes and emit the changes
240-
this.batching = false
241-
// call all the pending functions and clear the array
242-
this.batchedCalls.forEach((pendingFn) => pendingFn())
243-
this.batchedCalls.length = 0
244-
245-
// release the reactivity engine
246-
// unhalt()
247-
248-
this.instance().runtime.log('info', 'Batch function completed!')
249-
}
250232
// run the function. If it returns a promise, wait for it to resolve
251-
const prom = fn()
252-
if (prom instanceof Promise) {
233+
const pendingResponse = fn()
234+
if (pendingResponse instanceof Promise) {
253235
return new Promise<ReturnType<BatchFunction>>(async (resolve, reject) => {
254236
// wait for the promise to resolve
255-
const value = await prom
237+
const value = await pendingResponse
256238
// release the batch
257-
releaseBatch()
239+
this.endBatching()
258240
// resolve the promise, return the value of the promise
259241
return resolve(value)
260242
}) as ReturnType<BatchFunction>
261243
}
262-
releaseBatch()
263-
return prom
244+
this.endBatching()
245+
return pendingResponse
264246
}
265247

266248
/**
@@ -270,6 +252,40 @@ export class RuntimeInstance {
270252
get isBatching() {
271253
return this.batching
272254
}
255+
256+
/**
257+
* Release the batch
258+
* @returns {void}
259+
*/
260+
endBatching() {
261+
// if we aren't batching anymore, just return
262+
if (this.batching === false) {
263+
return
264+
}
265+
// stop storing changes and emit the changes
266+
this.batching = false
267+
// call all the pending functions and clear the array
268+
this.batchedCalls.forEach((pendingFn) => pendingFn())
269+
this.batchedCalls.length = 0
270+
271+
// release the reactivity engine
272+
// this.engine.release()
273+
274+
this.instance().runtime.log('info', 'Batch function completed!')
275+
}
276+
/**
277+
* Begin batching any calls to the runtime
278+
* @private
279+
* @returns {Function(): void} A function to release the batch
280+
*/
281+
startBatching() {
282+
this.batching = true
283+
// hold the reactivity engine and start storing changes
284+
// this.engine.halt()
285+
return () => {
286+
this.endBatching()
287+
}
288+
}
273289
}
274290
/**
275291
* Create a runtime for an instance NOTE: NOT FOR PUBLIC USE

packages/plexus-core/src/storage.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ export class StorageInstance {
179179
}
180180
}
181181

182+
// ! This might be broken? Definitely need to rethink storage procedures
182183
sync(checkValue?: any) {
183184
this.instance().runtime.log('info', 'Syncing storage...')
184185
this._internalStore.tracking.forEach(async (object) => {

packages/tsconfig.shared.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
"noImplicitAny": false,
1212
"noImplicitThis": true,
1313
"skipLibCheck": true,
14-
"esModuleInterop": true
14+
"esModuleInterop": true,
15+
"stripInternal": true
1516
}
1617
}

tests/api.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { beforeEach, afterEach, describe, test, expect } from 'vitest'
22
import { api, PlexusApi } from '@plexusjs/api'
3+
// only imported here to make sure it works in testing environment (node), not needed by user
34
import 'isomorphic-fetch'
45

56
// if(globalThis.fetch === undefined) globalThis.fetch = fetch as any as (input: RequestInfo, init?: RequestInit) => Promise<Response>;

tests/basic.test.ts

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,20 @@ import { describe, test } from 'vitest'
22
import {
33
DEFAULT_DECAY_RATE,
44
arrayState,
5+
objectState,
6+
stringState,
57
decayingUsers,
68
myCollection,
79
myCollectionUndefined,
8-
objectState,
9-
stringState,
1010
} from './test-utils'
1111
import { instance, state } from '@plexusjs/core'
1212

13+
beforeEach(() => {
14+
stringState.reset()
15+
objectState.reset()
16+
arrayState.reset()
17+
})
18+
1319
describe('Collections Core Functionality', () => {
1420
test('Can create collection', () => {
1521
expect(myCollection.value.length).toBe(0)
@@ -68,19 +74,20 @@ describe('State Core Functionality', () => {
6874

6975
test('Checking state().set()', () => {
7076
// check .set(value: object)
71-
objectState.set({ a: { b: false } })
77+
objectState.set({ a: { a2: false } })
7278
// check if the object is actually merged and children props do get overwritten
73-
expect(objectState.value.a?.b).toBe(false)
79+
expect(objectState.value.a?.a2).toBe(false)
7480
})
7581

7682
test('Checking state().patch()', () => {
83+
objectState.set({ a: { a1: true, a2: true }, b: true })
7784
// can the object deep merge?
78-
objectState.patch({ a: { b: false } })
79-
expect(objectState.value.a?.a).toBe(true)
85+
objectState.patch({ a: { a2: false } })
86+
expect(objectState.value.a?.a1).toBe(true)
8087
// check that other value is still there
8188
expect(objectState.value.b).toBe(true)
8289
// changed intended value
83-
expect(objectState.value.a?.b).toBe(false)
90+
expect(objectState.value.a?.a2).toBe(false)
8491

8592
// console.log(arrayState.value)
8693
// check array deep merge

tests/computed.test.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,11 @@ const core = {
5050
}, [collections.books.getGroup('all')]),
5151

5252
numOfReadingReactiveToAll: computed(() => {
53-
console.log('numOfReadingReactiveToAll compute...')
53+
console.log(
54+
'numOfReadingReactiveToAll compute...',
55+
collections.books.getGroup('READING').value.length,
56+
collections.books.getGroup('all').value.length
57+
)
5458
return collections.books.getGroup('READING').value.length
5559
}, [collections.books.getGroup('all')]),
5660
}
@@ -129,9 +133,14 @@ describe('Testing Computed State Function', () => {
129133
})
130134
test('Computed can watch a default collection group', () => {
131135
instance({ logLevel: 'debug' })
136+
// start watching the reading group
132137
collections.books.getGroup('READING')?.watch((v) => {
133138
console.log('READING changed to: ', v)
134139
})
140+
collections.books.getGroup('all')?.watch((v) => {
141+
console.log('ALL changed to: ', v)
142+
})
143+
// start watching the computed state that is watching the reading group
135144
core.numOfReadingReactiveToAll.watch((v) => {
136145
console.log('numOfReadingReactiveToAll.value changed to: ', v)
137146
})
@@ -152,7 +161,8 @@ describe('Testing Computed State Function', () => {
152161
core.numOfReadingReactiveToAll.value,
153162
core.collections.books.size,
154163
core.collections.books.getGroup('READING')?.size,
155-
core.collections.books.getGroup('all')?.size
164+
core.collections.books.getGroup('all')?.size,
165+
core.collections.books.getGroup('all').value
156166
)
157167

158168
expect(core.numOfReadingReactiveToAll.value).toBe(0)

0 commit comments

Comments
 (0)