Skip to content

Commit

Permalink
initial implementation of listProjects
Browse files Browse the repository at this point in the history
  • Loading branch information
achou11 committed Aug 23, 2023
1 parent b3634e6 commit aa29820
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 16 deletions.
75 changes: 72 additions & 3 deletions src/mapeo-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ import { MapeoProject } from './mapeo-project.js'
import { projectKeysTable, projectTable } from './schema/client.js'
import { ProjectKeys } from './generated/keys.js'

/** @typedef {import("@mapeo/schema").ProjectValue} ProjectValue */
/** @typedef {import("./types.js").ProjectInfo} ProjectInfo */

const CLIENT_SQLITE_FILE_NAME = 'client.db'

export class MapeoManager {
Expand Down Expand Up @@ -43,9 +46,20 @@ export class MapeoManager {
this.#activeProjects = new Map()
}

/**
* @param {Buffer} keysCipher
* @param {string} projectId
* @returns {ProjectKeys}
*/
#decodeProjectKeysCipher(keysCipher, projectId) {
return ProjectKeys.decode(
this.#keyManager.decryptLocalMessage(keysCipher, projectId)
)
}

/**
* Create a new project.
* @param {import('type-fest').Simplify<Partial<Pick<import("@mapeo/schema").ProjectValue, 'name'>>>} [settings]
* @param {import('type-fest').Simplify<Partial<Pick<ProjectValue, 'name'>>>} [settings]
* @returns {Promise<string>}
*/
async createProject(settings = {}) {
Expand Down Expand Up @@ -131,8 +145,9 @@ export class MapeoManager {
)
}

const projectKeys = ProjectKeys.decode(
this.#keyManager.decryptLocalMessage(result.keysCipher, projectId)
const projectKeys = this.#decodeProjectKeysCipher(
result.keysCipher,
projectId
)

const project = new MapeoProject({
Expand All @@ -145,4 +160,58 @@ export class MapeoManager {

return project
}

/**
* @returns {Promise<Array<ProjectInfo & Pick<ProjectValue, 'name'>>>}
*/
async listProjects() {
const allProjectsResult = this.#db
.select({
projectId: projectKeysTable.projectId,
keysCipher: projectKeysTable.keysCipher,
})
.from(projectKeysTable)
.all()

if (allProjectsResult.length === 0) {
return []
}

/** @type {Array<Promise<ProjectInfo & Pick<ProjectValue, 'name'>>>} */
const resultPromises = []

for (const { projectId, keysCipher } of allProjectsResult) {
let project = this.#activeProjects.get(projectId)

if (!project) {
const projectKeys = this.#decodeProjectKeysCipher(keysCipher, projectId)

project = new MapeoProject({
...projectKeys,
storagePath: this.#storagePath,
keyManager: this.#keyManager,
sharedDb: this.#db,
sharedIndexWriter: this.#projectSettingsIndexWriter,
})

this.#activeProjects.set(projectId, project)
}

const info = await project.$getProjectInfo()
const settings = await project.$getProjectSettings()

resultPromises.push(
Promise.resolve({
...info,
name: settings.name,
})
)

// TODO: Close project instance
// https://github.com/digidem/mapeo-core-next/issues/207
}

// TODO: Is it safe to do Promise.all here?
return Promise.all(resultPromises)
}
}
15 changes: 15 additions & 0 deletions src/mapeo-project.js
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,21 @@ export class MapeoProject {
return /** @type {EditableProjectSettings} */ ({})
}
}

/**
* @returns {Promise<import('./types.js').ProjectInfo>}
*/
async $getProjectInfo() {
const { createdAt, updatedAt } = await this.#dataTypes.project.getByDocId(
this.#projectId
)

return {
projectId: this.#projectId,
createdAt: new Date(createdAt),
updatedAt: new Date(updatedAt),
}
}
}

/**
Expand Down
6 changes: 6 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,3 +181,9 @@ export type ProjectKeys = {
'auth'
>
}

export type ProjectInfo = {
createdAt: Date
updatedAt: Date
projectId: string
}
30 changes: 17 additions & 13 deletions test-e2e/manager-basic.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,28 @@
import { test } from 'brittle'
import { MapeoManager } from '../src/mapeo-manager.js'

test('MapeoManager.createProject works', async (t) => {
test('Managing multiple projects', async (t) => {
const manager = new MapeoManager()

const expectedSettings = {
name: 'foo',
}
const initialProjects = await manager.listProjects()

const projectId = await manager.createProject(expectedSettings)

t.ok(projectId)
t.is(
initialProjects.length,
0,
'no projects exist when manager is initially created'
)

const project = await manager.getProject(projectId)
const createdProjectIds = [
await manager.createProject(),
await manager.createProject(),
await manager.createProject(),
]

const settings = await project.$getProjectSettings()
const allProjects = await manager.listProjects()

t.is(
settings.name,
expectedSettings.name,
'settings for fetched project are the same as when created'
t.is(allProjects.length, createdProjectIds.length)
t.ok(
allProjects.every((p) => createdProjectIds.includes(p.projectId)),
'all created projects are listed'
)
})

0 comments on commit aa29820

Please sign in to comment.