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 ".. " ;
13+ import { DGSupabaseClient } from "@repo/database/lib/client " ;
914
1015/**
1116 * Get extra data (author, timestamps) from file metadata
@@ -14,6 +19,7 @@ const getNodeExtraData = (
1419 file : TFile ,
1520 accountLocalId : string ,
1621) : {
22+ /* eslint-disable @typescript-eslint/naming-convention */
1723 author_local_id : string ;
1824 created : string ;
1925 last_modified : string ;
@@ -23,6 +29,7 @@ const getNodeExtraData = (
2329 created : new Date ( file . stat . ctime ) . toISOString ( ) ,
2430 last_modified : new Date ( file . stat . mtime ) . toISOString ( ) ,
2531 } ;
32+ /* eslint-enable @typescript-eslint/naming-convention */
2633} ;
2734
2835export const discourseNodeSchemaToLocalConcept = ( {
@@ -34,8 +41,23 @@ export const discourseNodeSchemaToLocalConcept = ({
3441 node : DiscourseNode ;
3542 accountLocalId : string ;
3643} ) : LocalConceptDataInput => {
37- const { description, template, id, name, created, modified, ...otherData } =
38- node ;
44+ const {
45+ description,
46+ template,
47+ id,
48+ name,
49+ created,
50+ modified,
51+ importedFromRid,
52+ ...otherData
53+ } = node ;
54+ /* eslint-disable @typescript-eslint/naming-convention */
55+ const literal_content : Record < string , Json > = {
56+ label : name ,
57+ source_data : otherData ,
58+ } ;
59+ if ( template ) literal_content . template = template ;
60+ if ( importedFromRid ) literal_content . importedFromRid = importedFromRid ;
3961 return {
4062 space_id : context . spaceId ,
4163 name,
@@ -45,11 +67,107 @@ export const discourseNodeSchemaToLocalConcept = ({
4567 created : new Date ( created ) . toISOString ( ) ,
4668 last_modified : new Date ( modified ) . toISOString ( ) ,
4769 description : description ,
48- literal_content : {
49- label : name ,
50- template : template ,
51- source_data : otherData ,
70+ literal_content,
71+ /* eslint-enable @typescript-eslint/naming-convention */
72+ } ;
73+ } ;
74+
75+ const STANDARD_ROLES = [ "source" , "destination" ] ;
76+
77+ export const discourseRelationTypeToLocalConcept = ( {
78+ context,
79+ relationType,
80+ accountLocalId,
81+ } : {
82+ context : SupabaseContext ;
83+ relationType : DiscourseRelationType ;
84+ accountLocalId : string ;
85+ } ) : LocalConceptDataInput => {
86+ const {
87+ id,
88+ label,
89+ complement,
90+ created,
91+ modified,
92+ importedFromRid,
93+ ...otherData
94+ } = relationType ;
95+ // eslint-disable-next-line @typescript-eslint/naming-convention
96+ const literal_content : Record < string , Json > = {
97+ roles : STANDARD_ROLES ,
98+ label,
99+ complement,
100+ // eslint-disable-next-line @typescript-eslint/naming-convention
101+ source_data : otherData ,
102+ } ;
103+ if ( importedFromRid ) literal_content . importedFromRid = importedFromRid ;
104+
105+ return {
106+ /* eslint-disable @typescript-eslint/naming-convention */
107+ space_id : context . spaceId ,
108+ name : label ,
109+ source_local_id : id ,
110+ is_schema : true ,
111+ author_local_id : accountLocalId ,
112+ created : new Date ( created ) . toISOString ( ) ,
113+ last_modified : new Date ( modified ) . toISOString ( ) ,
114+ literal_content,
115+ /* eslint-enable @typescript-eslint/naming-convention */
116+ } ;
117+ } ;
118+
119+ export const discourseRelationTripleSchemaToLocalConcept = ( {
120+ context,
121+ relation,
122+ accountLocalId,
123+ nodeTypesById,
124+ relationTypesById,
125+ } : {
126+ context : SupabaseContext ;
127+ relation : DiscourseRelation ;
128+ accountLocalId : string ;
129+ nodeTypesById : Record < string , DiscourseNode > ;
130+ relationTypesById : Record < string , DiscourseRelationType > ;
131+ } ) : LocalConceptDataInput => {
132+ const {
133+ id,
134+ relationshipTypeId,
135+ sourceId,
136+ destinationId,
137+ created,
138+ modified,
139+ importedFromRid,
140+ } = relation ;
141+ const sourceName = nodeTypesById [ sourceId ] ?. name ?? sourceId ;
142+ const destinationName = nodeTypesById [ destinationId ] ?. name ?? destinationId ;
143+ const relationType = relationTypesById [ relationshipTypeId ] ;
144+ if ( ! relationType )
145+ throw new Error ( `missing relation type ${ relationshipTypeId } ` ) ;
146+ const { label, complement } = relationType ;
147+ // eslint-disable-next-line @typescript-eslint/naming-convention
148+ const literal_content : Record < string , Json > = {
149+ roles : STANDARD_ROLES ,
150+ label,
151+ complement,
152+ } ;
153+ if ( importedFromRid ) literal_content . importedFromRid = importedFromRid ;
154+
155+ return {
156+ /* eslint-disable @typescript-eslint/naming-convention */
157+ space_id : context . spaceId ,
158+ name : `${ sourceName } -${ label } -> ${ destinationName } ` ,
159+ source_local_id : id ,
160+ is_schema : true ,
161+ author_local_id : accountLocalId ,
162+ created : new Date ( created ) . toISOString ( ) ,
163+ last_modified : new Date ( modified ) . toISOString ( ) ,
164+ literal_content,
165+ local_reference_content : {
166+ relation_type : relationshipTypeId ,
167+ source : sourceId ,
168+ destination : destinationId ,
52169 } ,
170+ /* eslint-enable @typescript-eslint/naming-convention */
53171 } ;
54172} ;
55173
@@ -66,21 +184,78 @@ export const discourseNodeInstanceToLocalConcept = ({
66184 accountLocalId : string ;
67185} ) : LocalConceptDataInput => {
68186 const extraData = getNodeExtraData ( nodeData . file , accountLocalId ) ;
69- const { nodeInstanceId, nodeTypeId, ...otherData } = nodeData . frontmatter ;
187+ const { nodeInstanceId, nodeTypeId, importedFromRid, ...otherData } =
188+ nodeData . frontmatter ;
189+ // eslint-disable-next-line @typescript-eslint/naming-convention
190+ const literal_content : Record < string , Json > = {
191+ label : nodeData . file . basename ,
192+ // eslint-disable-next-line @typescript-eslint/naming-convention
193+ source_data : otherData as unknown as Json ,
194+ } ;
195+ if ( importedFromRid && typeof importedFromRid === "string" )
196+ literal_content . importedFromRid = importedFromRid ;
70197 return {
198+ /* eslint-disable @typescript-eslint/naming-convention */
71199 space_id : context . spaceId ,
72200 name : nodeData . file . path ,
73201 source_local_id : nodeInstanceId as string ,
74202 schema_represented_by_local_id : nodeTypeId as string ,
75203 is_schema : false ,
76- literal_content : {
77- label : nodeData . file . basename ,
78- source_data : otherData as unknown as Json ,
79- } ,
204+ literal_content,
205+ /* eslint-enable @typescript-eslint/naming-convention */
80206 ...extraData ,
81207 } ;
82208} ;
83209
210+ export const relationInstanceToLocalConcept = ( {
211+ context,
212+ relationTypesById,
213+ allNodesById,
214+ relationInstanceData,
215+ } : {
216+ context : SupabaseContext ;
217+ relationTypesById : Record < string , DiscourseRelationType > ;
218+ allNodesById : Record < string , DiscourseNodeInVault > ;
219+ relationInstanceData : RelationInstance ;
220+ } ) : LocalConceptDataInput | null => {
221+ const { type, created, lastModified, source, destination, importedFromRid } =
222+ relationInstanceData ;
223+ const relationType = relationTypesById [ type ] ;
224+
225+ if ( ! relationType ) {
226+ console . error ( "Missing relationType id " + type ) ;
227+ return null ;
228+ }
229+ const sourceNode = allNodesById [ source ] ;
230+ const destinationNode = allNodesById [ destination ] ;
231+ if (
232+ sourceNode ?. frontmatter . importedFromRid ||
233+ destinationNode ?. frontmatter . importedFromRid
234+ )
235+ return null ; // punt relation to imported nodes for now.
236+ // otherwise put the importedFromRid in source, dest.
237+
238+ /* eslint-disable @typescript-eslint/naming-convention */
239+ const literal_content : Record < string , Json > = { } ;
240+ if ( importedFromRid ) literal_content . importedFromRid = importedFromRid ;
241+ return {
242+ space_id : context . spaceId ,
243+ name : `[[${ sourceNode ? sourceNode . file . basename : source } ]] -${ relationType . label } -> [[${ destinationNode ? destinationNode . file . basename : destination } ]]` ,
244+ source_local_id : relationInstanceData . id ,
245+ author_local_id : relationInstanceData . author ,
246+ schema_represented_by_local_id : type ,
247+ is_schema : false ,
248+ created : new Date ( created ) . toISOString ( ) ,
249+ last_modified : new Date ( lastModified ?? created ) . toISOString ( ) ,
250+ literal_content,
251+ local_reference_content : {
252+ source,
253+ destination,
254+ } ,
255+ /* eslint-enable @typescript-eslint/naming-convention */
256+ } ;
257+ } ;
258+
84259export const relatedConcepts = ( concept : LocalConceptDataInput ) : string [ ] => {
85260 const relations = Object . values (
86261 concept . local_reference_content || { } ,
@@ -103,23 +278,26 @@ const orderConceptsRec = (
103278 ordered : LocalConceptDataInput [ ] ,
104279 concept : LocalConceptDataInput ,
105280 remainder : { [ key : string ] : LocalConceptDataInput } ,
281+ processed : Set < string > ,
106282) : Set < string > => {
107283 const relatedConceptIds = relatedConcepts ( concept ) ;
108284 let missing : Set < string > = new Set ( ) ;
109285 while ( relatedConceptIds . length > 0 ) {
110286 const relatedConceptId = relatedConceptIds . shift ( ) ! ;
287+ if ( processed . has ( relatedConceptId ) ) continue ;
111288 const relatedConcept = remainder [ relatedConceptId ] ;
112289 if ( relatedConcept === undefined ) {
113290 missing . add ( relatedConceptId ) ;
114291 } else {
115292 missing = new Set ( [
116293 ...missing ,
117- ...orderConceptsRec ( ordered , relatedConcept , remainder ) ,
294+ ...orderConceptsRec ( ordered , relatedConcept , remainder , processed ) ,
118295 ] ) ;
119296 delete remainder [ relatedConceptId ] ;
120297 }
121298 }
122299 ordered . push ( concept ) ;
300+ processed . add ( concept . source_local_id ! ) ;
123301 delete remainder [ concept . source_local_id ! ] ;
124302 return missing ;
125303} ;
@@ -143,14 +321,15 @@ export const orderConceptsByDependency = (
143321 ) ;
144322 const ordered : LocalConceptDataInput [ ] = [ ] ;
145323 let missing : Set < string > = new Set ( ) ;
324+ const processed : Set < string > = new Set ( ) ;
146325 while ( Object . keys ( conceptById ) . length > 0 ) {
147326 const first = Object . values ( conceptById ) [ 0 ] ;
148327 if ( ! first ) break ;
149328 missing = new Set ( [
150329 ...missing ,
151- ...orderConceptsRec ( ordered , first , conceptById ) ,
330+ ...orderConceptsRec ( ordered , first , conceptById , processed ) ,
152331 ] ) ;
153- if ( missing . size > 0 ) console . error ( `missing: ${ [ ...missing ] } ` ) ;
332+ if ( missing . size > 0 ) console . error ( `missing: ${ [ ...missing ] . join ( ", " ) } ` ) ;
154333 }
155334 return { ordered, missing : Array . from ( missing ) } ;
156335} ;
0 commit comments