Skip to content

Commit

Permalink
Feat asyncapi: add commands to manage schema inheritance (#842)
Browse files Browse the repository at this point in the history
* feat(asyncapi): add command to add child schema

* feat(asyncapi): add command to change schema inheritance

* feat(asyncapi): add command to change schema type

* feat(asyncapi): add command to delete all schema children

* feat(asyncapi): add command to delete one schema child

---------

Co-authored-by: Benjamin Ledentec <[email protected]>
  • Loading branch information
ben-lc and Benjamin Ledentec authored Nov 26, 2024
1 parent 9c198df commit e4897b1
Show file tree
Hide file tree
Showing 36 changed files with 1,327 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import io.apicurio.datamodels.asyncapi.models.AaiSchema;
import io.apicurio.datamodels.asyncapi.visitors.IAaiVisitor;
import io.apicurio.datamodels.cmd.util.ModelUtils;
import io.apicurio.datamodels.core.models.common.ExternalDocumentation;
import io.apicurio.datamodels.core.models.common.INamed;
import io.apicurio.datamodels.core.models.common.IPropertySchema;
Expand Down Expand Up @@ -93,6 +94,22 @@ public AaiSchema createPropertySchema(String propertyName) {
return rval;
}

/**
* Restores a deleted oneOf schema at the position it was originally at.
* @param schema
*/
public void restoreOneOfSchema(Integer index, AaiSchema schema) {
this.oneOf = ModelUtils.restoreListEntry(index, schema, this.oneOf);
}

public void restoreAnyOfSchema(Integer index, AaiSchema schema) {
this.anyOf = ModelUtils.restoreListEntry(index, schema, this.anyOf);
}

public void restoreAllOfSchema(Integer index, AaiSchema schema) {
this.allOf = ModelUtils.restoreListEntry(index, schema, this.allOf);
}

/* ************************************************************************
* Schema subclasses.
* ************************************************************************ */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@
import java.util.List;

import io.apicurio.datamodels.Library;
import io.apicurio.datamodels.asyncapi.models.AaiSchema;
import io.apicurio.datamodels.cmd.AbstractCommand;
import io.apicurio.datamodels.cmd.util.ModelUtils;
import io.apicurio.datamodels.compat.NodeCompat;
import io.apicurio.datamodels.core.models.DocumentType;
import io.apicurio.datamodels.core.models.common.Schema;
import io.apicurio.datamodels.openapi.models.OasSchema;
import io.apicurio.datamodels.openapi.v3.models.Oas30Schema;
import io.apicurio.datamodels.openapi.v3.models.Oas30Schema.Oas30AnyOfSchema;
Expand All @@ -42,19 +44,32 @@ public abstract class AbstractSchemaInhCommand extends AbstractCommand {
* Determines the current inheritance type for the given schema.
* @param schema
*/
static String getInheritanceType(OasSchema schema) {
if (ModelUtils.isDefined(schema.allOf)) {
return TYPE_ALL_OF;
}
if (schema.ownerDocument().getDocumentType() == DocumentType.openapi3) {
Oas30Schema schema30 = (Oas30Schema) schema;
if (ModelUtils.isDefined(schema30.anyOf)) {
static String getInheritanceType(Schema schema) {
if (schema instanceof OasSchema) {
if (ModelUtils.isDefined(((OasSchema) schema).allOf)) {
return TYPE_ALL_OF;
}
if (schema.ownerDocument().getDocumentType() == DocumentType.openapi3) {
Oas30Schema schema30 = (Oas30Schema) schema;
if (ModelUtils.isDefined(schema30.anyOf)) {
return TYPE_ANY_OF;
}
if (ModelUtils.isDefined(schema30.oneOf)) {
return TYPE_ONE_OF;
}
}
} else if (schema instanceof AaiSchema) {
if (ModelUtils.isDefined(((AaiSchema) schema).allOf)) {
return TYPE_ALL_OF;
}
if (ModelUtils.isDefined(((AaiSchema) schema).anyOf)) {
return TYPE_ANY_OF;
}
if (ModelUtils.isDefined(schema30.oneOf)) {
if (ModelUtils.isDefined(((AaiSchema) schema).oneOf)) {
return TYPE_ONE_OF;
}
}

return TYPE_NONE;
}

Expand All @@ -63,20 +78,18 @@ static String getInheritanceType(OasSchema schema) {
* @param parentSchema
* @param inheritanceType
*/
protected OasSchema createSchema(OasSchema parentSchema, String inheritanceType) {
protected Schema createSchema(Schema parentSchema, String inheritanceType) {
if (NodeCompat.equals(TYPE_ALL_OF, inheritanceType)) {
return parentSchema.createAllOfSchema();
return createAllOfSchema(parentSchema);
}
if (NodeCompat.equals(TYPE_ANY_OF, inheritanceType)) {
Oas30Schema schema30 = (Oas30Schema) parentSchema;
return schema30.createAnyOfSchema();
return createAnyOfSchema(parentSchema);
}
if (NodeCompat.equals(TYPE_ONE_OF, inheritanceType)) {
Oas30Schema schema30 = (Oas30Schema) parentSchema;
return schema30.createOneOfSchema();
return createOneOfSchema(parentSchema);
}
// TODO is it possible to get here? if so what should we do?
return parentSchema.createAllOfSchema();
return createAllOfSchema(parentSchema);
}

/**
Expand All @@ -85,24 +98,73 @@ protected OasSchema createSchema(OasSchema parentSchema, String inheritanceType)
* @param targetSchema
* @param inheritanceType
*/
protected void copySchemaJsTo(List<Object> schemas, OasSchema targetSchema, String inheritanceType) {
protected void copySchemaJsTo(List<Object> schemas, Schema targetSchema, String inheritanceType) {
if (NodeCompat.equals(TYPE_ALL_OF, inheritanceType)) {
schemas.forEach(ser -> {
targetSchema.addAllOfSchema((OasSchema) Library.readNode(ser, targetSchema.createAllOfSchema()));
addAllOfSchema(targetSchema, (Schema) Library.readNode(ser, createAllOfSchema(targetSchema)));
});
}
if (NodeCompat.equals(TYPE_ANY_OF, inheritanceType)) {
Oas30Schema targetSchema30 = (Oas30Schema) targetSchema;
schemas.forEach(ser -> {
targetSchema30.addAnyOfSchema((Oas30AnyOfSchema) Library.readNode(ser, targetSchema30.createAnyOfSchema()));
addAnyOfSchema(targetSchema, (Schema) Library.readNode(ser, createAnyOfSchema(targetSchema)));
});
}
if (NodeCompat.equals(TYPE_ONE_OF, inheritanceType)) {
Oas30Schema targetSchema30 = (Oas30Schema) targetSchema;
schemas.forEach(ser -> {
targetSchema30.addOneOfSchema((Oas30OneOfSchema) Library.readNode(ser, targetSchema30.createOneOfSchema()));
addOneOfSchema(targetSchema, (Schema) Library.readNode(ser, createOneOfSchema(targetSchema)));
});
}
}

private static void addAllOfSchema(Schema to, Schema from) {
if (to instanceof OasSchema) {
((OasSchema) to).addAllOfSchema((OasSchema) from);
} else if (to instanceof AaiSchema) {
((AaiSchema) to).addAllOfSchema((AaiSchema) from);
}
}

private static Schema createAllOfSchema(Schema schema) {
if (schema instanceof OasSchema) {
return ((OasSchema) schema).createAllOfSchema();
} else if (schema instanceof AaiSchema) {
return ((AaiSchema) schema).createAllOfSchema();
}
return null;
}

private static void addAnyOfSchema(Schema to, Schema from) {
if (to instanceof Oas30Schema) {
((Oas30Schema) to).addAnyOfSchema((Oas30AnyOfSchema) from);
} else if (to instanceof AaiSchema) {
((AaiSchema) to).addAnyOfSchema((AaiSchema) from);
}
}

private static Schema createAnyOfSchema(Schema schema) {
if (schema instanceof Oas30Schema) {
return ((Oas30Schema) schema).createAnyOfSchema();
} else if (schema instanceof AaiSchema) {
return ((AaiSchema) schema).createAnyOfSchema();
}
return null;
}

private static void addOneOfSchema(Schema to, Schema from) {
if (to instanceof Oas30Schema) {
((Oas30Schema) to).addOneOfSchema((Oas30OneOfSchema) from);
} else if (to instanceof AaiSchema) {
((AaiSchema) to).addOneOfSchema((AaiSchema) from);
}
}

private static Schema createOneOfSchema(Schema schema) {
if (schema instanceof Oas30Schema) {
return ((Oas30Schema) schema).createOneOfSchema();
} else if (schema instanceof AaiSchema) {
return ((AaiSchema) schema).createOneOfSchema();
}
return null;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package io.apicurio.datamodels.cmd.commands;

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import io.apicurio.datamodels.Library;
import io.apicurio.datamodels.asyncapi.models.AaiSchema;
import io.apicurio.datamodels.compat.LoggerCompat;
import io.apicurio.datamodels.compat.MarshallCompat;
import io.apicurio.datamodels.compat.NodeCompat;
import io.apicurio.datamodels.core.models.Document;
import io.apicurio.datamodels.core.models.NodePath;

import java.util.List;

/**
* Asyncapi equivalent of {@link AddChildSchemaCommand}
*/
public class AddChildSchemaCommand_Aai20 extends AbstractSchemaInhCommand {
public NodePath _schemaPath;
public String _newChildSchemaType;
@JsonDeserialize(using= MarshallCompat.NullableJsonNodeDeserializer.class)
public Object _newChildSchemaObj;
public boolean _nullChildList;
public int _childIndex;

AddChildSchemaCommand_Aai20() {
}

AddChildSchemaCommand_Aai20(AaiSchema schema, AaiSchema childSchema, String childType) {
this._schemaPath = Library.createNodePath(schema);
this._newChildSchemaObj = Library.writeNode(childSchema);
this._newChildSchemaType = childType;
}

/**
* @see io.apicurio.datamodels.cmd.ICommand#execute(io.apicurio.datamodels.core.models.Document)
*/
@Override
public void execute(Document document) {
LoggerCompat.info("[AddChildSchemaCommand_Aai20] Executing.");
this._nullChildList = false;
this._childIndex = -1;

AaiSchema schema = (AaiSchema) this._schemaPath.resolve(document);
if (this.isNullOrUndefined(schema)) {
return;
}

List<AaiSchema> schemas = null;
AaiSchema newSchema = null;
if (NodeCompat.equals(TYPE_ALL_OF, _newChildSchemaType)) {
schemas = schema.allOf;
newSchema = schema.createAllOfSchema();
Library.readNode(this._newChildSchemaObj, newSchema);
schema.addAllOfSchema(newSchema);
this._childIndex = schema.allOf.size() - 1;
}
if (NodeCompat.equals(TYPE_ANY_OF, _newChildSchemaType)) {
schemas = schema.anyOf;
newSchema = schema.createAnyOfSchema();
Library.readNode(this._newChildSchemaObj, newSchema);
schema.addAnyOfSchema(newSchema);
this._childIndex = schema.anyOf.size() - 1;
}
if (NodeCompat.equals(TYPE_ONE_OF, _newChildSchemaType)) {
schemas = schema.oneOf;
newSchema = schema.createOneOfSchema();
Library.readNode(this._newChildSchemaObj, newSchema);
schema.addOneOfSchema(newSchema);
this._childIndex = schema.oneOf.size() - 1;
}

if (schemas == null) {
this._nullChildList = true;
}

}

/**
* @see io.apicurio.datamodels.cmd.ICommand#undo(io.apicurio.datamodels.core.models.Document)
*/
@Override
public void undo(Document document) {
LoggerCompat.info("[AddChildSchemaCommand_Aai20] Reverting.");

AaiSchema schema = (AaiSchema) this._schemaPath.resolve(document);
if (this.isNullOrUndefined(schema) || this._childIndex == -1) {
return;
}

if (NodeCompat.equals(TYPE_ALL_OF, _newChildSchemaType)) {
if (this._nullChildList) {
schema.allOf = null;
} else {
schema.allOf.remove(this._childIndex);
}
}
if (NodeCompat.equals(TYPE_ANY_OF, _newChildSchemaType)) {
if (this._nullChildList) {
schema.anyOf = null;
} else {
schema.anyOf.remove(this._childIndex);
}
}
if (NodeCompat.equals(TYPE_ONE_OF, _newChildSchemaType)) {
if (this._nullChildList) {
schema.oneOf = null;
} else {
schema.oneOf.remove(this._childIndex);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ private void switchInheritance(OasSchema schema, String fromType, String toType,
// when switching FROM "none" - wrap any properties this schema has into another
// schema and add it to the list of schemas
if (NodeCompat.equals(TYPE_NONE, fromType)) {
OasSchema wrapperSchema = createSchema(schema, fromType);
OasSchema wrapperSchema = (OasSchema) createSchema(schema, fromType);
wrapperSchema.type = "object";
moveProperties(schema, wrapperSchema);

Expand Down
Loading

0 comments on commit e4897b1

Please sign in to comment.