1- /* eslint-disable @typescript-eslint/naming-convention */
21import type { TFile } from "obsidian" ;
3- import type { DiscourseNode } from "~/types" ;
2+ import type {
3+ DiscourseNode ,
4+ DiscourseRelation ,
5+ DiscourseRelationType ,
6+ RelationInstance ,
7+ } from "~/types" ;
48import type { SupabaseContext } from "./supabaseContext" ;
9+ import type { DiscourseNodeInVault } from "./getDiscourseNodes" ;
510import type { LocalConceptDataInput } from "@repo/database/inputTypes" ;
611import type { ObsidianDiscourseNodeData } from "./syncDgNodesToSupabase" ;
712import type { Json } from "@repo/database/dbTypes" ;
8- import DiscourseGraphPlugin from ".." ;
913
1014/**
1115 * Get extra data (author, timestamps) from file metadata
@@ -14,6 +18,7 @@ const getNodeExtraData = (
1418 file : TFile ,
1519 accountLocalId : string ,
1620) : {
21+ /* eslint-disable @typescript-eslint/naming-convention */
1722 author_local_id : string ;
1823 created : string ;
1924 last_modified : string ;
@@ -23,6 +28,7 @@ const getNodeExtraData = (
2328 created : new Date ( file . stat . ctime ) . toISOString ( ) ,
2429 last_modified : new Date ( file . stat . mtime ) . toISOString ( ) ,
2530 } ;
31+ /* eslint-enable @typescript-eslint/naming-convention */
2632} ;
2733
2834export const discourseNodeSchemaToLocalConcept = ( {
@@ -34,8 +40,23 @@ export const discourseNodeSchemaToLocalConcept = ({
3440 node : DiscourseNode ;
3541 accountLocalId : string ;
3642} ) : LocalConceptDataInput => {
37- const { description, template, id, name, created, modified, ...otherData } =
38- node ;
43+ const {
44+ description,
45+ template,
46+ id,
47+ name,
48+ created,
49+ modified,
50+ importedFromRid,
51+ ...otherData
52+ } = node ;
53+ /* eslint-disable @typescript-eslint/naming-convention */
54+ const literal_content : Record < string , Json > = {
55+ label : name ,
56+ source_data : otherData ,
57+ } ;
58+ if ( template ) literal_content . template = template ;
59+ if ( importedFromRid ) literal_content . importedFromRid = importedFromRid ;
3960 return {
4061 space_id : context . spaceId ,
4162 name,
@@ -45,11 +66,106 @@ export const discourseNodeSchemaToLocalConcept = ({
4566 created : new Date ( created ) . toISOString ( ) ,
4667 last_modified : new Date ( modified ) . toISOString ( ) ,
4768 description : description ,
48- literal_content : {
49- label : name ,
50- template : template ,
51- source_data : otherData ,
69+ literal_content,
70+ /* eslint-enable @typescript-eslint/naming-convention */
71+ } ;
72+ } ;
73+
74+ const STANDARD_ROLES = [ "source" , "destination" ] ;
75+
76+ export const discourseRelationTypeToLocalConcept = ( {
77+ context,
78+ relationType,
79+ accountLocalId,
80+ } : {
81+ context : SupabaseContext ;
82+ relationType : DiscourseRelationType ;
83+ accountLocalId : string ;
84+ } ) : LocalConceptDataInput => {
85+ const {
86+ id,
87+ label,
88+ complement,
89+ created,
90+ modified,
91+ importedFromRid,
92+ ...otherData
93+ } = relationType ;
94+ // eslint-disable-next-line @typescript-eslint/naming-convention
95+ const literal_content : Record < string , Json > = {
96+ roles : STANDARD_ROLES ,
97+ label,
98+ complement,
99+ // eslint-disable-next-line @typescript-eslint/naming-convention
100+ source_data : otherData ,
101+ } ;
102+ if ( importedFromRid ) literal_content . importedFromRid = importedFromRid ;
103+
104+ return {
105+ /* eslint-disable @typescript-eslint/naming-convention */
106+ space_id : context . spaceId ,
107+ name : label ,
108+ source_local_id : id ,
109+ is_schema : true ,
110+ author_local_id : accountLocalId ,
111+ created : new Date ( created ) . toISOString ( ) ,
112+ last_modified : new Date ( modified ) . toISOString ( ) ,
113+ literal_content,
114+ /* eslint-enable @typescript-eslint/naming-convention */
115+ } ;
116+ } ;
117+
118+ export const discourseRelationTripleSchemaToLocalConcept = ( {
119+ context,
120+ relation,
121+ accountLocalId,
122+ nodeTypesById,
123+ relationTypesById,
124+ } : {
125+ context : SupabaseContext ;
126+ relation : DiscourseRelation ;
127+ accountLocalId : string ;
128+ nodeTypesById : Record < string , DiscourseNode > ;
129+ relationTypesById : Record < string , DiscourseRelationType > ;
130+ } ) : LocalConceptDataInput | null => {
131+ const {
132+ id,
133+ relationshipTypeId,
134+ sourceId,
135+ destinationId,
136+ created,
137+ modified,
138+ importedFromRid,
139+ } = relation ;
140+ const sourceName = nodeTypesById [ sourceId ] ?. name ?? sourceId ;
141+ const destinationName = nodeTypesById [ destinationId ] ?. name ?? destinationId ;
142+ const relationType = relationTypesById [ relationshipTypeId ] ;
143+ if ( ! relationType ) return null ;
144+ const { label, complement } = relationType ;
145+ // eslint-disable-next-line @typescript-eslint/naming-convention
146+ const literal_content : Record < string , Json > = {
147+ roles : STANDARD_ROLES ,
148+ label,
149+ complement,
150+ } ;
151+ if ( importedFromRid ) literal_content . importedFromRid = importedFromRid ;
152+
153+ return {
154+ /* eslint-disable @typescript-eslint/naming-convention */
155+ space_id : context . spaceId ,
156+ name : `${ sourceName } -${ label } -> ${ destinationName } ` ,
157+ source_local_id : id ,
158+ is_schema : true ,
159+ author_local_id : accountLocalId ,
160+ created : new Date ( created ) . toISOString ( ) ,
161+ last_modified : new Date ( modified ) . toISOString ( ) ,
162+ literal_content,
163+ local_reference_content : {
164+ relation_type : relationshipTypeId ,
165+ source : sourceId ,
166+ destination : destinationId ,
52167 } ,
168+ /* eslint-enable @typescript-eslint/naming-convention */
53169 } ;
54170} ;
55171
@@ -66,21 +182,83 @@ export const discourseNodeInstanceToLocalConcept = ({
66182 accountLocalId : string ;
67183} ) : LocalConceptDataInput => {
68184 const extraData = getNodeExtraData ( nodeData . file , accountLocalId ) ;
69- const { nodeInstanceId, nodeTypeId, ...otherData } = nodeData . frontmatter ;
185+ const { nodeInstanceId, nodeTypeId, importedFromRid, ...otherData } =
186+ nodeData . frontmatter ;
187+ // eslint-disable-next-line @typescript-eslint/naming-convention
188+ const literal_content : Record < string , Json > = {
189+ label : nodeData . file . basename ,
190+ // eslint-disable-next-line @typescript-eslint/naming-convention
191+ source_data : otherData as unknown as Json ,
192+ } ;
193+ if ( importedFromRid && typeof importedFromRid === "string" )
194+ literal_content . importedFromRid = importedFromRid ;
70195 return {
196+ /* eslint-disable @typescript-eslint/naming-convention */
71197 space_id : context . spaceId ,
72198 name : nodeData . file . path ,
73199 source_local_id : nodeInstanceId as string ,
74200 schema_represented_by_local_id : nodeTypeId as string ,
75201 is_schema : false ,
76- literal_content : {
77- label : nodeData . file . basename ,
78- source_data : otherData as unknown as Json ,
79- } ,
202+ literal_content,
203+ /* eslint-enable @typescript-eslint/naming-convention */
80204 ...extraData ,
81205 } ;
82206} ;
83207
208+ export const relationInstanceToLocalConcept = ( {
209+ context,
210+ relationTypesById,
211+ allNodesById,
212+ relationInstanceData,
213+ } : {
214+ context : SupabaseContext ;
215+ relationTypesById : Record < string , DiscourseRelationType > ;
216+ allNodesById : Record < string , DiscourseNodeInVault > ;
217+ relationInstanceData : RelationInstance ;
218+ } ) : LocalConceptDataInput | null => {
219+ const { type, created, lastModified, source, destination, importedFromRid } =
220+ relationInstanceData ;
221+ const relationType = relationTypesById [ type ] ;
222+
223+ if ( ! relationType ) {
224+ console . error ( "Missing relationType id " + type ) ;
225+ return null ;
226+ }
227+ const sourceNode = allNodesById [ source ] ;
228+ const destinationNode = allNodesById [ destination ] ;
229+ if ( sourceNode === undefined || destinationNode === undefined ) {
230+ console . error ( "Cannot find the nodes" ) ;
231+ return null ;
232+ }
233+
234+ if (
235+ sourceNode . frontmatter . importedFromRid ||
236+ destinationNode . frontmatter . importedFromRid
237+ )
238+ return null ; // punt relation to imported nodes for now.
239+ // otherwise put the importedFromRid in source, dest.
240+
241+ /* eslint-disable @typescript-eslint/naming-convention */
242+ const literal_content : Record < string , Json > = { } ;
243+ if ( importedFromRid ) literal_content . importedFromRid = importedFromRid ;
244+ return {
245+ space_id : context . spaceId ,
246+ name : `[[${ sourceNode . file . basename } ]] -${ relationType . label } -> [[${ destinationNode . file . basename } ]]` ,
247+ source_local_id : relationInstanceData . id ,
248+ author_local_id : relationInstanceData . author ,
249+ schema_represented_by_local_id : type ,
250+ is_schema : false ,
251+ created : new Date ( created ) . toISOString ( ) ,
252+ last_modified : new Date ( lastModified ?? created ) . toISOString ( ) ,
253+ literal_content,
254+ local_reference_content : {
255+ source,
256+ destination,
257+ } ,
258+ /* eslint-enable @typescript-eslint/naming-convention */
259+ } ;
260+ } ;
261+
84262export const relatedConcepts = ( concept : LocalConceptDataInput ) : string [ ] => {
85263 const relations = Object . values (
86264 concept . local_reference_content || { } ,
@@ -99,27 +277,40 @@ export const relatedConcepts = (concept: LocalConceptDataInput): string[] => {
99277 * schema_represented_by_local_id or local_reference_content — so that id
100278 * must equal some concept's source_local_id or it is reported as "missing".
101279 */
102- const orderConceptsRec = (
103- ordered : LocalConceptDataInput [ ] ,
104- concept : LocalConceptDataInput ,
105- remainder : { [ key : string ] : LocalConceptDataInput } ,
106- ) : Set < string > => {
280+ const orderConceptsRec = ( {
281+ ordered,
282+ concept,
283+ remainder,
284+ processed,
285+ } : {
286+ ordered : LocalConceptDataInput [ ] ;
287+ concept : LocalConceptDataInput ;
288+ remainder : { [ key : string ] : LocalConceptDataInput } ;
289+ processed : Set < string > ;
290+ } ) : Set < string > => {
107291 const relatedConceptIds = relatedConcepts ( concept ) ;
108292 let missing : Set < string > = new Set ( ) ;
109293 while ( relatedConceptIds . length > 0 ) {
110294 const relatedConceptId = relatedConceptIds . shift ( ) ! ;
295+ if ( processed . has ( relatedConceptId ) ) continue ;
111296 const relatedConcept = remainder [ relatedConceptId ] ;
112297 if ( relatedConcept === undefined ) {
113298 missing . add ( relatedConceptId ) ;
114299 } else {
115300 missing = new Set ( [
116301 ...missing ,
117- ...orderConceptsRec ( ordered , relatedConcept , remainder ) ,
302+ ...orderConceptsRec ( {
303+ ordered,
304+ concept : relatedConcept ,
305+ remainder,
306+ processed,
307+ } ) ,
118308 ] ) ;
119309 delete remainder [ relatedConceptId ] ;
120310 }
121311 }
122312 ordered . push ( concept ) ;
313+ processed . add ( concept . source_local_id ! ) ;
123314 delete remainder [ concept . source_local_id ! ] ;
124315 return missing ;
125316} ;
@@ -143,14 +334,20 @@ export const orderConceptsByDependency = (
143334 ) ;
144335 const ordered : LocalConceptDataInput [ ] = [ ] ;
145336 let missing : Set < string > = new Set ( ) ;
337+ const processed : Set < string > = new Set ( ) ;
146338 while ( Object . keys ( conceptById ) . length > 0 ) {
147339 const first = Object . values ( conceptById ) [ 0 ] ;
148340 if ( ! first ) break ;
149341 missing = new Set ( [
150342 ...missing ,
151- ...orderConceptsRec ( ordered , first , conceptById ) ,
343+ ...orderConceptsRec ( {
344+ ordered,
345+ concept : first ,
346+ remainder : conceptById ,
347+ processed,
348+ } ) ,
152349 ] ) ;
153- if ( missing . size > 0 ) console . error ( `missing: ${ [ ...missing ] } ` ) ;
350+ if ( missing . size > 0 ) console . error ( `missing: ${ [ ...missing ] . join ( ", " ) } ` ) ;
154351 }
155352 return { ordered, missing : Array . from ( missing ) } ;
156353} ;
0 commit comments