From 0a4909b347dbe66656f8034ba2c499e24bb42655 Mon Sep 17 00:00:00 2001 From: Dmitry Dorofeev Date: Sun, 20 Sep 2026 20:19:16 +0300 Subject: [PATCH 1/2] Add SQL relation extraction for standard CoUsage maps --- docs/mooseide-integration.md | 15 ++++++ .../FmxSQLCoUsageTest.class.st | 41 +++++++++++++++++ .../FmxSQLCoUsageExtractor.class.st | 46 +++++++++++++++++++ 3 files changed, 102 insertions(+) create mode 100644 src/FamixNGSQL-MooseIDE-Tests/FmxSQLCoUsageTest.class.st create mode 100644 src/FamixNGSQL-MooseIDE/FmxSQLCoUsageExtractor.class.st diff --git a/docs/mooseide-integration.md b/docs/mooseide-integration.md index 84917fe..6e38879 100644 --- a/docs/mooseide-integration.md +++ b/docs/mooseide-integration.md @@ -22,3 +22,18 @@ fork-first v3 development work, not a published v3 release. GitHub CI loads these optional tests in the ready-made Moose image. The plain Pharo job continues to test Core without GUI dependencies. + +## SQL CoUsage + +Select **SQL relation references** as the inner-box extractor in the standard +CoUsage map settings, or use: + +```smalltalk +FmxSQLCoUsageExtractor openOn: (model allWithType: FmxSQLStoredProcedure). +``` + +Containers are routines, views or tables; inner boxes are referenced database +tables/views. Column references are projected to their owning relation, and +foreign keys contribute referenced relations. Repeated references retain usage +counts. Empty results mean no modeled references, not proof that dynamic SQL has +no dependencies. The helper rejects mixed/unsupported input before opening. diff --git a/src/FamixNGSQL-MooseIDE-Tests/FmxSQLCoUsageTest.class.st b/src/FamixNGSQL-MooseIDE-Tests/FmxSQLCoUsageTest.class.st new file mode 100644 index 0000000..09ecbdd --- /dev/null +++ b/src/FamixNGSQL-MooseIDE-Tests/FmxSQLCoUsageTest.class.st @@ -0,0 +1,41 @@ +Class { + #name : #FmxSQLCoUsageTest, + #superclass : #TestCase, + #category : #'FamixNGSQL-MooseIDE-Tests' +} +{ #category : #tests } +FmxSQLCoUsageTest >> testSharedRelationsAndRepeatedReferences [ + | model table column first second extractor browser | + model := FmxSQLModel new. + table := FmxSQLTable new name: 'records'; mooseModel: model; yourself. + column := FmxSQLColumn new name: 'id'; columnsContainer: table; mooseModel: model; yourself. + first := FmxSQLStoredProcedure new name: 'first'; mooseModel: model; yourself. + second := FmxSQLStoredProcedure new name: 'second'; mooseModel: model; yourself. + FmxSQLColumnReference new source: first; column: column; mooseModel: model. + FmxSQLTableReference new source: first; table: table; mooseModel: model. + FmxSQLTableReference new source: second; table: table; mooseModel: model. + extractor := FmxSQLCoUsageExtractor new. + self assert: (extractor innerEntitiesFor: first) asArray equals: { table. table }. + self assert: (extractor innerEntitiesFor: second) asArray equals: { table }. + browser := FmxSQLCoUsageExtractor openOn: { first. second }. + [ self assert: browser specModel containerBoxes size equals: 2. + self assert: browser specModel innerBoxes size equals: 1 ] + ensure: [ browser window close ] +] +{ #category : #tests } +FmxSQLCoUsageTest >> testForeignKeyAndEmptyTable [ + | model source target column constraint | + model := FmxSQLModel new. + source := FmxSQLTable new name: 'source'; mooseModel: model; yourself. + target := FmxSQLTable new name: 'target'; mooseModel: model; yourself. + column := FmxSQLColumn new name: 'id'; columnsContainer: target; mooseModel: model; yourself. + constraint := FmxSQLForeignKeyConstraint new name: 'fk'; table: source; mooseModel: model; yourself. + FmxSQLColumnReference new foreignKeyConstraintSource: constraint; column: column; mooseModel: model. + self assert: (FmxSQLCoUsageExtractor new innerEntitiesFor: source) asArray equals: { target }. + self assertEmpty: (FmxSQLCoUsageExtractor new innerEntitiesFor: target) +] +{ #category : #tests } +FmxSQLCoUsageTest >> testUnsupportedInputIsRejectedBeforeOpening [ + self should: [ FmxSQLCoUsageExtractor openOn: { Object new } ] raise: Error. + self should: [ FmxSQLCoUsageExtractor new innerEntitiesFor: Object new ] raise: Error +] diff --git a/src/FamixNGSQL-MooseIDE/FmxSQLCoUsageExtractor.class.st b/src/FamixNGSQL-MooseIDE/FmxSQLCoUsageExtractor.class.st new file mode 100644 index 0000000..823c44b --- /dev/null +++ b/src/FamixNGSQL-MooseIDE/FmxSQLCoUsageExtractor.class.st @@ -0,0 +1,46 @@ +"Co-usage of database relations: containers are routines, views or tables; +inner boxes are referenced tables/views. Repeated references retain their frequency." +Class { + #name : #FmxSQLCoUsageExtractor, + #superclass : #MiCoInnerEntitiesAbstractExtractor, + #category : #'FamixNGSQL-MooseIDE' +} +{ #category : #accessing } +FmxSQLCoUsageExtractor class >> menuItemName [ ^ 'SQL relation references' ] +{ #category : #accessing } +FmxSQLCoUsageExtractor class >> description [ + ^ 'Referenced tables and views, including column and foreign-key references. Repeated references count as repeated uses.' +] +{ #category : #testing } +FmxSQLCoUsageExtractor class >> accepts: entity [ + ^ { FmxSQLTable. FmxSQLForeignTable. FmxSQLView. FmxSQLStoredProcedure } + anySatisfy: [ :class | entity isKindOf: class ] +] +{ #category : #opening } +FmxSQLCoUsageExtractor class >> openOn: entities [ + | browser | + (entities allSatisfy: [ :entity | self accepts: entity ]) ifFalse: [ + self error: 'SQL CoUsage expects only tables, views or routines' ]. + browser := MiCoUsageMapBrowser new. + browser specModel settings innerBoxExtractor: self. + browser open. + browser followEntity: entities asMooseGroup. + ^ browser +] +{ #category : #querying } +FmxSQLCoUsageExtractor >> innerEntitiesFor: entity [ + | relations | + (self class accepts: entity) ifFalse: [ self error: 'Unsupported SQL CoUsage entity' ]. + relations := OrderedCollection new. + entity queryAllOutgoing do: [ :reference | + ((reference isKindOf: FmxSQLColumnReference) or: [ + (reference isKindOf: FmxSQLTableReference) or: [ reference isKindOf: FmxSQLViewReference ] ]) ifTrue: [ + reference allTargets asSet do: [ :target | + | relation | + relation := (target isKindOf: FmxSQLColumn) + ifTrue: [ target columnsContainer ] ifFalse: [ target ]. + ((relation isKindOf: FmxSQLTable) or: [ + (relation isKindOf: FmxSQLForeignTable) or: [ relation isKindOf: FmxSQLView ] ]) + ifTrue: [ relations add: relation ] ] ] ]. + ^ relations +] From 0139e85b652a684d4451525ef5e29d8c60f1fc84 Mon Sep 17 00:00:00 2001 From: Dmitry Dorofeev Date: Sun, 20 Sep 2026 20:28:53 +0300 Subject: [PATCH 2/2] Load pinned archives independently of prebuilt Moose Iceberg checkouts --- .smalltalk.moose.ston | 1 + scripts/ci/prepare-moose.st | 3 +++ 2 files changed, 4 insertions(+) create mode 100644 scripts/ci/prepare-moose.st diff --git a/.smalltalk.moose.ston b/.smalltalk.moose.ston index 8b5bd1e..69a472d 100644 --- a/.smalltalk.moose.ston +++ b/.smalltalk.moose.ston @@ -1,5 +1,6 @@ SmalltalkCISpec { #name : 'FAMIXNGSQL-2-Pharo13-Moose13', + #preLoading : 'scripts/ci/prepare-moose.st', #loading : [ SCIMetacelloLoadSpec { #baseline : 'FAMIXNGSQL', diff --git a/scripts/ci/prepare-moose.st b/scripts/ci/prepare-moose.st new file mode 100644 index 0000000..23d2d75 --- /dev/null +++ b/scripts/ci/prepare-moose.st @@ -0,0 +1,3 @@ +"Use immutable archive dependencies, independent of prebuilt Iceberg checkouts. + Only affects the disposable CI image." +Iceberg enableMetacelloIntegration: false.