Exemple #1
0
def _write_entity(entity: Entity, output: pathlib.Path, package: str) -> None:
    #if entity.name != "UserHomeContent":
    #    return
    if entity.methods:
        service = output / entity.package / "service"
        service.mkdir(parents=True, exist_ok=True)
        service_class = service / f"{entity.name}Service.java"
        with IndentedWriter(path=service_class) as writer:
            _write_service(writer, entity, package)

    datamodel = output / entity.package / "datamodel"
    datamodel.mkdir(parents=True, exist_ok=True)
    datamodel_class = datamodel / f"{entity.name}Entity.java"
    import_list = None
    with IndentedWriter(path=datamodel_class) as writer:
        import_list = _write_datamodel(writer, entity, output, package, None)
    with IndentedWriter(path=datamodel_class) as writer:
        _write_datamodel(writer, entity, output, package, import_list)

    logic = output / entity.package / "logic"
    logic.mkdir(parents=True, exist_ok=True)
    logic_class = logic / f"{entity.name}.java"
    if not logic_class.exists():
        with IndentedWriter(path=logic_class) as writer:
            _write_logic(writer, entity, package)
Exemple #2
0
def _write_enum(writer: IndentedWriter, property: Property,
                cases: List[str]) -> None:
    writer.writeln(f"export enum {property.name} {{")

    for case in cases:
        value = "'" + case + "'"
        if case.isnumeric() or case.replace('.', '', 1).isdigit():
            name = "'" + property.name + "_" + case + "'"
            value = case
        elif case.find(".") != -1:
            name = "'" + case + "'"
Exemple #3
0
def _write_datamodel(writer: IndentedWriter, entity: Entity,
                     output: pathlib.Path, package: str,
                     import_list: Set) -> None:
    writer.writeln(f"package {package}.{_package(entity.package)}.datamodel;")

    writer.newline()

    if import_list is not None:
        import_list.update({"java.io.Serializable"})

        for dependency in _get_dependencies(entity):
            import_list.add(
                f"{package}.{_package(dependency.package)}.logic." +
                dependency.name)

        for import_item in sorted(import_list):
            writer.writeln(f"import {import_item};")
    else:
        import_list = set()

    writer.newline()

    import_list = _write_datamodel_class(writer, entity.root, import_list)

    return import_list
Exemple #4
0
def _write_logic_inner(writer: IndentedWriter, message: Message) -> None:
    if len(message.extends) > 1:
        shared_interface = _get_shared_interface(message)

        writer.writeln(f"interface {message.name} : {message.name}Entity {{")
        indented_writer = writer.indented()
        writer.writeln("}")
        writer.newline()

        for extends in message.extends:
            _write_logic_class(writer, extends.root, shared_interface)
            writer.newline()
    else:
        _write_logic_class(writer, message)
Exemple #5
0
def _write_datamodel(writer: IndentedWriter, entity: Entity,
                     output: pathlib.Path) -> None:
    dependency_statements: Set[str] = set()

    dependencies = _dependencies(entity.root)
    if dependencies:
        for dependency in dependencies:
            name = dependency.root.name
            path = _rel_import(entity.package, dependency.package, name)
            statement = f"import {{ {name} }} from '{str(path)}';"

            dependency_statements.add(statement)

    if dependency_statements:
        for dependency_statement in sorted(dependency_statements):
            writer.writeln(dependency_statement)
        writer.newline()

    _write_enums(writer, entity.root)
    _write_datamodel_class(writer, entity.root)
Exemple #6
0
def _write_entity(entity: Entity, output: pathlib.Path, package: str,
                  force: bool) -> None:
    if entity.methods:
        service = output / entity.package / "service"
        service.mkdir(parents=True, exist_ok=True)
        service_class = service / f"{entity.name}Service.kt"
        with IndentedWriter(path=service_class) as writer:
            _write_service(writer, entity, package)

    datamodel = output / entity.package / "datamodel"
    datamodel.mkdir(parents=True, exist_ok=True)
    datamodel_class = datamodel / f"{entity.name}Entity.kt"
    import_list = None
    with IndentedWriter(path=datamodel_class) as writer:
        import_list = _write_datamodel(writer, entity, output, package, None)
    with IndentedWriter(path=datamodel_class) as writer:
        _write_datamodel(writer, entity, output, package, import_list)

    logic = output / entity.package / "logic"
    logic.mkdir(parents=True, exist_ok=True)
    logic_class = logic / f"{entity.name}.kt"
    if force or not logic_class.exists():
        with IndentedWriter(path=logic_class) as writer:
            _write_logic(writer, entity, package)
Exemple #7
0
def _write_logic(writer: IndentedWriter, entity: Entity, package: str) -> None:
    writer.writeln(f"package {package}.{_package(entity.package)}.logic;")

    writer.newline()

    import_list = [
        f"{package}.{_package(entity.package)}.datamodel.{entity.name}Entity",
        f"java.io.Serializable", "androidx.annotation.NonNull",
        "androidx.annotation.Nullable", "java.util.List"
    ]

    for dependency in _get_dependencies(entity):
        import_list.append(f"{package}.{_package(dependency.package)}.logic." +
                           dependency.name)

    for import_item in sorted(set(import_list)):
        writer.writeln(f"import {import_item};")

    writer.newline()

    _write_logic_class(writer, entity.root)
Exemple #8
0
def _write_service_typeadapterfactories(writer: IndentedWriter,
                                        message: Message, prefix: str):
    prefix += message.name
    indented_writer = writer.indented()
    if len(message.extends) > 1:
        indented_writer.writeln("RuntimeTypeAdapterFactory")
        indented_indented_writer = indented_writer.indented()
        indented_indented_writer.writeln(
            f'.of({prefix}::class.java, "__type__")')
        for extends in message.extends:
            indented_indented_writer.writeln(
                f'.registerSubtype({prefix}{extends.name}::class.java, "{pathlib.Path(*extends.path.parts[1:])}")'
            )
    elif len(message.extends) == 1:
        _write_service_typeadapterfactories(writer, message.extends[0].root,
                                            "")
    prefix += "."
    for submessage in message.messages:
        _write_service_typeadapterfactories(writer, submessage, prefix)
Exemple #9
0
def _write_logic(writer: IndentedWriter, entity: Entity, package: str) -> None:
    writer.writeln(f"package {package}.{_package(entity.package)}.logic")

    writer.newline()

    import_list = [
        f"{package}.{_package(entity.package)}.datamodel.{entity.name}Entity"
    ]

    for dependency in _get_dependencies(
            entity, False
    ):  # set this to True to reduce imports, but will give false negatives at the moment
        import_list.append(f"{package}.{_package(dependency.package)}.logic." +
                           dependency.name)
        import_list.append(
            f"{package}.{_package(dependency.package)}.datamodel." +
            dependency.name + "Entity")

    for import_item in sorted(set(import_list)):
        writer.writeln(f"import {import_item}")

    writer.newline()

    _write_logic_inner(writer, entity.root)
Exemple #10
0
def _write_datamodel_class(writer: IndentedWriter,
                           message: Message,
                           import_list: Set,
                           prefix: str = '') -> None:
    writer.write("public")
    if prefix != '':
        writer.append(" static")

    writer.append(f" class {message.name}Entity")
    if message.extends is not None:
        writer.append(f" extends {message.extends.name}")
    writer.appendln(" implements Serializable {")

    writer.newline()

    prefix += message.name + "."

    indented_writer = writer.indented()

    constructor_parameters = []

    for property in message.properties:
        if property.method == "request":
            continue

        type = property.type
        name = property.name
        variable_name = camelcase(name)
        variable_type = _java_type(type)
        nullable = property.nullable

        if property.enum is not None and len(property.enum):
            indented_writer.writeln(f'public enum {name} {{')
            for enum_value in property.enum:
                enum_writer = indented_writer.indented()
                enum_writer.writeln(f'{enum_value},')
            indented_writer.writeln('}')
            indented_writer.newline()
            variable_type = name
        if nullable:
            indented_writer.writeln(f'@Nullable')
            import_list.add("androidx.annotation.Nullable")
        else:
            constructor_parameters.append((variable_name, variable_type))
            indented_writer.writeln(f'@NonNull')
            import_list.add("androidx.annotation.NonNull")

        indented_writer.writeln(f'@SerializedName("{name}")')
        import_list.add("com.google.gson.annotations.SerializedName")
        indented_writer.writeln(f"public {variable_type} {variable_name};")
        indented_writer.newline()

    for submessage in message.messages:
        name = submessage.name
        nullable = submessage.nullable

        if submessage.is_array:
            if submessage.extends is None or submessage.is_non_empty:
                import_list.update(
                    _write_datamodel_class(indented_writer, submessage,
                                           import_list, prefix))
                variable_type = "List<" + prefix + name + ">"
            else:
                variable_type = "List<" + submessage.extends.name + ">"
            variable_name = camelcase(name) + "List"
            import_list.add("java.util.List")
        else:
            if submessage.extends is None or submessage.is_non_empty:
                import_list.update(
                    _write_datamodel_class(indented_writer, submessage,
                                           import_list, prefix))
                variable_type = prefix + name
            else:
                variable_type = submessage.extends.name
            variable_name = camelcase(name)

        if nullable:
            indented_writer.writeln('@Nullable')
            import_list.add("androidx.annotation.Nullable")
        else:
            constructor_parameters.append((variable_name, variable_type))
            indented_writer.writeln('@NonNull')
            import_list.add("androidx.annotation.NonNull")
        indented_writer.writeln(f'@SerializedName("{name}")')
        import_list.add("com.google.gson.annotations.SerializedName")
        indented_writer.writeln(f'public {variable_type} {variable_name};')
        indented_writer.newline()

    super_constructor_parameters = []
    constructor_parameters_string = []

    if message.extends is not None:
        super_constructor_parameters, super_import_list = _get_super_constructor_parameters(
            message.extends.root)
        import_list.update(super_import_list)

        for constructor_parameter in super_constructor_parameters:
            name = constructor_parameter[0]
            type = constructor_parameter[1]

            constructor_parameters_string.append(f'@NonNull {type} {name}')
            import_list.add("androidx.annotation.NonNull")

    for constructor_parameter in constructor_parameters:
        name = constructor_parameter[0]
        type = constructor_parameter[1]

        constructor_parameters_string.append(f'@NonNull {type} {name}')
        import_list.add("androidx.annotation.NonNull")

    indented_writer.writeln(
        f'public {message.name}Entity({", ".join(constructor_parameters_string)}) {{'
    )

    super_arguments_string = []

    for constructor_parameter in super_constructor_parameters:
        name = constructor_parameter[0]
        super_arguments_string.append(name)

    body_writer = indented_writer.indented()
    body_writer.writeln(f'super({", ".join(super_arguments_string)});')

    for constructor_parameter in constructor_parameters:
        name = constructor_parameter[0]

        body_writer.writeln(f'this.{name} = {name};')

    indented_writer.writeln('}')
    indented_writer.newline()

    writer.writeln("}")
    writer.newline()

    return import_list
Exemple #11
0
def _write_datamodel_inner(writer: IndentedWriter,
                           message: Message,
                           import_list: Set,
                           prefix: str = '') -> Set:
    if len(message.extends) > 1:
        shared_interface = _get_shared_interface(message)

        writer.writeln(f"interface {message.name}Entity : Entity {{")
        indented_writer = writer.indented()
        for enum in shared_interface.enums:
            indented_writer.writeln(f"enum class {enum[0]} {{")
            indented_writer.indented().writeln(f'{", ".join(enum[1])}')
            indented_writer.writeln(f"}}")
            writer.newline()
        for variable in shared_interface.variables:
            indented_writer.writeln(f"var {variable.name}: {variable.type}")
        writer.writeln("}")
        writer.newline()

        for extends in message.extends:
            import_list.update(
                _write_datamodel_class(writer, extends.root, import_list,
                                       prefix, shared_interface))
            writer.newline()

        return import_list
    else:
        return _write_datamodel_class(writer, message, import_list, prefix)
Exemple #12
0
def _write_datamodel_class(writer: IndentedWriter,
                           message: Message,
                           prefix: str = '') -> None:
    writer.write(f"export interface {message.name}")
    if message.extends is not None:
        writer.append(f" extends {message.extends.name}")

    variables: Set[str] = set()

    for property in message.properties:
        if property.method == "request":
            continue

        name = property.name

        if property.enum is not None:
            type = name
        else:
            type = _type(property.type)

        variable = name
        variable += f": {type}"
        if property.nullable:
            variable += " | null"
        variable += ";"

        variables.add(variable)

    interfaces: List[Message] = []

    for sub_message in message.messages:
        name = sub_message.name
        type = sub_message.name

        if sub_message.is_array:
            if sub_message.extends is None or len(sub_message.messages) or len(
                    sub_message.properties):
                interfaces.append(sub_message)
                type = f"{name}[]"
            else:
                type = f"{sub_message.extends.name}[]"
        else:
            if sub_message.extends is None or len(sub_message.messages) or len(
                    sub_message.properties):
                interfaces.append(sub_message)
            else:
                type = sub_message.extends.name

        variable = name
        variable += f": {type}"
        if sub_message.nullable:
            variable += " | null"
        variable += ";"

        variables.add(variable)

    # When there are no variables, then just render an empty interface, but with {} on 1 line
    if variables:
        writer.appendln(" {")
        for variable in sorted(variables, key=lambda x: x.split(":")[0]):
            writer.indented().writeln(variable)

        writer.appendln("}")
    else:
        writer.appendln(" {}")

    if interfaces:
        writer.newline()

        for interface in interfaces:
            _write_datamodel_class(writer, interface)
Exemple #13
0
def _write_service(writer: IndentedWriter, entity: Entity,
                   package: str) -> None:
    writer.writeln(f"package {package}.{_package(entity.package)}.service")

    writer.newline()

    dependencies = set()
    dependencies.update([
        "retrofit2.http.Query", "com.google.gson.TypeAdapterFactory",
        f"com.sendrato.app.sdk.gson.RuntimeTypeAdapterFactory"
    ])

    if "GET" in entity.methods or "PUT" in entity.methods or "POST" in entity.methods or "DELETE" in entity.methods:
        dependencies.add("io.reactivex.Single")
    if entity.version != -1:
        dependencies.add("retrofit2.http.Headers")
    if "PUT" in entity.methods or "POST" in entity.methods:
        dependencies.add("retrofit2.http.Body")
    for method in entity.methods:
        dependencies.add(f"retrofit2.http.{method}")
    if "GET" in entity.methods or "PUT" in entity.methods or "POST" in entity.methods or "DELETE" in entity.methods:
        dependencies.add(
            f"{package}.{_package(entity.package)}.logic.{entity.name}")
    for dependency in _get_dependencies(entity):
        dependencies.add(f"{package}.{_package(dependency.package)}.logic." +
                         dependency.name)

    for dependency in sorted(dependencies):
        writer.writeln(f"import {dependency}")

    writer.newline()
    writer.writeln(f"interface {entity.name}Service {{")
    writer.newline()

    indented_writer = writer.indented()

    for method in entity.methods:

        for key_id in entity.key_ids:
            parameter_list = []
            for key_property in entity.key_properties(key_id):
                variable_name = camelcase(key_property.name)
                variable_type = _kotlin_type(key_property.type)
                if key_property.nullable:
                    variable_type += '?'
                parameter_list.append(
                    f'@Query("{key_property.name}") {variable_name}: {variable_type}'
                )
            parameters = ', '.join(parameter_list)
            if entity.version != -1:
                indented_writer.writeln(
                    f'@Headers("X-Navajo-Version: {entity.version}")')
                indented_writer.writeln(
                    f'@{method}("{entity.path}?v={entity.version}")')
            else:
                indented_writer.writeln(f'@{method}("{entity.path}")')
            if method == "GET":
                indented_writer.writeln(
                    f'fun {entity.name[0].lower() + entity.name[1:]}({parameters}): Single<{entity.name}>'
                )
            if method == "PUT":
                indented_writer.writeln(
                    f'fun update{entity.name}({parameters}, @Body {entity.name[0].lower() + entity.name[1:]}: {entity.name}): Single<{entity.name}>'
                )
            if method == "DELETE":
                indented_writer.writeln(
                    f'fun remove{entity.name}({parameters}): Single<{entity.name}>'
                )
            if method == "POST":
                indented_writer.writeln(
                    f'fun insert{entity.name}({parameters}, @Body {entity.name[0].lower() + entity.name[1:]}: {entity.name}): Single<{entity.name}>'
                )
            indented_writer.newline()

        if not entity.key_ids:
            if entity.version != -1:
                indented_writer.writeln(
                    f'@Headers("X-Navajo-Version: {entity.version}")')
                indented_writer.writeln(
                    f'@{method}("{entity.path}?v={entity.version}")')
            else:
                indented_writer.writeln(f'@{method}("{entity.path}")')
            if method == "GET":
                indented_writer.writeln(
                    f'fun {entity.name[0].lower() + entity.name[1:]}(): Single<{entity.name}> '
                )
            if method == "PUT":
                indented_writer.writeln(
                    f'fun update{entity.name}(@Body {entity.name[0].lower() + entity.name[1:]}: {entity.name}): Single<{entity.name}>'
                )
            if method == "DELETE":
                indented_writer.writeln(
                    f'fun remove{entity.name}(): Single<{entity.name}>')
            if method == "POST":
                indented_writer.writeln(
                    f'fun insert{entity.name}(@Body {entity.name[0].lower() + entity.name[1:]}: {entity.name}): Single<{entity.name}>'
                )
            indented_writer.newline()
    indented_writer.writeln("companion object {")
    companion_writer = indented_writer.indented()
    companion_writer.writeln(
        "var typeFactoryAdapterList = listOf<TypeAdapterFactory>(")
    _write_service_typeadapterfactories(companion_writer, entity.root, "")
    companion_writer.writeln(")")
    indented_writer.writeln("}")

    writer.writeln("}")
    writer.newline()
Exemple #14
0
def _write_logic_class(writer: IndentedWriter,
                       message: Message,
                       shared_interface: SharedInterface = None) -> None:
    if shared_interface:
        writer.write(f"open class {shared_interface.name}{message.name}")
    else:
        writer.write(f"open class {message.name}")

    super_nonnull_variables = _get_variables(message, "", True)[0]
    super_nullable_variables = _get_variables(message, "", True)[1]
    shared_interface_super_nonnull_variables = []
    shared_interface_super_nullable_variables = []
    if shared_interface:
        for parent in shared_interface.parents:
            shared_interface_super_nonnull_variables += _get_variables(
                parent.root, "")[0]
            shared_interface_super_nullable_variables += _get_variables(
                parent.root, "")[1]

    indented_writer = writer.indented()

    writer.appendln("(")
    if (super_nonnull_variables or shared_interface_super_nonnull_variables
            or shared_interface_super_nullable_variables):
        for constructor_parameter in super_nonnull_variables:
            name = constructor_parameter.name
            type = constructor_parameter.type
            indented_writer.writeln(f'{name}: {type},')
        if shared_interface:
            for variable in shared_interface.variables:
                if variable not in super_nonnull_variables:
                    indented_writer.writeln(
                        f'{variable.name}: {variable.type},')
        if shared_interface_super_nonnull_variables:
            for variable in shared_interface_super_nonnull_variables:
                if variable not in super_nonnull_variables:
                    indented_writer.writeln(
                        f'{variable.name}: {variable.type},')
        # if shared_interface_super_nullable_variables:
        #     for variable in shared_interface_super_nullable_variables:
        #         if variable not in super_nullable_variables:
        #             indented_writer.writeln(f'{variable.name}: {variable.type},')

        if shared_interface:
            writer.writeln(f") : {shared_interface.name}{message.name}Entity(")
        else:
            writer.writeln(f") : {message.name}Entity(")
        for constructor_parameter in super_nonnull_variables:
            name = constructor_parameter.name
            if debug:
                indented_writer.writeln('/* super variable */ ')
            indented_writer.writeln(f'{name},')
        if shared_interface:
            for variable in shared_interface.variables:
                if variable not in super_nonnull_variables:
                    if debug:
                        indented_writer.writeln(
                            '/* shared interface variable */ ')
                    indented_writer.writeln(f'{variable.name},')
        if shared_interface_super_nonnull_variables:
            for variable in shared_interface_super_nonnull_variables:
                if variable not in super_nonnull_variables:
                    if debug:
                        indented_writer.writeln(
                            '/* shared interface super nonnull variable */ ')
                    indented_writer.writeln(f'{variable.name},')
        # if shared_interface_super_nullable_variables:
        #     for variable in shared_interface_super_nullable_variables:
        #         if variable not in super_nullable_variables:
        #             if debug:
        #                 indented_writer.writeln('/* shared interface super nullable variable */ ')
        #             indented_writer.writeln(f'{variable.name},')
        writer.write(f")")
    else:
        if shared_interface:
            writer.writeln(
                f") : {shared_interface.name}{message.name}Entity()")
        else:
            writer.writeln(f") : {message.name}Entity()")
    hasId = False
    if not shared_interface:
        for variable in super_nonnull_variables:
            if variable.network_name == "Id" and variable.type == "String" and not variable.nullable:
                hasId = True

    if hasId or message.messages:
        hasSubClass = False
        for submessage in message.messages:
            name = submessage.name

            if submessage.is_array:
                if len(submessage.extends
                       ) != 1 or submessage.properties or submessage.messages:
                    if not hasSubClass:
                        writer.appendln(" {")
                        hasSubClass = True
                    _write_logic_inner(indented_writer, submessage)
            else:
                if len(submessage.extends
                       ) != 1 or submessage.properties or submessage.messages:
                    if not hasSubClass:
                        writer.appendln(" {")
                        hasSubClass = True
                    _write_logic_inner(indented_writer, submessage)
        if hasId:
            if not hasSubClass:
                writer.appendln(" {")
                hasSubClass = True
            indented_writer.newline()
            indented_writer.writeln("companion object {")
            indented_writer.indented().write("fun create(")
            for constructor_parameter in super_nonnull_variables:
                name = constructor_parameter.name
                type = constructor_parameter.type
                if name != 'id':
                    indented_writer.append(f'{name}: {type}, ')
            indented_writer.append(") = " + message.name + "(INSERT_ID")
            for constructor_parameter in super_nonnull_variables:
                name = constructor_parameter.name
                type = constructor_parameter.type
                if name != 'id':
                    indented_writer.append(f', {name}')
            indented_writer.appendln(")")
            indented_writer.writeln("}")
        if hasSubClass:
            writer.writeln("}")
        else:
            writer.newline()
    else:
        writer.newline()

    if (shared_interface and
        (super_nonnull_variables or shared_interface_super_nonnull_variables
         or shared_interface_super_nullable_variables)):
        constructor_writer = indented_writer.indented()
        writer.writeln("{")

        indented_writer.writeln("constructor(")
        constructor_writer.writeln(
            f"{camelcase(message.name)}: {message.name},")
        for constructor_parameter in shared_interface_super_nonnull_variables:
            if constructor_parameter not in super_nonnull_variables:
                constructor_writer.writeln(
                    f'{constructor_parameter[1]}: {constructor_parameter[2]},'
                )  #last one without comma
        # for constructor_parameter in shared_interface_super_nullable_variables:
        #     if constructor_parameter not in super_nullable_variables:
        #         constructor_writer.writeln(f'{constructor_parameter[1]}: {constructor_parameter[2]},') #last one without comma
        for variable in shared_interface.variables:
            if variable not in super_nonnull_variables:
                constructor_writer.writeln(
                    f"{variable.name}: {variable.type},")
        indented_writer.writeln(") : this(")
        for constructor_parameter in super_nonnull_variables:
            name = constructor_parameter.name
            constructor_writer.writeln(
                f'{camelcase(message.name)}.{name},')  #last one without comma
        for constructor_parameter in shared_interface_super_nonnull_variables:
            if constructor_parameter not in super_nonnull_variables:
                name = constructor_parameter.name
                constructor_writer.writeln(f'{name},')  #last one without comma
        # for constructor_parameter in shared_interface_super_nullable_variables:
        #     name = constructor_parameter[1]
        #     if constructor_parameter not in super_nullable_variables:
        #         constructor_writer.writeln(f'{name},') #last one without comma
        for variable in shared_interface.variables:
            if variable not in super_nonnull_variables:
                constructor_writer.writeln(f'{variable.name},')
        indented_writer.writeln(") {")
        indented_writer.indented().writeln(
            f"copyNullableVariables({camelcase(message.name)})")
        indented_writer.writeln("}")
        writer.writeln("}")
Exemple #15
0
def _write_datamodel_class(writer: IndentedWriter,
                           message: Message,
                           import_list: Set,
                           prefix: str = '',
                           shared_interface: SharedInterface = None) -> Set:
    if shared_interface is None:
        writer.write(f"open class {message.name}Entity")
    else:
        writer.write(f"open class {shared_interface.name}{message.name}Entity")

    if not shared_interface:
        prefix += message.name + "."

    variables = _get_variables(message, prefix)
    nonnull_variables = variables[0]
    nullable_variables = variables[1]
    enums = variables[2]
    inner_classes = variables[3]
    super_variables = []
    super_interface_nonnull_variables = []
    super_interface_nullable_variables = []
    shared_interface_super_nonnull_variables = []
    shared_interface_super_nullable_variables = []

    constructor_vars = []
    member_vars = []

    if len(message.extends) == 1:
        super_variables = _get_variables(message.extends[0].root,
                                         message.extends[0].root.name + ".",
                                         True)[0]
    if shared_interface:
        for parent in shared_interface.parents:
            shared_interface_super_nonnull_variables += _get_variables(
                parent.root, prefix)[0]
            shared_interface_super_nullable_variables += _get_variables(
                parent.root, prefix)[1]

    indented_writer = writer.indented()

    if (super_variables or nonnull_variables
            or super_interface_nonnull_variables or shared_interface
            or shared_interface_super_nonnull_variables
            or shared_interface_super_nullable_variables):
        writer.appendln("(")

        if (super_variables):
            for variable in super_variables:
                if debug:
                    indented_writer.writeln('/* super variable */ ')
                indented_writer.writeln(f'{variable.name}: {variable.type},')
                constructor_vars.append(variable)

        if (super_interface_nonnull_variables):
            for variable in super_interface_nonnull_variables:
                if variable in shared_interface_super_nonnull_variables + nonnull_variables:
                    continue
                if shared_interface:
                    if debug:
                        indented_writer.writeln(
                            '/* super interface non null shared variable */ ')
                    indented_writer.writeln(
                        f'override var {variable.name}: {variable.type},')
                else:
                    import_list.add(
                        "com.google.gson.annotations.SerializedName")
                    if debug:
                        indented_writer.writeln(
                            '/* super interface non null variable */ ')
                    indented_writer.writeln(
                        f'@SerializedName("{variable.network_name}") override var {variable.name}: {variable.type},'
                    )
                constructor_vars.append(variable)

        if (nonnull_variables):
            for variable in nonnull_variables:
                import_list.add("com.google.gson.annotations.SerializedName")
                if shared_interface:
                    if variable in super_interface_nonnull_variables:
                        if debug:
                            indented_writer.writeln(
                                '/* non null shared override variable */ ')
                        indented_writer.writeln(
                            f'{variable.name}: {variable.type},')
                    else:
                        if debug:
                            indented_writer.writeln(
                                '/* non null shared variable */ ')
                        indented_writer.writeln(
                            f'{variable.name}: {variable.type},')
                else:
                    if variable in super_interface_nonnull_variables:
                        if debug:
                            indented_writer.writeln(
                                '/* non null override variable */ ')
                        indented_writer.writeln(
                            f'@SerializedName("{variable.network_name}") override var {variable.name}: {variable.type},'
                        )
                    else:
                        if debug:
                            indented_writer.writeln('/* non null variable */ ')
                        indented_writer.writeln(
                            f'@SerializedName("{variable.network_name}") open var {variable.name}: {variable.type},'
                        )

                constructor_vars.append(variable)

        if (shared_interface):
            for variable in shared_interface.variables:
                import_list.add("com.google.gson.annotations.SerializedName")
                if debug:
                    indented_writer.writeln('/* shared interface variable */ ')
                indented_writer.writeln(
                    f'@SerializedName("{variable.network_name}") override var {variable.name}: {variable.type},'
                )
                constructor_vars.append(variable)

        if (shared_interface_super_nonnull_variables):
            for variable in shared_interface_super_nonnull_variables:
                if variable in nonnull_variables:
                    continue
                if debug:
                    indented_writer.writeln(
                        '/* shared interface super nonnull variable */ ')
                indented_writer.writeln(
                    f'@SerializedName("{variable.network_name}") override var {variable.name}: {variable.type},'
                )
                constructor_vars.append(variable)

        writer.write(")")
    if shared_interface:
        writer.append(f" : {message.name}")
        if super_variables or super_interface_nonnull_variables or nonnull_variables:
            vars = []
            if super_variables:
                for variable in super_variables:
                    vars.append(f'{variable.name}')
            if (super_interface_nonnull_variables):
                for variable in super_interface_nonnull_variables:
                    if variable in nonnull_variables:
                        continue
                    vars.append(f'{variable.name} /* super interface */')
            if nonnull_variables:
                for variable in nonnull_variables:
                    vars.append(f'{variable.name}')
            writer.append(f'({", ".join(vars)})')

        if shared_interface.is_inner:
            writer.append(f", {prefix + shared_interface.name}")
        else:
            writer.append(f", {shared_interface.name}")
        # if shared_interface.variables:
        # writer.append("(")
        # for variable in shared_interface.variables:
        #     writer.append(f'{variable.name}, ')
        # writer.append(")")
        writer.append(", Serializable, Entity")
    elif not message.extends:
        writer.append(" : Serializable, Entity")
    else:
        writer.append(f" : {message.extends[0].name}")
        if super_variables:
            writer.appendln("(")
            for variable, has_more in lookahead(super_variables):
                indented_writer.write(f'{variable.name}')
                if has_more:
                    writer.appendln(',')
                else:
                    writer.appendln('')
            writer.write(")")
        writer.append(", Serializable, Entity")

    hasId = False
    if not shared_interface:
        for variable in nonnull_variables:
            if variable.network_name == "Id" and variable.type == "String" and not variable.nullable:
                hasId = True

    writer.appendln(" {")
    writer.newline()

    if (shared_interface_super_nullable_variables):
        for variable in shared_interface_super_nullable_variables:
            if variable in nullable_variables:
                continue
            else:
                if debug:
                    indented_writer.writeln(
                        '/* shared interface super nullable variable */ ')
                indented_writer.writeln(
                    f'@SerializedName("{variable.network_name}") override var {variable.name}: {variable.type} = null'
                )
                member_vars.append(variable)

    for inner_class in inner_classes:
        import_list.update(
            _write_datamodel_inner(indented_writer, inner_class[0],
                                   import_list, inner_class[1]))

    for enum in enums:
        indented_writer.writeln(f"enum class {enum[0]} {{")
        indented_writer.indented().writeln(f'{", ".join(enum[1])}')
        indented_writer.writeln(f"}}")
        writer.newline()

    if not shared_interface:
        for variable in nullable_variables:
            import_list.add("com.google.gson.annotations.SerializedName")
            indented_writer.writeln(
                f'@SerializedName("{variable.network_name}")')
            indented_writer.writeln(
                f"open var {variable.name}: {variable.type} = null")
            member_vars.append(variable)
            writer.newline()

        for variable in super_interface_nullable_variables:
            import_list.add("com.google.gson.annotations.SerializedName")
            indented_writer.writeln(
                f'@SerializedName("{variable.network_name}")')
            indented_writer.writeln(
                f"override var {variable.name}: {variable.type} = null")
            member_vars.append(variable)
            writer.newline()

    if hasId:
        indented_writer.writeln("override fun hashCode(): Int {")
        indented_writer.indented().writeln("return id.hashCode()")
        indented_writer.writeln("}")
        indented_writer.newline()
        indented_writer.writeln("override fun equals(other: Any?): Boolean {")
        indented_writer.indented().writeln(
            f"if (other is {message.name}Entity) {{")
        indented_writer.indented().indented().writeln(
            "return this === other || (id == other.id && id != INSERT_ID)")
        indented_writer.indented().writeln("}")
        indented_writer.indented().writeln("return super.equals(other)")
        indented_writer.writeln("}")
        indented_writer.newline()
        indented_writer.writeln("companion object {")
        indented_writer.indented().writeln('const val INSERT_ID = "insert"')
        indented_writer.writeln("}")
        indented_writer.newline()

    logic_type = f"{prefix}{shared_interface.name}{message.name}" if shared_interface else f"{prefix[:-1]}"
    indented_writer.writeln("@Transient")
    indented_writer.writeln(f"private lateinit var original: {logic_type}")
    indented_writer.newline()
    indented_writer.writeln("override fun saveOriginal() {")
    indented_writer.indented().writeln(f"original = copy()")
    indented_writer.writeln("}")
    indented_writer.newline()

    indented_writer.writeln(f"override fun copy(): {logic_type} {{")
    indented_writer.indented().write(f"val copy = {logic_type}(")
    for variable in constructor_vars:
        indented_writer.append(
            f"{variable.name}{'.map { it.copy() }.map { it as ' + variable.type[12:-1] + ' }.toMutableList()' if variable.name.endswith('List') else ''}{'' if variable.primitive or variable.name.endswith('List') else ('.copy() as ' + variable.type)}, "
        )
    indented_writer.appendln(")")
    indented_writer.indented().writeln(
        f"copy.copyNullableVariables(this as {logic_type})")
    indented_writer.indented().writeln(f"return copy")
    indented_writer.writeln("}")
    indented_writer.newline()
    indented_writer.writeln(
        f"fun copyNullableVariables(from: {logic_type}) {{")
    if message.extends or shared_interface:
        indented_writer.indented().writeln(
            f"super.copyNullableVariables(from)")
    for variable in member_vars:
        if variable.primitive:
            indented_writer.indented().writeln(
                f"{variable.name} = from.{variable.name}")
        else:
            if variable.name.endswith("List"):
                if variable.nullable:
                    indented_writer.indented().writeln(
                        f"{variable.name} = from.{variable.name}?.map {{ it.copy() }}?.map {{ it as {variable.type[12:-2]} }}?.toMutableList()"
                    )
                else:
                    indented_writer.indented().writeln(
                        f"{variable.name} = from.{variable.name}.map {{ it.copy() }}.map {{ it as {variable.type[12:-1]} }}.toMutableList()"
                    )
            else:
                indented_writer.indented().writeln(
                    f"{variable.name} = from.{variable.name}{'?' if variable.nullable else ''}.copy() as {variable.type}"
                )
    indented_writer.writeln("}")
    indented_writer.newline()

    indented_writer.writeln(
        f"override fun deepEquals(other: Any?): Boolean {{")

    if message.extends:
        indented_writer.indented().writeln(f"if (!super.deepEquals(other)) {{")
        indented_writer.indented().indented().writeln("return false")
        indented_writer.indented().writeln("}")
    indented_writer.indented().writeln(f"return other is {logic_type}")
    for variable in (constructor_vars + member_vars):
        if variable.primitive:
            indented_writer.indented().indented().writeln(
                f"&& {variable.name} == other.{variable.name}")
        else:
            if variable.name.endswith("List"):
                indented_writer.indented().indented().writeln(
                    f"&& {f'if ({variable.name} == null || other.{variable.name} == null) {variable.name} == other.{variable.name} else' if variable.nullable else ''} {variable.name}!!.size == other.{variable.name}!!.size && {variable.name}!!.zip(other.{variable.name}!!) {{ a, b -> a.deepEquals(b) }}.fold(true) {{ x, y -> x && y}}"
                )
            else:
                indented_writer.indented().indented().writeln(
                    f"&& {f'if ({variable.name} == null) other.{variable.name} == null else {variable.name}?' if variable.nullable else variable.name}.deepEquals(other.{variable.name}){' == true' if variable.nullable else ''}"
                )

    indented_writer.writeln("}")
    indented_writer.newline()
    if message.extends or shared_interface:
        indented_writer.write("override ")
    else:
        indented_writer.write("open ")
    indented_writer.appendln(f"fun hasChanged(): Boolean {{")
    indented_writer.indented().writeln(f"return !deepEquals(original)")
    indented_writer.writeln("}")

    indented_writer.newline()
    indented_writer.writeln(f"override fun toOriginal() : {logic_type} {{")
    indented_writer.indented().writeln(f"val result = original")
    indented_writer.indented().writeln(f"original.saveOriginal()")
    indented_writer.indented().writeln(f"return result")
    indented_writer.writeln("}")

    writer.writeln("}")

    return import_list
Exemple #16
0
def _write_logic_class(writer: IndentedWriter, message: Message) -> None:
    writer.write("public")
    if writer.indent > 0:
        writer.append(" static")

    writer.appendln(f" class {message.name} extends {message.name}Entity {{")
    writer.newline()

    indented_writer = writer.indented()

    constructor_parameters, super_import_list = _get_super_constructor_parameters(
        message)
    constructor_parameters_string = []
    super_arguments_string = []

    for constructor_parameter in constructor_parameters:
        name = constructor_parameter[0]
        type = constructor_parameter[1]

        constructor_parameters_string.append(f'@NonNull {type} {name}')
        super_arguments_string.append(f'{name}')

    indented_writer.writeln(
        f'public {message.name}({", ".join(constructor_parameters_string)}) {{'
    )
    indented_writer.indented().writeln(
        f'super({", ".join(super_arguments_string)});')
    indented_writer.writeln("}")

    for submessage in message.messages:
        name = submessage.name

        if submessage.is_array:
            if submessage.extends is None or submessage.properties or submessage.messages:
                _write_logic_class(indented_writer, submessage)
        else:
            if submessage.extends is None or submessage.is_non_empty:
                _write_logic_class(indented_writer, submessage)

    writer.writeln(f"}}")
Exemple #17
0
def _write_service(writer: IndentedWriter, entity: Entity,
                   package: str) -> None:
    writer.writeln(f"package {package}.{_package(entity.package)}.service;")

    writer.newline()

    dependencies: List[str] = []

    if entity.key_ids:
        dependencies.append("retrofit2.http.Query")

    import_non_null = False
    import_nullable = False

    for key_id in entity.key_ids:
        for key_property in entity.key_properties(key_id):
            if key_property.nullable:
                import_nullable = True
            else:
                import_non_null = True

    if "GET" in entity.methods or "PUT" in entity.methods or "POST" in entity.methods or "DELETE" in entity.methods:
        dependencies.append("io.reactivex.Single")
    if entity.version != -1:
        dependencies.append("retrofit2.http.Headers")
    if "PUT" in entity.methods or "POST" in entity.methods:
        import_non_null = True
        dependencies.append("retrofit2.http.Body")
    for method in entity.methods:
        dependencies.append(f"retrofit2.http.{method}")
    if "GET" in entity.methods or "PUT" in entity.methods or "POST" in entity.methods:
        dependencies.append(
            f"{package}.{_package(entity.package)}.logic.{entity.name}")
    if import_non_null:
        dependencies.append("androidx.annotation.NonNull")
    if import_nullable:
        dependencies.append("androidx.annotation.Nullable")

    previous_dependency = None
    for dependency in sorted(dependencies):
        if previous_dependency is not None and previous_dependency.split(
                ".")[0] != dependency.split(".")[0]:
            writer.newline()
        writer.writeln(f"import {dependency};")
        previous_dependency = dependency

    writer.newline()
    writer.writeln(f"public interface {entity.name}Service {{")
    writer.newline()

    for method in entity.methods:
        indented_writer = writer.indented()

        for key_id in entity.key_ids:
            parameter_list = []
            for key_property in entity.key_properties(key_id):
                variable_name = camelcase(key_property.name)
                variable_type = _java_type(key_property.type)
                nullable = '@NonNull'
                if key_property.nullable:
                    nullable = '@Nullable'
                parameter_list.append(
                    f'{nullable} @Query("{key_property.name}") {variable_type} {variable_name}'
                )
            parameters = ', '.join(parameter_list)
            if entity.version != -1:
                indented_writer.writeln(
                    f'@Headers("X-Navajo-Version: {entity.version}")')
                indented_writer.writeln(
                    f'@{method}("{entity.path}?v={entity.version}")')
            else:
                indented_writer.writeln(f'@{method}("{entity.path}")')
            if method == "GET":
                indented_writer.writeln(
                    f'Single<{entity.name}> get{entity.name}({parameters});')
            if method == "PUT":
                indented_writer.writeln(
                    f'Single<{entity.name}> update{entity.name}({parameters}, @NonNull @Body {entity.name} {entity.name[0].lower() + entity.name[1:]});'
                )
            if method == "DELETE":
                indented_writer.writeln(
                    f'Single<{entity.name}> remove{entity.name}({parameters});'
                )
            if method == "POST":
                indented_writer.writeln(
                    f'Single<{entity.name}> insert{entity.name}({parameters}, @NonNull @Body {entity.name} {entity.name[0].lower() + entity.name[1:]});'
                )
            indented_writer.newline()

        if not len(entity.key_ids):
            if entity.version != -1:
                indented_writer.writeln(
                    f'@Headers("X-Navajo-Version: {entity.version}")')
                indented_writer.writeln(
                    f'@{method}("{entity.path}?v={entity.version}")')
            else:
                indented_writer.writeln(f'@{method}("{entity.path}")')
            if method == "GET":
                indented_writer.writeln(
                    f'Single<{entity.name}> get{entity.name}();')
            if method == "PUT":
                indented_writer.writeln(
                    f'Single<{entity.name}> update{entity.name}(@NonNull @Body {entity.name} {entity.name[0].lower() + entity.name[1:]});'
                )
            if method == "DELETE":
                indented_writer.writeln(
                    f'Single<{entity.name}> remove{entity.name}();')
            if method == "POST":
                indented_writer.writeln(
                    f'Single<{entity.name}> insert{entity.name}(@NonNull @Body {entity.name} {entity.name[0].lower() + entity.name[1:]});'
                )
            indented_writer.newline()

    writer.writeln("}")
    writer.newline()
Exemple #18
0
def _write_entity(entity: Entity, output: pathlib.Path) -> None:
    datamodel = output / entity.package
    datamodel.mkdir(parents=True, exist_ok=True)
    datamodel_class = datamodel / f"{entity.name}.ts"
    with IndentedWriter(path=datamodel_class) as writer:
        _write_datamodel(writer, entity, output)