Fix some mutations

This commit is contained in:
Hakan Shehu
2025-10-25 01:17:30 +02:00
parent 59ea93e136
commit ea34da3326
5 changed files with 55 additions and 31 deletions

View File

@@ -1,5 +1,3 @@
import { merge } from 'lodash-es';
import { WorkspaceMutationHandlerBase } from '@colanode/client/handlers/mutations/workspace-mutation-handler-base'; import { WorkspaceMutationHandlerBase } from '@colanode/client/handlers/mutations/workspace-mutation-handler-base';
import { MutationHandler } from '@colanode/client/lib/types'; import { MutationHandler } from '@colanode/client/lib/types';
import { import {
@@ -15,8 +13,8 @@ export class NodeUpdateMutationHandler
input: NodeUpdateMutationInput input: NodeUpdateMutationInput
): Promise<NodeUpdateMutationOutput> { ): Promise<NodeUpdateMutationOutput> {
const workspace = this.getWorkspace(input.userId); const workspace = this.getWorkspace(input.userId);
await workspace.nodes.updateNode(input.nodeId, (attributes) => { await workspace.nodes.updateNode(input.nodeId, () => {
return merge(attributes, input.attributes); return input.attributes;
}); });
return { return {

View File

@@ -4,7 +4,7 @@ export type NodeUpdateMutationInput = {
type: 'node.update'; type: 'node.update';
userId: string; userId: string;
nodeId: string; nodeId: string;
attributes: Partial<NodeAttributes>; attributes: NodeAttributes;
}; };
export type NodeUpdateMutationOutput = { export type NodeUpdateMutationOutput = {

View File

@@ -52,11 +52,16 @@ export class YDoc {
schema: z.ZodSchema, schema: z.ZodSchema,
object: z.infer<typeof schema> object: z.infer<typeof schema>
): Uint8Array | null { ): Uint8Array | null {
if (!schema.safeParse(object).success) { const normalizedObject = this.normalizeForUpdate(object);
throw new Error('Invalid object', schema.safeParse(object).error);
const parseResult = schema.safeParse(normalizedObject);
if (!parseResult.success) {
throw new Error(`Invalid object: ${parseResult.error.message}`, {
cause: parseResult.error,
});
} }
const objectSchema = this.extractType(schema, object); const objectSchema = this.extractType(schema, normalizedObject);
if (!(objectSchema instanceof z.ZodObject)) { if (!(objectSchema instanceof z.ZodObject)) {
throw new Error('Schema must be a ZodObject'); throw new Error('Schema must be a ZodObject');
} }
@@ -70,7 +75,7 @@ export class YDoc {
const objectMap = this.doc.getMap('object'); const objectMap = this.doc.getMap('object');
this.doc.transact(() => { this.doc.transact(() => {
this.applyObjectChanges(objectSchema, object, objectMap); this.applyObjectChanges(objectSchema, normalizedObject, objectMap);
const parseResult = schema.safeParse(objectMap.toJSON()); const parseResult = schema.safeParse(objectMap.toJSON());
if (!parseResult.success) { if (!parseResult.success) {
@@ -469,4 +474,26 @@ export class YDoc {
return schema; return schema;
} }
private normalizeForUpdate(object: any): any {
if (object === null || object === undefined) {
return object;
}
if (Array.isArray(object)) {
return object.map((item) => this.normalizeForUpdate(item));
}
if (typeof object === 'object') {
const normalized: any = {};
for (const [key, value] of Object.entries(object)) {
if (value !== undefined) {
normalized[key] = this.normalizeForUpdate(value);
}
}
return normalized;
}
return object;
}
} }

View File

@@ -83,22 +83,24 @@ export const SelectFieldOptions = ({
); );
} }
if (!fieldDraft.options) { const existingOptions = fieldDraft.options ?? {};
fieldDraft.options = {}; const maxIndex = Object.values(existingOptions)
}
const maxIndex = Object.values(fieldDraft.options)
.map((selectOption) => selectOption.index) .map((selectOption) => selectOption.index)
.sort((a, b) => -compareString(a, b))[0]; .sort((a, b) => -compareString(a, b))[0];
const index = generateFractionalIndex(maxIndex, null); const index = generateFractionalIndex(maxIndex, null);
fieldDraft.options[selectOptionId] = { const updatedOptions = {
...existingOptions,
[selectOptionId]: {
name: name, name: name,
id: selectOptionId, id: selectOptionId,
color: color, color: color,
index: index, index: index,
},
}; };
fieldDraft.options = updatedOptions;
}); });
return selectOptionId; return selectOptionId;
@@ -113,6 +115,7 @@ export const SelectFieldOptions = ({
onSelect(selectOptionId); onSelect(selectOptionId);
}, },
onError: (error) => { onError: (error) => {
console.log('error', error);
toast.error(error.message as string); toast.error(error.message as string);
}, },
}); });

View File

@@ -1,4 +1,5 @@
import { createCollection } from '@tanstack/react-db'; import { createCollection } from '@tanstack/react-db';
import { cloneDeep } from 'lodash-es';
import { LocalNode } from '@colanode/client/types'; import { LocalNode } from '@colanode/client/types';
@@ -49,38 +50,33 @@ export const createNodesCollection = (userId: string) => {
}, },
}, },
onInsert: async ({ transaction }) => { onInsert: async ({ transaction }) => {
transaction.mutations.forEach(async (mutation) => { for (const mutation of transaction.mutations) {
await window.colanode.executeMutation({ await window.colanode.executeMutation({
type: 'node.create', type: 'node.create',
userId, userId,
node: mutation.modified, node: mutation.modified,
}); });
}); }
}, },
onUpdate: async ({ transaction }) => { onUpdate: async ({ transaction }) => {
transaction.mutations.forEach(async (mutation) => { for (const mutation of transaction.mutations) {
console.log('onUpdate', mutation); const attributes = cloneDeep(mutation.modified.attributes);
const attributes = mutation.changes.attributes;
if (!attributes) {
return;
}
await window.colanode.executeMutation({ await window.colanode.executeMutation({
type: 'node.update', type: 'node.update',
userId, userId,
nodeId: mutation.key, nodeId: mutation.key,
attributes, attributes,
}); });
}); }
}, },
onDelete: async ({ transaction }) => { onDelete: async ({ transaction }) => {
transaction.mutations.forEach(async (mutation) => { for (const mutation of transaction.mutations) {
await window.colanode.executeMutation({ await window.colanode.executeMutation({
type: 'node.delete', type: 'node.delete',
userId, userId,
nodeId: mutation.key, nodeId: mutation.key,
}); });
}); }
}, },
}); });
}; };