Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add project settings functionality to MapeoProject #187

Merged
merged 38 commits into from
Aug 24, 2023

Conversation

achou11
Copy link
Member

@achou11 achou11 commented Aug 16, 2023

Closes #167

Notes:

  • implements project records indexing on the config store
  • introduces the $setProjectSettings and $getProjectSettings methods (which also make it easier to test the indexing)

TODO:

@achou11 achou11 force-pushed the 167/project-info-index branch from 6ce5568 to d701a61 Compare August 17, 2023 16:50
@achou11
Copy link
Member Author

achou11 commented Aug 17, 2023

running into a couple of implementation questions that I probably need some help with:

  1. Because the project table lives in a separate database from the other mapeo schema data types, I need a Drizzle instance that uses a SQLite instance that points to the client db. The one created in MapeoProject only creates one pointing to the project db right now. At the time of writing, I currently add a "config" object that specifies the client db instance, which feels off. With this, every project that gets created will be sharing the same "client" db instance, which on paper makes sense but also has me somewhat skeptical...

  2. What's responsible for actually creating the project i.e. writing the very first "project" record? Seems like that would be the responsibility of whatever holds the project DataType via dataType.create(...), which is the MapeoProject at the time of writing. However, since DataType.create is async, we can't call it in the constructor, meaning that we'd need to expose a public method that the creator of the instance would then call. For example, the pseudo-code for a wrapper client class createProject method would look something like:

class MapeoManager {
  async createProject(value) {
    const project = new MapeoProject(...)
    await project.$create(value)
    return project
  }
}

Does that seem reasonable, or do I need to approach the design of this a little differently? Or maybe I'm missing an important detail...

@gmaclennan gmaclennan mentioned this pull request Aug 18, 2023
@achou11
Copy link
Member Author

achou11 commented Aug 18, 2023

After discussion with Gregor:

  1. My approach is valid. Not pretty but probably no noticeably better way of doing it for now

  2. I was onto something here and turns out we need Add dataType.createWithDocId() method #190 in order to address the issue. That method will be used in the MapeoProject.$setProjectSettings to provide upsert behavior. So the wrapper client would create the MapeoProject instance and then calls $setProjectSettings, with the project setting "creation" being taken care of in the MapeoProject implementation

@achou11 achou11 force-pushed the 167/project-info-index branch from b5e3aac to 4288d76 Compare August 18, 2023 16:55
@achou11 achou11 changed the title WIP: add project info indexing to MapeoProject add project settings indexing to MapeoProject Aug 18, 2023
@achou11 achou11 marked this pull request as ready for review August 18, 2023 16:56
@achou11 achou11 requested a review from gmaclennan August 18, 2023 16:56
Comment on lines 106 to 110
// TODO: Use simplified decode export from @mapeo/schema when available
const schemaName = decode(entry.block, {
index: entry.index,
coreKey: entry.key,
}).schemaName
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

highlighting that this ideally would be using a more optimal variant of decode, which hasn't been implemented yet at time of writing

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addressed via c6259d2

Comment on lines 119 to 122
await Promise.all([
indexWriter.batch(otherEntries),
projectSettingsConfig.indexWriter.batch(projectSettingsEntries),
])
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do i need to do any error catching/handling here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the decode() function will throw if it encounters a block that it does not know how to decode. These errors should just be ignored for now.

For errors in the indexWriter batch, I think it's ok to not catch them and let them bubble up to the dataStore

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addressed via 6763de9


/**
* @param {import('./types.js').ProjectSettings} settings
* @param {string} [versionId]
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be string | string[]? Thought it would be, but then how would that get passed to dataType.getByVersionId? (which accepts string)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should have a second parameter here. Using this method should always just update the latest e.g.

async $setProjectSettings(settings) {
  const { project } = this.#dataTypes
  const existing = project.getByDocId(this.#projectId)
  if (existing) {
    return project.update([ existing.versionId, ...existing.forks ], {
      ...getValueOf(existing),
      ...settings
    })
  } else {
    return project[kCreateWithDocId](this.#projectId, {
      ...settings,
      schemaName: 'project'
    })
  }

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addressed via 2cc9d44

test-e2e/project-settings.js Show resolved Hide resolved
}

/**
* @returns {Promise<import('@mapeo/schema').Project>}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have this returning the entire project document for now, but guessing we'd want less information to surface in general.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I think return Omit<ProjectValue, 'schemaName'>

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addressed via 82563b4

@@ -124,4 +166,34 @@ export class MapeoProject {
get field() {
return this.#dataTypes.field
}

/**
* @param {Omit<import('@mapeo/schema').ProjectValue, 'schemaName'>} settings
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

kind of forgot what defaultPresets represents - should it also be omitted here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be Partial<Omit<ProjectValue, 'schemaName'>>

default presets is configuration for which presets are shown to the user to select from.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually I think we should modify the schema and consider all properties on projectSettings to be optional, and implement defaults in code.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to modify the schema given https://github.com/digidem/mapeo-schema/issues/104?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we allow fields to be undefined. We just don't allow them to be null

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be Partial<Omit<ProjectValue, 'schemaName'>>

addressed via 2cc9d44

@achou11 achou11 changed the title add project settings indexing to MapeoProject add project settings functionality to MapeoProject Aug 21, 2023
Comment on lines 26 to 29
const NAMESPACE_SCHEMAS = /** @type {const} */ ({
data: ['observation'],
config: ['preset', 'field'],
config: ['preset', 'field', 'project'],
auth: [],
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there should be a comment here explaining what this is used for. took me a bit to figure out I needed to update it to add the project schema

Comment on lines +49 to +50
// TODO: Update to use @mapeo/crypto when ready (https://github.com/digidem/mapeo-core-next/issues/171)
this.#projectId = coreManagerOpts.projectKey.toString('hex')
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just highlighting this as something that will eventually be updated

@achou11 achou11 deleted the 167/project-info-index branch August 24, 2023 11:18
gmaclennan added a commit that referenced this pull request Sep 6, 2023
* main: (25 commits)
  add initial implementation of MemberApi (#232)
  feat: $blobs.getUrl and $blobs.create methods (#184)
  chore: update manager e2e tests (#237)
  feat: add capabilities (#231)
  feat: coreOwnership integration [3/3] (#230)
  feat: CoreOwnership class w getOwner & getCoreKey [2/3] (#229)
  feat: handle `coreOwnership` records in `IndexWriter` [1/3] (#214)
  fix: adjust storage options for MapeoManager and MapeoProject (#235)
  implement addProject method for MapeoManager class (#215)
  implement listProjects method for MapeoManager class (#208)
  feat: expose blobStore.writerDriveId (#219)
  implement wrapper client containing createProject and getProject methods (#199)
  add project settings functionality to MapeoProject (#187)
  feat: Add encode/decode for project keys [3/3] (#203)
  feat: update protobuf for RPC [2/3] (#202)
  chore: move protobuf messages into src/generated [1/3] (#201)
  feat: Add internal `dataType.createWithDocId()` (#192)
  chore: explicitly set "mode" opt for encryptionKeys column creation (#186)
  chore: fix linting and type checking (#183)
  chore: consolidate encryption key columns in projectKeys table (#181)
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add projectInfo indexing to MapeoProject
2 participants