11/* eslint-disable @typescript-eslint/naming-convention */
22import type { TFile } from "obsidian" ;
3- import type { DiscourseNode } from "~/types" ;
3+ import type DiscourseGraphPlugin from "~/index" ;
4+ import type {
5+ DiscourseNode ,
6+ DiscourseRelation ,
7+ DiscourseRelationType ,
8+ } from "~/types" ;
49import type { SupabaseContext } from "./supabaseContext" ;
10+ import type { DiscourseNodeInVault } from "./syncDgNodesToSupabase" ;
511import type { LocalConceptDataInput } from "@repo/database/inputTypes" ;
612import type { ObsidianDiscourseNodeData } from "./syncDgNodesToSupabase" ;
713import type { Json } from "@repo/database/dbTypes" ;
@@ -52,21 +58,157 @@ export const discourseNodeSchemaToLocalConcept = ({
5258 } ;
5359} ;
5460
61+ const STANDARD_ROLES = [ "source" , "destination" ] ;
62+
63+ export const discourseRelationTypeToLocalConcept = ( {
64+ context,
65+ relationType,
66+ accountLocalId,
67+ } : {
68+ context : SupabaseContext ;
69+ relationType : DiscourseRelationType ;
70+ accountLocalId : string ;
71+ } ) : LocalConceptDataInput => {
72+ const now = new Date ( ) . toISOString ( ) ;
73+ const { id, label, complement, ...otherData } = relationType ;
74+ return {
75+ space_id : context . spaceId ,
76+ name : label ,
77+ source_local_id : id ,
78+ is_schema : true ,
79+ author_local_id : accountLocalId ,
80+ created : now ,
81+ literal_content : {
82+ label,
83+ complement,
84+ source_data : otherData ,
85+ } as unknown as Json ,
86+ last_modified : now ,
87+ } ;
88+ } ;
89+
90+ export const discourseRelationSchemaToLocalConcept = ( {
91+ context,
92+ relation,
93+ accountLocalId,
94+ nodeTypesById,
95+ relationTypesById,
96+ } : {
97+ context : SupabaseContext ;
98+ relation : DiscourseRelation ;
99+ accountLocalId : string ;
100+ nodeTypesById : Record < string , DiscourseNode > ;
101+ relationTypesById : Record < string , DiscourseRelationType > ;
102+ } ) : LocalConceptDataInput => {
103+ const sourceName =
104+ nodeTypesById [ relation . sourceId ] ?. name ?? relation . sourceId ;
105+ const destinationName =
106+ nodeTypesById [ relation . destinationId ] ?. name ?? relation . destinationId ;
107+ const relationType = relationTypesById [ relation . relationshipTypeId ] ;
108+ if ( ! relationType )
109+ throw new Error ( `missing relation type ${ relation . relationshipTypeId } ` ) ;
110+ const { label, complement } = relationType ;
111+ const now = new Date ( ) . toISOString ( ) ; // TODO: Keep a date in the structure
112+ // TODO: Create an Id for the triple
113+ const compositeId = [
114+ relation . relationshipTypeId ,
115+ relation . sourceId ,
116+ relation . destinationId ,
117+ ] . join ( ":" ) ;
118+
119+ return {
120+ space_id : context . spaceId ,
121+ name : `${ sourceName } -${ label } -> ${ destinationName } ` ,
122+ source_local_id : compositeId ,
123+ is_schema : true ,
124+ author_local_id : accountLocalId ,
125+ created : now ,
126+ last_modified : now ,
127+ literal_content : {
128+ roles : STANDARD_ROLES ,
129+ label,
130+ complement,
131+ } ,
132+ local_reference_content : {
133+ relation_type : relation . relationshipTypeId ,
134+ source : relation . sourceId ,
135+ destination : relation . destinationId ,
136+ } ,
137+ } ;
138+ } ;
139+
55140/**
56141 * Convert discourse node instance (file) to LocalConceptDataInput
57142 */
58- export const discourseNodeInstanceToLocalConcept = ( {
143+ export const discourseNodeInstanceToLocalConcepts = ( {
144+ plugin,
145+ allNodesByName,
59146 context,
60147 nodeData,
61148 accountLocalId,
62149} : {
150+ plugin : DiscourseGraphPlugin ;
151+ allNodesByName : Record < string , DiscourseNodeInVault > ;
63152 context : SupabaseContext ;
64153 nodeData : ObsidianDiscourseNodeData ;
65154 accountLocalId : string ;
66- } ) : LocalConceptDataInput => {
155+ } ) : LocalConceptDataInput [ ] => {
67156 const extraData = getNodeExtraData ( nodeData . file , accountLocalId ) ;
68157 const { nodeInstanceId, nodeTypeId, ...otherData } = nodeData . frontmatter ;
69- return {
158+ const response : LocalConceptDataInput [ ] = [ ] ;
159+ for ( const relType of plugin . settings . relationTypes ) {
160+ const rels = otherData [ relType . id ] ;
161+ if ( rels ) {
162+ delete otherData [ relType . id ] ;
163+ const triples = plugin . settings . discourseRelations . filter (
164+ ( r ) => r . relationshipTypeId === relType . id && r . sourceId === nodeTypeId ,
165+ ) ;
166+ if ( ! triples . length ) {
167+ // we're probably the target.
168+ continue ;
169+ }
170+ const tripleDestTypes = new Set ( triples . map ( ( rel ) => rel . destinationId ) ) ;
171+ for ( let rel of rels as string [ ] ) {
172+ if ( rel . startsWith ( "[[" ) && rel . endsWith ( "]]" ) )
173+ rel = rel . substring ( 2 , rel . length - 2 ) ;
174+ if ( rel . endsWith ( ".md" ) ) rel = rel . substring ( 0 , rel . length - 3 ) ;
175+ const target = allNodesByName [ rel ] ;
176+ if ( ! target ) {
177+ console . error ( `Could not find node name ${ rel } ` ) ;
178+ continue ;
179+ }
180+ const targetTypeId = target . frontmatter . nodeTypeId as string ;
181+ const targetInstanceId = target . frontmatter . nodeInstanceId as string ;
182+ if ( ! tripleDestTypes . has ( targetTypeId ) ) {
183+ console . error (
184+ `Found a relation of type ${ relType . id } between ${ nodeData . file . path } and ${ rel } but no relation fits` ,
185+ ) ;
186+ continue ;
187+ }
188+ const compositeSchemaId = [ relType . id , nodeTypeId , targetTypeId ] . join (
189+ ":" ,
190+ ) ;
191+ const compositeInstanceId = [
192+ relType . id ,
193+ nodeInstanceId as string ,
194+ targetInstanceId ,
195+ ] . join ( ":" ) ;
196+ response . push ( {
197+ space_id : context . spaceId ,
198+ name : `[[${ nodeData . file . basename } ]] -${ relType . label } -> [[${ target . file . basename } ]]` ,
199+ source_local_id : compositeInstanceId ,
200+ schema_represented_by_local_id : compositeSchemaId ,
201+ is_schema : false ,
202+ local_reference_content : {
203+ source : nodeInstanceId as string ,
204+ destination : targetInstanceId ,
205+ } ,
206+ ...extraData ,
207+ } ) ;
208+ }
209+ }
210+ }
211+ response . push ( {
70212 space_id : context . spaceId ,
71213 name : nodeData . file . path ,
72214 source_local_id : nodeInstanceId as string ,
@@ -77,7 +219,8 @@ export const discourseNodeInstanceToLocalConcept = ({
77219 source_data : otherData as unknown as Json ,
78220 } ,
79221 ...extraData ,
80- } ;
222+ } ) ;
223+ return response ;
81224} ;
82225
83226export const relatedConcepts = ( concept : LocalConceptDataInput ) : string [ ] => {
0 commit comments