package synchronizator // A user representation of a node, this interface should be implemented by the user // to provide the ability to parse the database node into a user defined // struct that fulfills it's requirements. // // This interface is compatible with the [NodeClass] interface but it doesn't // handle the class parameter as it's a static value provided by the // StandardNode type StandardNode interface { // How to transform the struct into a node. It needs to return the class, // name and a []byte representation of the metadata. // // - name: A user friendly name // - metadata: Arbitrary data. This will be stored as a jsonb in the database // ToNode() (string, []byte, error) // How to transform a node into the struct. This method should modify the // struct directly as it receives a pointer. // // - class: The class of the node, should not be modified to avoid inconsistencies. // - name: A user friendly name // - metadata: Arbitrary data. This is stored as a jsonb in the database FromNode(string, string, []byte) error } // A node in the database. // It adds some helper methods to easily manage the node. type Node struct { _conn *DB // Underlaying connection to the database. _class string // The class of the node, should not be modified to avoid inconsistencies. _relationships []*Relationship // Relationships of the node Id int64 // The id of the node name string // The name of the node metadata []byte // Arbitrary data. This is stored as a jsonb in the database } // Creates a new relation of type StandardRelationship to the node with the // provided id. An error is returned if the relation already exists. // // This method is a wrapper around the AddRelation method of the connection. func (node *Node) AddRelation(relation StandardRelationship, to int64) (*Relationship, error) { return node._conn.AddRelation(node.Id, relation, to) } // Update a relation with the node of the provided id. // // This method is a wrapper around the UpdateRelation method of the connection. func (node *Node) UpdateRelation(metadata any, to int64) error { return node._conn.UpdateRelation(node.Id, metadata, to) } // Delete a relation with the node of the provided id. // // This method is a wrapper around the DeleteRelation method of the connection. func (node *Node) DeleteRelation(to int64) error { return node._conn.DeleteRelation(node.Id, to) } // Fetch all the outgoing relations for this node. This method will return a // slice of relationships pointers and also store them in the node for further // use. func (node *Node) GetOutRelations() ([]*Relationship, error) { sql := ` WITH RECURSIVE NodeRelationships AS ( SELECT *, relationships._class AS relationship_class, relationships.metadata AS relationship_metadata FROM nodes as src JOIN relationships ON src.id = relationships.node_from WHERE src.id = $1 ) SELECT NodeRelationships.id as src_node, NodeRelationships.relationship_class, NodeRelationships.relationship_metadata, dst.id as dst_id FROM NodeRelationships JOIN nodes as dst ON dst.id = NodeRelationships.node_to ` rows, err := node._conn.Query(sql, node.Id) if err != nil { return nil, err } defer rows.Close() node._relationships = make([]*Relationship, 0) for rows.Next() { relationship := &Relationship{ _conn: node._conn, } if err := rows.Scan(&relationship.From, &relationship._class, &relationship.Metadata, &relationship.To); err != nil { return nil, err } node._relationships = append(node._relationships, relationship) } return node._relationships, nil } // Deletes this node from the database. // This method is a wrapper around the DeleteNode method of the connection. func (node *Node) Delete() error { return node._conn.DeleteNode(node.Id) } // Allows to retreive the saved information back into the user struct. This // method will call the [NodeClass.FromNode] of the provided struct. // // Example: // // data := &Library{} // if err := node.Unmarshall(data); err != nil { // println(err) // } func (node *Node) Unmarshall(dst StandardNode) error { return dst.FromNode(node._class, node.name, node.metadata) } // Returns the class of the node func (relationship *Relationship) GetClass() string { return relationship._class }