Skip to content

Conversation

@Prajwala-Adiga
Copy link
Contributor

@Prajwala-Adiga Prajwala-Adiga commented Nov 27, 2025

Description of Changes

This pull request introduces the initial implementation of the Asset Administration Shell (AAS) Repository service in the BaSyx Go components.

#Key Features Added

AAS Repository Service

  • Introduced a new AAS Repository service following the structure of existing Submodel and Discovery services
  • Implemented basic CRUD support for Asset Administration Shells:
    • GET /shells
    • GET /shells/{id}
    • POST /shells
    • DELETE /shells/{id}

PostgreSQL Persistence Layer

  • Implemented PostgreSQLAASDatabase backend
  • Added persistence methods:
    • GetAllAAS
    • GetAASByID
    • InsertAAS
    • DeleteAASByID
  • Refactored insertion logic to use goqu for safer SQL construction
  • Reduced cognitive complexity by splitting large persistence functions into focused helpers

Database Schema Integration

  • Integrated AAS tables into the global basyxschema.sql (instead of a service-specific schema)
  • Added and validated the following AAS-related tables:
    • aas
    • aas_display_name_ref
    • aas_description_ref
    • administration
    • asset_information
    • aas_specific_asset_id
    • aas_resource
    • asset_information_default_thumbnail
    • aas_extension (schema only, not yet used)
  • Fixed schema ordering, foreign key references, and trigger definitions
  • Verified schema loading via service startup

AAS Data Model Support

  • Full persistence and retrieval of:
    • Core AAS metadata
    • DisplayName
    • Description
    • AdministrativeInformation
    • AssetInformation
    • SpecificAssetIds
    • DefaultThumbnail
    • DerivedFrom references
  • Explicitly excluded for now (to be implemented in follow-up PRs):
    • Extensions
    • EmbeddedDataSpecifications
    • Submodel references

Testing & Quality Assurance

  • Added unit tests for the PostgreSQL persistence layer using sqlmock
  • Added integration tests for the AAS Repository service using Docker Compose
    • Service startup validation
    • End-to-end POST - GET flow against a real PostgreSQL instance
  • Fixed all golangci-lint and staticcheck issues (including SA5011 nil-dereference warnings) - in the internal/common/builder/unit_test/reference_builder_test.go

Configuration & Tooling

  • Updated main.go to:
  • Initialize database connection
  • Load global schema
  • Register AAS routes
  • Updated launch.json for local debugging
  • Aligned Docker setup with existing BaSyx services
  • Ensured compatibility with CI lint configuration

Related Issue #66

Notes for Reviewers

AAS columns (Extensions, EmbeddedDataSpecifications, Submodel linking) are not implemented. They are planned for follow-up PRs once the foundation is reviewed and merged.

Copy link
Contributor

@Martin187187 Martin187187 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You’ve implemented the new endpoints with a minimal version. This is a good starting point. Keep in mind that AssetAdministrationShell contains many more fields, so I assume this was meant as a prototype. I’ve added a few comments for future iterations:

  • Please use goqu as our query builder. Make sure to review existing patterns so the queries remain consistent with the rest of the codebase.
  • Make use of the global schema file. Many tables and subqueries can be reused, and this will help avoid duplication and ensure consistent structure.
  • Use our standard error response format. I included an example in the comments, all new endpoints should follow this structure.

Let me know if you need any guidance integrating these points.

@Prajwala-Adiga Prajwala-Adiga marked this pull request as draft December 17, 2025 13:54
Copy link
Contributor

@Martin187187 Martin187187 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’ve reviewed your changes and see two critical points:

  • Scalability of the GET request: The current implementation does not scale well with the number of AAS entries in the database. Ideally, the number of queries should remain constant, regardless of how much data is stored.

  • Code reuse and batching: A significant amount of existing code could be reused (e.g. LangStringNameTypes, LangStringTextTypes, SpecificAssetIds). These utilities are already highly optimized because they operate in batches. Reusing them would both improve performance and increase overall code quality and consistency.

The first point is particularly important from a scalability perspective. The second point is more about maintainability and quality, but it could still have a positive performance impact.
Feel free to share your thoughts—happy to discuss trade-offs or alternative approaches.



CREATE TABLE IF NOT EXISTS aas_extension (
aas_id VARCHAR(2048) NOT NULL REFERENCES aas(id) ON DELETE CASCADE,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use the primary key to reference to aas

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Martin187187 Could you help me understand this comment? 'id' is the PK for the table aas

CREATE TABLE IF NOT EXISTS aas ( id VARCHAR(2048) PRIMARY KEY, id_short VARCHAR(2048), category VARCHAR(2048), model_type VARCHAR(128) NOT NULL, administration_id BIGINT REFERENCES administrative_information(id), asset_information_id BIGINT REFERENCES asset_information(id), derived_from_reference_id BIGINT REFERENCES reference(id) );

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, my explanation is extremly bad here. What i meant:

  • Create a new primary key in aas that is an integer.
  • make id unique in aas table. use the new primary key for references as it is more efficient to use integer in relationships (less byte)
    This doesnt change any logic but would be best practice for designing schemas.

return ai, nil
}

func (p *PostgreSQLAASDatabase) insertReference(ref *model.Reference) (int64, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


// insertDisplayName inserts the DisplayName entries for the AAS.
func (p *PostgreSQLAASDatabase) insertDisplayName(aas model.AssetAdministrationShell) error {
if len(aas.DisplayName) == 0 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}

// insertDescription inserts the Description entries for the AAS.
func (p *PostgreSQLAASDatabase) insertDescription(aas model.AssetAdministrationShell) error {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines +860 to +878
// 3) Specific Asset IDs
for _, sid := range aas.AssetInformation.SpecificAssetIds {
query, _, err = dialect.
Insert("aas_specific_asset_id").
Rows(goqu.Record{
"asset_information_id": assetInfoID,
"name": sid.Name,
"value": sid.Value,
"semantic_id": sid.SemanticID,
"external_subject_id": sid.ExternalSubjectID,
}).
ToSQL()
if err != nil {
return err
}
if _, err = p.DB.Exec(query); err != nil {
return err
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines +750 to +765
for _, d := range aas.Description {
query, _, err = dialect.
Insert("lang_string_text_type").
Rows(goqu.Record{
"lang_string_text_type_reference_id": descRefID,
"language": d.Language,
"text": d.Text,
}).
ToSQL()
if err != nil {
return err
}
if _, err = p.DB.Exec(query); err != nil {
return err
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

@FriedJannik FriedJannik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added some things i caught - i think Martin reviewed the rest :)

basyxschema.sql Outdated
CREATE TYPE modelling_kind AS ENUM ('Instance', 'Template');
END IF;
END $$;
END;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are a lot of these changes - are those necessarry? If o, would you mind reverting them so that the diff is not that large ? :)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These were the changes that were giving me compilation errors. So, I was forced to make these changes. But to give the benefit of doubt, I can revert them and test them again for completeness.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reverted

basyxschema.sql Outdated

CREATE TABLE IF NOT EXISTS asset_information (
id BIGSERIAL PRIMARY KEY,
asset_kind VARCHAR(64),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use the ENUM here (cf ll.136-141)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed



# ---------- Runtime stage ----------
FROM alpine:3.19
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use alpine 3.22 here aswell

Suggested change
FROM alpine:3.19
FROM alpine:3.22

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this file needed?

@Martin187187
Copy link
Contributor

I just noticed that the current specficAssetId table has descriptorId as a column. Therefore this table cannot be reused.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants