Skip to content

Commit

Permalink
Merge branch 'main' into move-unit-tests-to-test-folder
Browse files Browse the repository at this point in the history
  • Loading branch information
EvanHahn committed Sep 26, 2024
2 parents b744890 + 143fa7a commit 2123d7e
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 7 deletions.
24 changes: 24 additions & 0 deletions src/lib/key-by.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/**
* Like [`Map.groupBy`][0], but the result's values aren't arrays.
*
* If multiple values resolve to the same key, an error is thrown.
*
* [0]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/groupBy
*
* @template T
* @template K
* @param {Iterable<T>} items
* @param {(item: T) => K} callbackFn
* @returns {Map<K, T>}
*/
export function keyBy(items, callbackFn) {
/** @type {Map<K, T>} */ const result = new Map()
for (const item of items) {
const key = callbackFn(item)
if (result.has(key)) {
throw new Error(`keyBy found duplicate key ${JSON.stringify(key)}`)
}
result.set(key, item)
}
return result
}
7 changes: 4 additions & 3 deletions src/member-api.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
projectKeyToId,
projectKeyToProjectInviteId,
} from './utils.js'
import { keyBy } from './lib/key-by.js'
import { abortSignalAny } from './lib/ponyfills.js'
import timingSafeEqual from './lib/timing-safe-equal.js'
import { ROLES, isRoleIdForNewInvite } from './roles.js'
Expand Down Expand Up @@ -279,6 +280,8 @@ export class MemberApi extends TypedEmitter {
this.#dataTypes.deviceInfo.getMany(),
])

const deviceInfoByConfigCoreId = keyBy(allDeviceInfo, ({ docId }) => docId)

return Promise.all(
[...allRoles.entries()].map(async ([deviceId, role]) => {
/** @type {MemberInfo} */
Expand All @@ -290,9 +293,7 @@ export class MemberApi extends TypedEmitter {
'config'
)

const deviceInfo = allDeviceInfo.find(
({ docId }) => docId === configCoreId
)
const deviceInfo = deviceInfoByConfigCoreId.get(configCoreId)

memberInfo.name = deviceInfo?.name
memberInfo.deviceType = deviceInfo?.deviceType
Expand Down
7 changes: 3 additions & 4 deletions test/core-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -353,12 +353,11 @@ test('sends "haves" bitfields over project creator core replication stream', asy

const cm1Core = cm1.getWriterCore('data').core
await cm1Core.ready()
const batchSize = 4096
// Create 4 million entries in hypercore - will be at least two have bitfields
const batchSize = 4096
const block = new Uint8Array([99])
const data = Array(batchSize).fill(block)
for (let i = 0; i < 2 ** 22; i += batchSize) {
const data = Array(batchSize)
.fill(null)
.map(() => 'block')
await cm1Core.append(data)
}

Expand Down
37 changes: 37 additions & 0 deletions test/lib/key-by.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import assert from 'node:assert/strict'
import test from 'node:test'
import { keyBy } from '../../src/lib/key-by.js'

test('returns an empty map if passed an empty iterable', () => {
assert.deepEqual(
keyBy([], () => {
throw new Error('Should not be called')
}),
new Map()
)
})

test('keys a list of items by a key function', () => {
const items = [
{ id: 1, name: 'foo' },
{ id: 2, name: 'bar' },
{ id: 3, name: 'baz' },
]
const result = keyBy(items, (item) => item.id)
assert.deepEqual(
result,
new Map([
[1, items[0]],
[2, items[1]],
[3, items[2]],
])
)
})

test('duplicate keys', () => {
const items = [
{ id: 1, name: 'foo' },
{ id: 1, name: 'bar' },
]
assert.throws(() => keyBy(items, (item) => item.id))
})

0 comments on commit 2123d7e

Please sign in to comment.