Skip to content

Commit

Permalink
support patch generation
Browse files Browse the repository at this point in the history
  • Loading branch information
tomsontom committed Dec 13, 2024
1 parent f3c08f4 commit 85be8bc
Show file tree
Hide file tree
Showing 6 changed files with 225 additions and 178 deletions.
120 changes: 76 additions & 44 deletions dsl/src/cli/java-client-api/record.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { CompositeGeneratorNode, NL, toString } from "langium/generate";
import { CompositeGeneratorNode, IndentNode, NL, toString } from "langium/generate";
import { Artifact } from "../artifact-generator.js";
import { JavaImportsCollector, JavaClientAPIGeneratorConfig, generateCompilationUnit, toPath, resolveObjectType } from "../java-gen-utils.js";
import { MResolvedRecordType, allRecordProperties, isMInlineEnumType, isMKeyProperty, isMProperty, isMRevisionProperty } from "../model.js";
import { MBaseProperty, MResolvedRecordType, allRecordProperties, isMInlineEnumType, isMKeyProperty, isMProperty, isMRevisionProperty } from "../model.js";
import { generateInlineEnum } from "./enum.js";
import { toFirstUpper } from "../util.js";
import { generateBuilderProperty, generateProperty } from "./shared.js";
Expand All @@ -22,13 +22,86 @@ export function generateRecord(t: MResolvedRecordType, artifactConfig: JavaClien
};
}

export function generateRecordPatch(
child: IndentNode,
allProps: readonly MBaseProperty[],
artifactConfig: JavaClientAPIGeneratorConfig,
fqn: (type: string) => string,
superPatchTypes: string[]) {
if( superPatchTypes.length > 0 ) {
child.append(`public interface Patch extends ${superPatchTypes.map( t => `${t}.Patch`).join(', ')} {`,NL)
} else {
child.append('public interface Patch {',NL)
}

child.indent( patchBody => {
if( allProps.find( p => !isMKeyProperty(p) && !isMRevisionProperty(p) ) ) {
patchBody.append('public enum Props {',NL)
patchBody.indent(enumBody => {
allProps.filter( p => !isMKeyProperty(p) && !isMRevisionProperty(p) ).forEach( (p, idx) => {
enumBody.append(`${p.name.toUpperCase()},`,NL)
})
})

patchBody.append('}',NL,NL)

patchBody.append('public boolean isSet(Props prop);', NL,NL)
}

allProps.forEach( p => {
if( isMKeyProperty(p) || isMRevisionProperty(p) ) {
generateProperty(patchBody, p, artifactConfig, fqn)
} else if( p.nullable === false && p.array === false ) {
generateProperty(patchBody, p, artifactConfig, fqn, true)
}
} )
allProps.forEach( p => {
if( ! isMKeyProperty(p) && ! isMRevisionProperty(p) && p.nullable === false && p.array === false ) {
const Consumer = fqn('java.util.function.Consumer');
const Function = fqn('java.util.function.Function');
if( p.variant === 'union' || p.variant === 'record' ) {

} else if( typeof p.type === 'string' ) {
patchBody.append(`public static void if${toFirstUpper(p.name)}(Patch dto, ${Consumer}<${resolveObjectType(p.type, artifactConfig.nativeTypeSubstitues, fqn)}> consumer) {`,NL)
patchBody.indent( mBody => {
mBody.append(`if( dto.isSet(Props.${p.name.toUpperCase()}) ) {`,NL)
mBody.indent( block => {
block.append(`consumer.accept(dto.${p.name}());`,NL)
})
mBody.append('}',NL)
} )
patchBody.append('}',NL)

patchBody.append(`public static <T> T if${toFirstUpper(p.name)}(Patch dto, ${Function}<${resolveObjectType(p.type, artifactConfig.nativeTypeSubstitues, fqn)}, T> consumer, T defaultValue) {`,NL)
patchBody.indent( mBody => {
mBody.append(`if( dto.isSet(Props.${p.name.toUpperCase()}) ) {`,NL)
mBody.indent( block => {
block.append(`return consumer.apply(dto.${p.name}());`,NL)
})
mBody.append('}',NL)

mBody.append('return defaultValue;',NL)
} )

patchBody.append('}',NL)
}
}
})
})
child.append('}',NL)
}

export function generateRecordContent(t: MResolvedRecordType, artifactConfig: JavaClientAPIGeneratorConfig, fqn: (type: string) => string): CompositeGeneratorNode {
const node = new CompositeGeneratorNode();

const superTypes = t.resolved.unions.length > 0 ? [
...t.resolved.unions.map( u => `${u.name}DTO`)
] : [ 'BaseDTO' ];

const superPatchTypes = t.resolved.unions.length > 0 ? [
...t.resolved.unions.map( u => `${u.name}DTO`)
] : [];

node.append(`public interface ${t.name}DTO extends ${superTypes.join(', ')} {`, NL)

const sharedProps = t.resolved.unions.flatMap(u => u.resolved.sharedProps);
Expand Down Expand Up @@ -69,48 +142,7 @@ export function generateRecordContent(t: MResolvedRecordType, artifactConfig: Ja
} )
child.append('}', NL)
if( t.patchable ) {
child.append('public interface Patch {',NL)
child.indent( patchBody => {
if( allProps.find( p => !isMKeyProperty(p) && !isMRevisionProperty(p) ) ) {
patchBody.append('public enum Props {',NL)
patchBody.indent(enumBody => {
allProps.filter( p => !isMKeyProperty(p) && !isMRevisionProperty(p) ).forEach( (p, idx) => {
enumBody.append(`${p.name.toUpperCase()},`,NL)
})
})

patchBody.append('}',NL,NL)

patchBody.append('public boolean isSet(Props prop);', NL,NL)
}

allProps.forEach( p => {
if( isMKeyProperty(p) || isMRevisionProperty(p) ) {
generateProperty(patchBody, p, artifactConfig, fqn)
} else if( p.nullable === false && p.array === false ) {
generateProperty(patchBody, p, artifactConfig, fqn)
}
} )
allProps.forEach( p => {
if( ! isMKeyProperty(p) && ! isMRevisionProperty(p) && p.nullable === false && p.array === false ) {
const Consumer = fqn('java.util.function.Consumer');
if( p.variant === 'union' || p.variant === 'record' ) {

} else if( typeof p.type === 'string' ) {
patchBody.append(`public static void if${toFirstUpper(p.name)}(Patch dto, ${Consumer}<${resolveObjectType(p.type, artifactConfig.nativeTypeSubstitues, fqn)}> consumer) {`,NL)
patchBody.indent( mBody => {
mBody.append(`if( dto.isSet(Props.${p.name.toUpperCase()}) ) {`,NL)
mBody.indent( block => {
block.append(`consumer.accept(dto.${p.name}());`,NL)
})
mBody.append('}',NL)
} )
patchBody.append('}',NL)
}
}
})
})
child.append('}',NL)
generateRecordPatch(child, allProps, artifactConfig, fqn, superPatchTypes);
}
});
node.append('}',NL)
Expand Down
8 changes: 5 additions & 3 deletions dsl/src/cli/java-client-api/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ export function generateProperty(
node: IndentNode,
property: MKeyProperty | MRevisionProperty | MProperty,
artifactConfig: JavaClientAPIGeneratorConfig,
fqn: (type: string) => string
fqn: (type: string) => string,
isPatch?: boolean
) {
if( property.doc ) {
node.append('/**', NL)
Expand All @@ -46,10 +47,11 @@ export function generateProperty(
node.append(`public ${builtinToJavaType(property.type, fqn)} ${property.name}();`,NL)
} else {
if( property.variant === 'union' || property.variant === 'record' ) {
const type = isPatch ? `${property.type}DTO.Patch` : `${property.type}DTO`;
if( property.array ) {
node.append(`public ${fqn('java.util.List')}<${property.type}DTO> ${property.name}();`,NL)
node.append(`public ${fqn('java.util.List')}<${type}> ${property.name}();`,NL)
} else {
node.append(`public ${property.type}DTO ${property.name}();`,NL)
node.append(`public ${type} ${property.name}();`,NL)
}
} else if( typeof property.type === 'string' ) {
if( property.array ) {
Expand Down
8 changes: 7 additions & 1 deletion dsl/src/cli/java-client-api/union.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import {
generateBuilderProperty,
generateProperty
} from "./shared.js";
import { generateRecordContent } from "./record.js";
import { generateRecordContent, generateRecordPatch } from "./record.js";

export function generateUnion(t: MResolvedUnionType, artifactConfig: JavaClientAPIGeneratorConfig): Artifact {
const packageName = `${artifactConfig.rootPackageName}.dto`;
Expand Down Expand Up @@ -56,6 +56,12 @@ export function generateUnionContent(t: MResolvedUnionType, artifactConfig: Java
}
});

if( t.resolved.records.find( r => r.patchable ) ) {
node.indent( child => {
generateRecordPatch(child, t.resolved.sharedProps, artifactConfig, fqn, []);
});
}

if( t.resolved.sharedProps.length > 0 ) {
node.indent( child => {
t.resolved.sharedProps.forEach( p => generateProperty(child, p, artifactConfig, fqn) )
Expand Down
55 changes: 28 additions & 27 deletions dsl/src/cli/java-server-jakarta-ws/record.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Artifact } from "../artifact-generator.js";
import { builtinToJavaType, generateCompilationUnit, JavaImportsCollector, JavaServerJakartaWSGeneratorConfig, resolveObjectType, resolveType, toPath } from "../java-gen-utils.js";
import { allRecordProperties, isMKeyProperty, isMProperty, isMRevisionProperty, isMUnionType, MBaseProperty, MResolvedRecordType, MResolvedRSDModel } from "../model.js";
import { toFirstUpper } from "../util.js";
import { generateProperty, generatePropertyAccess } from "./shared.js";

export function generateRecord(t: MResolvedRecordType, model: MResolvedRSDModel, artifactConfig: JavaServerJakartaWSGeneratorConfig): Artifact | undefined {
if( t.resolved.unions.length === 1 ) {
Expand All @@ -27,11 +28,13 @@ export function generateRecordContent(t: MResolvedRecordType, artifactConfig: Ja

const dtoInterface = fqn(`${artifactConfig.rootPackageName}.service.dto.${t.name}DTO`);

node.append(`public record ${t.name}DTOImpl(`,NL)
node.append(`public class ${t.name}DTOImpl implements ${dtoInterface} {`,NL)
node.indent( param => {
allProps.forEach( (property, idx, arr) => {
const end = idx + 1 < arr.length ? ',' : `) implements ${dtoInterface} {`
addProperty(param, property, end, artifactConfig, fqn);
allProps.forEach( property => {
generateProperty(param, property, artifactConfig, fqn);
});
allProps.forEach( property => {
generatePropertyAccess(param, property, artifactConfig, fqn);
});
})

Expand All @@ -50,26 +53,20 @@ export function generateRecordContent(t: MResolvedRecordType, artifactConfig: Ja
})
mBody.append('}')
mBody.appendNewLine();
mBody.append(`return new ${t.name}DTOImpl(`,NL);
mBody.indent( inner => {
allProps.forEach( (p, idx, arr) => {
if( isMKeyProperty(p) || isMRevisionProperty(p) || (p.variant !== 'union' && p.variant !== 'record') ) {
inner.append(`source.${p.name}()`)
mBody.append(`var rv = new ${t.name}DTOImpl();`,NL)
allProps.forEach( (p, idx, arr) => {
if( isMKeyProperty(p) || isMRevisionProperty(p) || (p.variant !== 'union' && p.variant !== 'record') ) {
mBody.append(`rv.${p.name} = source.${p.name}();`)
} else {
if( p.array ) {
mBody.append(`rv.${p.name} = source.${p.name}().stream().map(${p.type}DTOImpl::of).toList();`)
} else {
if( p.array ) {
inner.append(`source.${p.name}().stream().map(${p.type}DTOImpl::of).toList()`)
} else {
inner.append(`${p.type}DTOImpl.of(source.${p.name}())`)
}
}
if( idx + 1 < arr.length ) {
inner.append(',')
mBody.append(`rv.${p.name} = ${p.type}DTOImpl.of(source.${p.name}());`)
}
inner.appendNewLine()
});
})

mBody.append(');',NL)
}
mBody.appendNewLine()
});
mBody.append('return rv;',NL);
})
body.append('}')
} )
Expand All @@ -79,7 +76,7 @@ export function generateRecordContent(t: MResolvedRecordType, artifactConfig: Ja
body.append(`public static class BuilderImpl implements Builder {`, NL);
body.indent( param => {
allProps.forEach( (property) => {
addProperty(param, property, ";", artifactConfig, fqn);
generateProperty(param, property, artifactConfig, fqn);
});
param.appendNewLine();
allProps.forEach( (property) => {
Expand Down Expand Up @@ -127,8 +124,12 @@ export function generateRecordContent(t: MResolvedRecordType, artifactConfig: Ja
param.appendNewLine();
param.append(`public ${artifactConfig.rootPackageName}.service.dto.${t.name}DTO build() {`,NL)
param.indent( methodBody => {
methodBody.append(`return new ${t.name}DTOImpl(${allProps.map(p => p.name).join(', ')});`,NL)
})
methodBody.append(`var rv = new ${t.name}DTOImpl();`,NL)
allProps.forEach(p => {
methodBody.append(`rv.${p.name} = ${p.name};`, NL)
})
methodBody.append(`return rv;`,NL)
});
param.append('}', NL)
});
body.append('}',NL)
Expand Down Expand Up @@ -204,7 +205,7 @@ export function addBuilderMethod(param: IndentNode, property: MBaseProperty, art
}
}

function addProperty(param: IndentNode, property: MBaseProperty, end: string, artifactConfig: JavaServerJakartaWSGeneratorConfig, fqn: (type: string) => string) {
/*function addProperty(param: IndentNode, property: MBaseProperty, end: string, artifactConfig: JavaServerJakartaWSGeneratorConfig, fqn: (type: string) => string) {
if( isMKeyProperty(property) ) {
param.append(`${builtinToJavaType(property.type, fqn)} ${property.name}`, end, NL)
} else if( isMRevisionProperty(property) ) {
Expand All @@ -226,4 +227,4 @@ function addProperty(param: IndentNode, property: MBaseProperty, end: string, ar
param.append(`${toFirstUpper(property.name)} ${property.name}`, end, NL)
}
}
}
}*/
Loading

0 comments on commit 85be8bc

Please sign in to comment.