[
  {
    "path": ".commitlintrc.json",
    "content": "{\n  \"extends\": [\n    \"@commitlint/config-conventional\"\n  ]\n}\n"
  },
  {
    "path": ".github/CODEOWNERS",
    "content": "*       @neo4j/team-connectors\n\n/.github/   @ali-ince @fbiville @venikkin\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\nlabels: bug\n---\n\n## Guidelines\n\nPlease note that GitHub issues are only meant for bug reports/feature requests. If you have questions on how to use the Neo4j Connector for Apache Spark,\nplease ask on [the Neo4j Discussion Forum](https://community.neo4j.com/c/integrations/18) instead of creating an issue here.\n\n## Expected Behavior (Mandatory)\n\n\n## Actual Behavior (Mandatory)\n\n\n## How to Reproduce the Problem\n\n### Simple Dataset (where it's possible)\n\n```\n// Insert the output of the `df.show()` call\n\n```\n\n\n### Steps (Mandatory)\n\n1.\n1.\n1.\n\n## Screenshots (where it's possible)\n\n## Specifications (Mandatory)\n\nCurrently used versions\n\n### Versions\n\n- Spark:\n- Scala:\n- Neo4j:\n- Neo4j Connector:\n\n## Additional information\n\n* The code of the Spark job\n* the structure of the Dataframe\n* did you define the constraints/indexes?\n* if you're you using any Spark Cloud provider please specify it (ie: Databricks)\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\n\n---\n\n## Guidelines\n\nPlease note that GitHub issues are only meant for bug reports/feature requests. If you have questions on how to use the Neo4j Connector for Apache Spark,\nplease ask on [the Neo4j Discussion Forum](https://community.neo4j.com/c/integrations/18) instead of creating an issue here.\n\n## Feature description (Mandatory)\nA clear and concise description of what you want to happen. Add any considered drawbacks.\n\n## Considered alternatives\nA clear and concise description of any alternative solutions or features you've considered. Maybe there is something in the project that could be reused?\n\n## How this feature can improve the project?\nIf you can, explain how users will be able to use this and possibly write out a version the docs.\nMaybe a screenshot or design?"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "version: 2\nupdates:\n  - package-ecosystem: \"github-actions\"\n    directory: \"/\"\n    schedule:\n      interval: \"daily\"\n    cooldown:\n      default-days: 3\n\n  - package-ecosystem: \"maven\"\n    directory: \"/\"\n    target-branch: \"5.0\"\n    schedule:\n      interval: \"daily\"\n    cooldown:\n      default-days: 3\n\n  - package-ecosystem: \"maven\"\n    directory: \"/\"\n    target-branch: \"6.0\"\n    schedule:\n      interval: \"daily\"\n    cooldown:\n      default-days: 3\n"
  },
  {
    "path": ".gitignore",
    "content": "neo4j-home\n.gradle\ngradle/\nbuild/\n*~\n\\#*\ntarget\nout\n.project\n.classpath\n.settings\n.externalToolBuilders/\n.scala_dependencies\n.factorypath\n.cache\n.cache-main\n.cache-tests\n*.iws\n*.ipr\n*.iml\n.idea\n.DS_Store\n.shell_history\n.mailmap\n.java-version\n.cache-main\n.cache-tests\nThumbs.db\n.cache-main\n.cache-tests\ndocs/guides\ndoc/node\ndoc/node_modules\ndoc/package-lock.json\nscripts/python/local\nnode_modules\n"
  },
  {
    "path": ".husky/commit-msg",
    "content": "#!/usr/bin/env sh\n\nnpx --no -- commitlint --edit \"$1\"\n"
  },
  {
    "path": ".husky/pre-commit",
    "content": "#!/usr/bin/env sh\n\n./mvnw sortpom:sort spotless:apply -f .teamcity\n./mvnw sortpom:sort spotless:apply\ngit update-index --again\n\n"
  },
  {
    "path": ".mvn/wrapper/maven-wrapper.properties",
    "content": "# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing,\n# software distributed under the License is distributed on an\n# \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n# KIND, either express or implied.  See the License for the\n# specific language governing permissions and limitations\n# under the License.\nwrapperVersion=3.3.2\ndistributionType=only-script\ndistributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip\n"
  },
  {
    "path": ".teamcity/.editorconfig",
    "content": "# This .editorconfig section approximates ktfmt's formatting rules. You can include it in an\n# existing .editorconfig file or use it standalone by copying it to <project root>/.editorconfig\n# and making sure your editor is set to read settings from .editorconfig files.\n#\n# It includes editor-specific config options for IntelliJ IDEA.\n#\n# If any option is wrong, PR are welcome\n\n[*]\nmax_line_length = unset\n\n[pom.xml]\nmax_line_length = 180\n\n[{*.kt,*.kts}]\nindent_style = space\ninsert_final_newline = true\nmax_line_length = 100\nindent_size = 2\nij_continuation_indent_size = 4\nij_java_names_count_to_use_import_on_demand = 9999\nij_kotlin_align_in_columns_case_branch = false\nij_kotlin_align_multiline_binary_operation = false\nij_kotlin_align_multiline_extends_list = false\nij_kotlin_align_multiline_method_parentheses = false\nij_kotlin_align_multiline_parameters = true\nij_kotlin_align_multiline_parameters_in_calls = false\nij_kotlin_allow_trailing_comma = true\nij_kotlin_allow_trailing_comma_on_call_site = true\nij_kotlin_assignment_wrap = normal\nij_kotlin_blank_lines_after_class_header = 0\nij_kotlin_blank_lines_around_block_when_branches = 0\nij_kotlin_blank_lines_before_declaration_with_comment_or_annotation_on_separate_line = 1\nij_kotlin_block_comment_at_first_column = true\nij_kotlin_call_parameters_new_line_after_left_paren = true\nij_kotlin_call_parameters_right_paren_on_new_line = false\nij_kotlin_call_parameters_wrap = on_every_item\nij_kotlin_catch_on_new_line = false\nij_kotlin_class_annotation_wrap = split_into_lines\nij_kotlin_code_style_defaults = KOTLIN_OFFICIAL\nij_kotlin_continuation_indent_for_chained_calls = true\nij_kotlin_continuation_indent_for_expression_bodies = true\nij_kotlin_continuation_indent_in_argument_lists = true\nij_kotlin_continuation_indent_in_elvis = false\nij_kotlin_continuation_indent_in_if_conditions = false\nij_kotlin_continuation_indent_in_parameter_lists = false\nij_kotlin_continuation_indent_in_supertype_lists = false\nij_kotlin_else_on_new_line = false\nij_kotlin_enum_constants_wrap = off\nij_kotlin_extends_list_wrap = normal\nij_kotlin_field_annotation_wrap = split_into_lines\nij_kotlin_finally_on_new_line = false\nij_kotlin_if_rparen_on_new_line = false\nij_kotlin_import_nested_classes = false\nij_kotlin_insert_whitespaces_in_simple_one_line_method = true\nij_kotlin_keep_blank_lines_before_right_brace = 2\nij_kotlin_keep_blank_lines_in_code = 2\nij_kotlin_keep_blank_lines_in_declarations = 2\nij_kotlin_keep_first_column_comment = true\nij_kotlin_keep_indents_on_empty_lines = false\nij_kotlin_keep_line_breaks = true\nij_kotlin_lbrace_on_next_line = false\nij_kotlin_line_comment_add_space = false\nij_kotlin_line_comment_at_first_column = true\nij_kotlin_method_annotation_wrap = split_into_lines\nij_kotlin_method_call_chain_wrap = normal\nij_kotlin_method_parameters_new_line_after_left_paren = true\nij_kotlin_method_parameters_right_paren_on_new_line = true\nij_kotlin_method_parameters_wrap = on_every_item\nij_kotlin_name_count_to_use_star_import = 9999\nij_kotlin_name_count_to_use_star_import_for_members = 9999\nij_kotlin_parameter_annotation_wrap = off\nij_kotlin_space_after_comma = true\nij_kotlin_space_after_extend_colon = true\nij_kotlin_space_after_type_colon = true\nij_kotlin_space_before_catch_parentheses = true\nij_kotlin_space_before_comma = false\nij_kotlin_space_before_extend_colon = true\nij_kotlin_space_before_for_parentheses = true\nij_kotlin_space_before_if_parentheses = true\nij_kotlin_space_before_lambda_arrow = true\nij_kotlin_space_before_type_colon = false\nij_kotlin_space_before_when_parentheses = true\nij_kotlin_space_before_while_parentheses = true\nij_kotlin_spaces_around_additive_operators = true\nij_kotlin_spaces_around_assignment_operators = true\nij_kotlin_spaces_around_equality_operators = true\nij_kotlin_spaces_around_function_type_arrow = true\nij_kotlin_spaces_around_logical_operators = true\nij_kotlin_spaces_around_multiplicative_operators = true\nij_kotlin_spaces_around_range = false\nij_kotlin_spaces_around_relational_operators = true\nij_kotlin_spaces_around_unary_operator = false\nij_kotlin_spaces_around_when_arrow = true\nij_kotlin_variable_annotation_wrap = off\nij_kotlin_while_on_new_line = false\nij_kotlin_wrap_elvis_expressions = 1\nij_kotlin_wrap_expression_body_functions = 1\nij_kotlin_wrap_first_method_in_call_chain = false"
  },
  {
    "path": ".teamcity/builds/Build.kt",
    "content": "package builds\n\nimport jetbrains.buildServer.configs.kotlin.BuildType\nimport jetbrains.buildServer.configs.kotlin.Project\nimport jetbrains.buildServer.configs.kotlin.buildFeatures.notifications\nimport jetbrains.buildServer.configs.kotlin.sequential\nimport jetbrains.buildServer.configs.kotlin.toId\n\nclass Build(\n    name: String,\n    forPullRequests: Boolean,\n    javaVersions: Set<JavaVersion>,\n    scalaVersions: Set<ScalaVersion>,\n    pysparkVersions: Set<PySparkVersion>,\n    neo4jVersions: Set<Neo4jVersion>,\n    forCompatibility: Boolean = false,\n    customizeCompletion: BuildType.() -> Unit = {}\n) :\n    Project(\n        {\n          this.id(name.toId())\n          this.name = name\n\n          val complete = Empty(\"${name}-complete\", \"complete\")\n\n          val bts = sequential {\n            if (forPullRequests)\n                buildType(WhiteListCheck(\"${name}-whitelist-check\", \"white-list check\"))\n            if (forPullRequests) dependentBuildType(PRCheck(\"${name}-pr-check\", \"pr check\"))\n\n            parallel {\n              scalaVersions.forEach { scala ->\n                dependentBuildType(\n                    SemgrepCheck(\n                        \"${name}-semgrep-check-${scala.version}\",\n                        \"semgrep check (${scala.version})\",\n                        scala))\n              }\n\n              javaVersions.cartesianProduct(scalaVersions, neo4jVersions).forEach {\n                  (java, scala, neo4j) ->\n                sequential {\n                  val packaging =\n                      Package(\n                          \"${name}-package-${java.version}-${scala.version}-${neo4j.version}\",\n                          \"package (${java.version}, ${scala.version}, ${neo4j.version})\",\n                          java,\n                          scala,\n                      )\n\n                  dependentBuildType(\n                      Maven(\n                          \"${name}-build-${java.version}-${scala.version}-${neo4j.version}\",\n                          \"build (${java.version}, ${scala.version}, ${neo4j.version})\",\n                          \"test-compile\",\n                          java,\n                          scala,\n                      ),\n                  )\n\n                  dependentBuildType(\n                      Maven(\n                          \"${name}-unit-tests-${java.version}-${scala.version}-${neo4j.version}\",\n                          \"unit tests (${java.version}, ${scala.version}, ${neo4j.version})\",\n                          \"test\",\n                          java,\n                          scala,\n                          neo4j,\n                      ),\n                  )\n\n                  dependentBuildType(\n                      collectArtifacts(\n                          packaging,\n                      ),\n                  )\n\n                  parallel {\n                    dependentBuildType(\n                        JavaIntegrationTests(\n                            \"${name}-integration-tests-java-${java.version}-${scala.version}-${neo4j.version}\",\n                            \"java integration tests (${java.version}, ${scala.version}, ${neo4j.version})\",\n                            java,\n                            scala,\n                            neo4j,\n                        ) {},\n                    )\n\n                    pysparkVersions\n                        .filter { it.shouldTestWith(java, scala) }\n                        .forEach { pyspark ->\n                          pyspark.pythonVersions.forEach { python ->\n                            dependentBuildType(\n                                PythonIntegrationTests(\n                                    \"${name}-integration-tests-pyspark-${java.version}-${scala.version}-${neo4j.version}-${python.version}-${pyspark.sparkVersion.version}\",\n                                    \"pyspark integration tests (${java.version}, ${scala.version}, ${neo4j.version}, ${python.version}, ${pyspark.sparkVersion.version})\",\n                                    java,\n                                    python,\n                                    scala,\n                                    pyspark.sparkVersion,\n                                    neo4j,\n                                ) {\n                                  dependencies {\n                                    artifacts(packaging) {\n                                      artifactRules =\n                                          \"\"\"\n                                    +:packages/*.jar => ./scripts/python\n                                    \"\"\"\n                                              .trimIndent()\n                                    }\n                                  }\n                                },\n                            )\n                          }\n                        }\n                  }\n                }\n              }\n            }\n\n            dependentBuildType(complete)\n            if (!forPullRequests && !forCompatibility)\n                dependentBuildType(Release(\"${name}-release\", \"release\", DEFAULT_JAVA_VERSION))\n          }\n\n          bts.buildTypes().forEach {\n            it.thisVcs(if (forPullRequests) \"pull/*\" else DEFAULT_BRANCH)\n\n            it.features {\n              loginToECR()\n              requireDiskSpace(\"5gb\")\n              if (!forCompatibility) enableCommitStatusPublisher()\n              if (forPullRequests) enablePullRequests()\n            }\n\n            buildType(it)\n          }\n\n          complete.features {\n            notifications {\n              branchFilter = buildString {\n                appendLine(\"+:$DEFAULT_BRANCH\")\n                appendLine(\"+:refs/heads/$DEFAULT_BRANCH\")\n                if (forPullRequests) {\n                  appendLine(\"+:pull/*\")\n                  appendLine(\"+:refs/heads/pull/*\")\n                }\n              }\n\n              queuedBuildRequiresApproval = forPullRequests\n              buildFailedToStart = !forPullRequests\n              buildFailed = !forPullRequests\n              buildFinishedSuccessfully = !forPullRequests\n              buildProbablyHanging = !forPullRequests\n\n              notifierSettings = slackNotifier {\n                connection = SLACK_CONNECTION_ID\n                sendTo = SLACK_CHANNEL\n                messageFormat = simpleMessageFormat()\n              }\n            }\n          }\n\n          complete.apply(customizeCompletion)\n        },\n    )\n"
  },
  {
    "path": ".teamcity/builds/Common.kt",
    "content": "package builds\n\nimport builds.Neo4jSparkConnectorVcs.branchSpec\nimport jetbrains.buildServer.configs.kotlin.BuildFeatures\nimport jetbrains.buildServer.configs.kotlin.BuildSteps\nimport jetbrains.buildServer.configs.kotlin.BuildType\nimport jetbrains.buildServer.configs.kotlin.CompoundStage\nimport jetbrains.buildServer.configs.kotlin.FailureAction\nimport jetbrains.buildServer.configs.kotlin.Requirements\nimport jetbrains.buildServer.configs.kotlin.ReuseBuilds\nimport jetbrains.buildServer.configs.kotlin.buildFeatures.PullRequests\nimport jetbrains.buildServer.configs.kotlin.buildFeatures.buildCache\nimport jetbrains.buildServer.configs.kotlin.buildFeatures.commitStatusPublisher\nimport jetbrains.buildServer.configs.kotlin.buildFeatures.dockerRegistryConnections\nimport jetbrains.buildServer.configs.kotlin.buildFeatures.freeDiskSpace\nimport jetbrains.buildServer.configs.kotlin.buildFeatures.pullRequests\nimport jetbrains.buildServer.configs.kotlin.buildSteps.DockerCommandStep\nimport jetbrains.buildServer.configs.kotlin.buildSteps.MavenBuildStep\nimport jetbrains.buildServer.configs.kotlin.buildSteps.ScriptBuildStep\nimport jetbrains.buildServer.configs.kotlin.buildSteps.dockerCommand\nimport jetbrains.buildServer.configs.kotlin.buildSteps.maven\nimport jetbrains.buildServer.configs.kotlin.buildSteps.script\nimport jetbrains.buildServer.configs.kotlin.vcs.GitVcsRoot\n\nconst val GITHUB_OWNER = \"neo4j\"\nconst val GITHUB_REPOSITORY = \"neo4j-spark-connector\"\nconst val DEFAULT_BRANCH = \"5.0\"\nval MAVEN_DEFAULT_ARGS = buildString {\n  append(\"--no-transfer-progress \")\n  append(\"--batch-mode \")\n  append(\"-Dmaven.repo.local=%teamcity.build.checkoutDir%/.m2/repository \")\n  append(\"-Dmaven.wagon.http.retryHandler.class=standard \")\n  append(\"-Dmaven.wagon.http.retryHandler.timeout=60 \")\n  append(\"-Dmaven.wagon.http.retryHandler.count=3 \")\n  append(\n      \"-Dmaven.wagon.http.retryHandler.nonRetryableClasses=java.io.InterruptedIOException,java.net.UnknownHostException,java.net.ConnectException \")\n}\nconst val SEMGREP_DOCKER_IMAGE = \"semgrep/semgrep:1.146.0\"\nconst val FULL_GITHUB_REPOSITORY = \"$GITHUB_OWNER/$GITHUB_REPOSITORY\"\nconst val GITHUB_URL = \"https://github.com/$FULL_GITHUB_REPOSITORY\"\n\nval DEFAULT_JAVA_VERSION = JavaVersion.V_11\n\n// Look into Root Project's settings -> Connections\nconst val SLACK_CONNECTION_ID = \"PROJECT_EXT_83\"\nconst val SLACK_CHANNEL = \"#team-connectors-feed\"\n\n// Look into Root Project's settings -> Connections\nconst val ECR_CONNECTION_ID = \"PROJECT_EXT_124\"\n\nenum class LinuxSize(val value: String) {\n  SMALL(\"small\"),\n  LARGE(\"large\")\n}\n\nenum class JavaVersion(val version: String, val dockerImage: String) {\n  V_8(version = \"8\", dockerImage = \"eclipse-temurin:8-jdk\"),\n  V_11(version = \"11\", dockerImage = \"eclipse-temurin:11-jdk\"),\n  V_17(version = \"17\", dockerImage = \"eclipse-temurin:17-jdk\"),\n  V_21(version = \"21\", dockerImage = \"eclipse-temurin:21-jdk\"),\n}\n\nenum class ScalaVersion(val version: String) {\n  V2_12(version = \"2.12\"),\n  V2_13(version = \"2.13\"),\n}\n\nenum class PythonVersion(val version: String) {\n  V3_9(version = \"3.9\"),\n  V3_10(version = \"3.10\"),\n  V3_11(version = \"3.11\"),\n  V3_12(version = \"3.12\"),\n  V3_13(version = \"3.13\"),\n}\n\nenum class SparkVersion(val short: String, val version: String) {\n  V3_4_4(short = \"3\", version = \"3.4.4\"),\n  V3_5_5(short = \"3\", version = \"3.5.5\"),\n}\n\nenum class PySparkVersion(\n    val sparkVersion: SparkVersion,\n    val scalaVersion: ScalaVersion,\n    val javaVersions: Set<JavaVersion>,\n    val pythonVersions: Set<PythonVersion>,\n) {\n  V3_4(\n      SparkVersion.V3_4_4,\n      ScalaVersion.V2_12,\n      setOf(\n          JavaVersion.V_8,\n          JavaVersion.V_11,\n          JavaVersion.V_17,\n      ),\n      setOf(\n          PythonVersion.V3_9,\n          PythonVersion.V3_10,\n          PythonVersion.V3_11,\n          PythonVersion.V3_12,\n      ),\n  ),\n  V3_5(\n      SparkVersion.V3_5_5,\n      ScalaVersion.V2_12,\n      setOf(\n          JavaVersion.V_8,\n          JavaVersion.V_11,\n          JavaVersion.V_17,\n          JavaVersion.V_21,\n      ),\n      setOf(\n          PythonVersion.V3_9,\n          PythonVersion.V3_10,\n          PythonVersion.V3_11,\n          PythonVersion.V3_12,\n          PythonVersion.V3_13,\n      ),\n  ),\n}\n\nfun PySparkVersion.shouldTestWith(javaVersion: JavaVersion, scalaVersion: ScalaVersion): Boolean =\n    this.javaVersions.contains(javaVersion) && this.scalaVersion == scalaVersion\n\nenum class Neo4jVersion(val version: String, val dockerImage: String) {\n  V_NONE(\"\", \"\"),\n  V_4_4(\"4.4\", \"neo4j:4.4-enterprise\"),\n  V_4_4_DEV(\n      \"4.4-dev\",\n      \"535893049302.dkr.ecr.eu-west-1.amazonaws.com/build-service/neo4j:4.4-enterprise-debian-nightly\",\n  ),\n  V_5(\"5\", \"neo4j:5-enterprise\"),\n  V_5_DEV(\n      \"5-dev\",\n      \"535893049302.dkr.ecr.eu-west-1.amazonaws.com/build-service/neo4j:5-enterprise-debian-nightly-bundle\",\n  ),\n  V_CALVER(\"2026\", \"neo4j:2026-enterprise\"),\n  V_CALVER_DEV(\n      \"2026-dev\",\n      \"535893049302.dkr.ecr.eu-west-1.amazonaws.com/build-service/neo4j:2026-enterprise-debian-nightly-bundle\",\n  ),\n}\n\nfun <S, T, Y> Iterable<S>.cartesianProduct(\n    other1: Collection<T>,\n    other2: Collection<Y>\n): Iterable<Triple<S, T, Y>> =\n    this.flatMap { s -> other1.map { t -> s to t } }\n        .flatMap { (s, t) -> other2.map { y -> Triple(s, t, y) } }\n\nobject Neo4jSparkConnectorVcs :\n    GitVcsRoot(\n        {\n          id(\"Connectors_Neo4jSparkConnector_Build\")\n\n          name = \"neo4j-spark-connector\"\n          url = \"git@github.com:neo4j/neo4j-spark-connector.git\"\n          branch = \"refs/heads/$DEFAULT_BRANCH\"\n          branchSpec = \"refs/heads/*\"\n\n          authMethod = defaultPrivateKey { userName = \"git\" }\n        },\n    )\n\nfun Requirements.runOnLinux(size: LinuxSize = LinuxSize.SMALL) {\n  startsWith(\"cloud.amazon.agent-name-prefix\", \"linux-${size.value}\")\n}\n\nfun BuildType.thisVcs(forBranch: String) = vcs {\n  root(Neo4jSparkConnectorVcs)\n\n  branchSpec = buildString {\n    appendLine(\"-:*\")\n    appendLine(\"+:$forBranch\")\n  }\n\n  cleanCheckout = true\n}\n\nfun BuildFeatures.enableCommitStatusPublisher() = commitStatusPublisher {\n  vcsRootExtId = Neo4jSparkConnectorVcs.id.toString()\n  publisher = github {\n    githubUrl = \"https://api.github.com\"\n    authType = personalToken { token = \"%github-commit-status-token%\" }\n  }\n}\n\nfun BuildFeatures.enablePullRequests() = pullRequests {\n  vcsRootExtId = Neo4jSparkConnectorVcs.id.toString()\n  provider = github {\n    authType = token { token = \"%github-pull-request-token%\" }\n    filterAuthorRole = PullRequests.GitHubRoleFilter.EVERYBODY\n    filterTargetBranch = buildString {\n      appendLine(\"+:$DEFAULT_BRANCH\")\n      appendLine(\"+:refs/heads/$DEFAULT_BRANCH\")\n    }\n  }\n}\n\nfun BuildFeatures.requireDiskSpace(size: String = \"3gb\") = freeDiskSpace {\n  requiredSpace = size\n  failBuild = true\n}\n\nfun BuildFeatures.loginToECR() = dockerRegistryConnections {\n  cleanupPushedImages = true\n  loginToRegistry = on { dockerRegistryId = ECR_CONNECTION_ID }\n}\n\nfun BuildFeatures.buildCache(javaVersion: JavaVersion, scalaVersion: ScalaVersion) = buildCache {\n  this.name =\n      \"neo4j-spark-connector-${DEFAULT_BRANCH}-${javaVersion.version}-${scalaVersion.version}\"\n  publish = true\n  use = true\n  publishOnlyChanged = true\n  rules = \".m2/repository\"\n}\n\nfun CompoundStage.dependentBuildType(bt: BuildType, reuse: ReuseBuilds = ReuseBuilds.SUCCESSFUL) =\n    buildType(bt) {\n      onDependencyCancel = FailureAction.CANCEL\n      onDependencyFailure = FailureAction.FAIL_TO_START\n      reuseBuilds = reuse\n    }\n\nfun collectArtifacts(buildType: BuildType): BuildType {\n  buildType.artifactRules =\n      \"\"\"\n        +:spark-3/target/*_for_spark_*.jar => packages\n        +:spark-3/target/*.zip => packages\n    \"\"\"\n          .trimIndent()\n\n  return buildType\n}\n\nfun BuildSteps.runMaven(javaVersion: JavaVersion, init: MavenBuildStep.() -> Unit): MavenBuildStep {\n  val maven =\n      this.maven {\n        dockerImagePlatform = MavenBuildStep.ImagePlatform.Linux\n        dockerImage = javaVersion.dockerImage\n        dockerRunParameters = \"--volume /var/run/docker.sock:/var/run/docker.sock\"\n\n        localRepoScope = MavenBuildStep.RepositoryScope.MAVEN_DEFAULT\n      }\n\n  init(maven)\n  return maven\n}\n\nfun BuildSteps.setVersion(name: String, version: String, javaVersion: JavaVersion): MavenBuildStep {\n  return this.runMaven(javaVersion) {\n    this.name = name\n    goals = \"versions:set\"\n    runnerArgs =\n        \"$MAVEN_DEFAULT_ARGS -Djava.version=${javaVersion.version} -DnewVersion=$version -DgenerateBackupPoms=false\"\n  }\n}\n\nfun BuildSteps.commitAndPush(\n    name: String,\n    commitMessage: String,\n    includeFiles: String = \"\\\\*pom.xml\",\n    dryRunParameter: String = \"dry-run\"\n): ScriptBuildStep {\n  return this.script {\n    this.name = name\n    scriptContent =\n        \"\"\"\n          #!/bin/bash -eu              \n         \n          git add $includeFiles\n          git commit -m \"$commitMessage\"\n          git push\n        \"\"\"\n            .trimIndent()\n\n    conditions { doesNotMatch(dryRunParameter, \"true\") }\n  }\n}\n\nfun BuildSteps.pullImage(version: Neo4jVersion): DockerCommandStep =\n    this.dockerCommand {\n      name = \"pull neo4j test image\"\n      commandType = other {\n        subCommand = \"image\"\n        commandArgs = \"pull ${version.dockerImage}\"\n      }\n    }\n"
  },
  {
    "path": ".teamcity/builds/Empty.kt",
    "content": "package builds\n\nimport jetbrains.buildServer.configs.kotlin.BuildType\nimport jetbrains.buildServer.configs.kotlin.toId\n\nclass Empty(id: String, name: String) :\n    BuildType({\n      this.id(id.toId())\n      this.name = name\n\n      requirements { runOnLinux(LinuxSize.SMALL) }\n    })\n"
  },
  {
    "path": ".teamcity/builds/JavaIntegrationTests.kt",
    "content": "package builds\n\nimport jetbrains.buildServer.configs.kotlin.BuildType\nimport jetbrains.buildServer.configs.kotlin.toId\n\nclass JavaIntegrationTests(\n    id: String,\n    name: String,\n    javaVersion: JavaVersion,\n    scalaVersion: ScalaVersion,\n    neo4jVersion: Neo4jVersion,\n    init: BuildType.() -> Unit\n) :\n    BuildType(\n        {\n          this.id(id.toId())\n          this.name = name\n\n          init()\n\n          artifactRules =\n              \"\"\"\n              +:diagnostics => diagnostics.zip\n              \"\"\"\n                  .trimIndent()\n\n          params { text(\"env.NEO4J_TEST_IMAGE\", neo4jVersion.dockerImage) }\n\n          steps {\n            if (neo4jVersion != Neo4jVersion.V_NONE) {\n              pullImage(neo4jVersion)\n            }\n\n            runMaven(javaVersion) {\n              this.goals = \"verify\"\n              this.runnerArgs =\n                  \"$MAVEN_DEFAULT_ARGS -Djava.version=${javaVersion.version} -Dscala-${scalaVersion.version} -DskipUnitTests\"\n            }\n          }\n\n          features { buildCache(javaVersion, scalaVersion) }\n\n          requirements { runOnLinux(LinuxSize.LARGE) }\n        },\n    )\n"
  },
  {
    "path": ".teamcity/builds/Maven.kt",
    "content": "package builds\n\nimport jetbrains.buildServer.configs.kotlin.BuildType\nimport jetbrains.buildServer.configs.kotlin.toId\n\nopen class Maven(\n    id: String,\n    name: String,\n    goals: String,\n    javaVersion: JavaVersion,\n    scalaVersion: ScalaVersion,\n    neo4jVersion: Neo4jVersion = Neo4jVersion.V_NONE,\n    args: String? = null\n) :\n    BuildType(\n        {\n          this.id(id.toId())\n          this.name = name\n\n          params {\n            text(\"env.JAVA_VERSION\", javaVersion.version)\n            text(\"env.NEO4J_TEST_IMAGE\", neo4jVersion.dockerImage)\n          }\n\n          steps {\n            if (neo4jVersion != Neo4jVersion.V_NONE) {\n              pullImage(neo4jVersion)\n            }\n\n            runMaven(javaVersion) {\n              this.goals = goals\n              this.runnerArgs =\n                  \"$MAVEN_DEFAULT_ARGS -Djava.version=${javaVersion.version} -Dscala-${scalaVersion.version} ${args ?: \"\"}\"\n            }\n          }\n\n          features { buildCache(javaVersion, scalaVersion) }\n\n          requirements { runOnLinux(LinuxSize.SMALL) }\n        },\n    )\n"
  },
  {
    "path": ".teamcity/builds/PRCheck.kt",
    "content": "package builds\n\nimport jetbrains.buildServer.configs.kotlin.BuildType\nimport jetbrains.buildServer.configs.kotlin.buildFeatures.dockerSupport\nimport jetbrains.buildServer.configs.kotlin.buildSteps.ScriptBuildStep\nimport jetbrains.buildServer.configs.kotlin.buildSteps.script\nimport jetbrains.buildServer.configs.kotlin.toId\n\nclass PRCheck(id: String, name: String) :\n    BuildType({\n      this.id(id.toId())\n      this.name = name\n\n      steps {\n        script {\n          scriptContent =\n              \"\"\"\n                #!/bin/bash\n                \n                set -eu\n                \n                export DANGER_GITHUB_API_TOKEN=%github-pull-request-token%\n                export PULL_REQUEST_URL=https://github.com/$GITHUB_OWNER/$GITHUB_REPOSITORY/%teamcity.build.branch%\n                \n                # process pull request\n                npm ci\n                npx danger ci --verbose --failOnErrors\n            \"\"\"\n                  .trimIndent()\n\n          dockerImage = \"node:18.4\"\n          dockerImagePlatform = ScriptBuildStep.ImagePlatform.Linux\n        }\n      }\n\n      features { dockerSupport {} }\n\n      requirements { runOnLinux(LinuxSize.SMALL) }\n    })\n"
  },
  {
    "path": ".teamcity/builds/Package.kt",
    "content": "package builds\n\nimport jetbrains.buildServer.configs.kotlin.BuildType\nimport jetbrains.buildServer.configs.kotlin.buildSteps.ScriptBuildStep\nimport jetbrains.buildServer.configs.kotlin.buildSteps.script\nimport jetbrains.buildServer.configs.kotlin.toId\n\nclass Package(\n    id: String,\n    name: String,\n    javaVersion: JavaVersion,\n    scalaVersion: ScalaVersion,\n) :\n    BuildType({\n      this.id(id.toId())\n      this.name = name\n\n      params { text(\"env.JAVA_VERSION\", javaVersion.version) }\n\n      steps {\n        script {\n          scriptContent =\n              \"\"\"\n                  ./maven-release.sh package ${scalaVersion.version}\n              \"\"\"\n                  .trimIndent()\n\n          dockerImagePlatform = ScriptBuildStep.ImagePlatform.Linux\n          dockerImage = javaVersion.dockerImage\n          dockerRunParameters = \"--volume /var/run/docker.sock:/var/run/docker.sock\"\n        }\n      }\n\n      features { buildCache(javaVersion, scalaVersion) }\n\n      requirements { runOnLinux(LinuxSize.SMALL) }\n    })\n"
  },
  {
    "path": ".teamcity/builds/PythonIntegrationTests.kt",
    "content": "package builds\n\nimport jetbrains.buildServer.configs.kotlin.BuildType\nimport jetbrains.buildServer.configs.kotlin.buildSteps.ScriptBuildStep\nimport jetbrains.buildServer.configs.kotlin.buildSteps.script\nimport jetbrains.buildServer.configs.kotlin.toId\n\nclass PythonIntegrationTests(\n    id: String,\n    name: String,\n    javaVersion: JavaVersion,\n    pythonVersion: PythonVersion,\n    scalaVersion: ScalaVersion,\n    sparkVersion: SparkVersion,\n    neo4jVersion: Neo4jVersion,\n    init: BuildType.() -> Unit\n) :\n    BuildType(\n        {\n          this.id(id.toId())\n          this.name = name\n\n          init()\n\n          artifactRules =\n              \"\"\"\n              +:diagnostics => diagnostics.zip\n              \"\"\"\n                  .trimIndent()\n\n          params { text(\"env.NEO4J_TEST_IMAGE\", neo4jVersion.dockerImage) }\n\n          steps {\n            if (neo4jVersion != Neo4jVersion.V_NONE) {\n              pullImage(neo4jVersion)\n            }\n\n            script {\n              scriptContent =\n                  \"\"\"\n              #!/bin/bash -eu\n              \n              apt-get update\n              apt-get install -o Acquire::Retries=10 --yes build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev curl git libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev\n              curl -fsSL https://pyenv.run | bash\n              \n              export PYENV_ROOT=\"${'$'}HOME/.pyenv\"\n              export PATH=\"${'$'}PYENV_ROOT/bin:${'$'}PATH\"\n              eval \"$(pyenv init - bash)\"\n              pyenv install ${pythonVersion.version}\n              pyenv global ${pythonVersion.version}\n                 \n              python -m pip install --upgrade pip\n              pip install pyspark==${sparkVersion.version} \"testcontainers[neo4j]\" six tzlocal==2.1 \n              \n              project_version=\"$(./mvnw help:evaluate -Dexpression=\"project.version\" --quiet -DforceStdout)\"\n              jar_name=\"neo4j-connector-apache-spark_${scalaVersion.version}-${'$'}{project_version}_for_spark_${sparkVersion.short}.jar\"\n              cd ./scripts/python\n              python test_spark.py \"${'$'}{jar_name}\" \"${neo4jVersion.dockerImage}\"\n              \"\"\"\n                      .trimIndent()\n\n              dockerImagePlatform = ScriptBuildStep.ImagePlatform.Linux\n              dockerImage = javaVersion.dockerImage\n              dockerRunParameters = \"--volume /var/run/docker.sock:/var/run/docker.sock\"\n            }\n          }\n\n          requirements { runOnLinux(LinuxSize.SMALL) }\n        },\n    )\n"
  },
  {
    "path": ".teamcity/builds/Release.kt",
    "content": "package builds\n\nimport jetbrains.buildServer.configs.kotlin.AbsoluteId\nimport jetbrains.buildServer.configs.kotlin.BuildType\nimport jetbrains.buildServer.configs.kotlin.ParameterDisplay\nimport jetbrains.buildServer.configs.kotlin.buildSteps.ScriptBuildStep\nimport jetbrains.buildServer.configs.kotlin.buildSteps.script\nimport jetbrains.buildServer.configs.kotlin.toId\n\nprivate const val DRY_RUN = \"dry-run\"\n\nclass Release(id: String, name: String, javaVersion: JavaVersion) :\n    BuildType(\n        {\n          this.id(id.toId())\n          this.name = name\n\n          templates(AbsoluteId(\"FetchSigningKey\"))\n\n          params {\n            text(\n                \"releaseVersion\",\n                \"\",\n                label = \"Version to release\",\n                display = ParameterDisplay.PROMPT,\n                allowEmpty = false,\n            )\n            text(\n                \"nextSnapshotVersion\",\n                \"\",\n                label = \"Next snapshot version\",\n                description = \"Next snapshot version to set after release\",\n                display = ParameterDisplay.PROMPT,\n                allowEmpty = false,\n            )\n\n            checkbox(\n                DRY_RUN,\n                \"true\",\n                \"Dry run?\",\n                description =\n                    \"Whether to perform a dry run where nothing is published and released\",\n                display = ParameterDisplay.PROMPT,\n                checked = \"true\",\n                unchecked = \"false\",\n            )\n\n            password(\"env.JRELEASER_GITHUB_TOKEN\", \"%github-pull-request-token%\")\n\n            text(\"env.JRELEASER_DRY_RUN\", \"%$DRY_RUN%\")\n            text(\"env.JRELEASER_PROJECT_VERSION\", \"%releaseVersion%\")\n\n            text(\"env.JRELEASER_ANNOUNCE_SLACK_ACTIVE\", \"NEVER\")\n            text(\"env.JRELEASER_ANNOUNCE_SLACK_TOKEN\", \"%slack-token%\")\n            text(\"env.JRELEASER_ANNOUNCE_SLACK_WEBHOOK\", \"%slack-webhook%\")\n\n            password(\"env.JRELEASER_GPG_PASSPHRASE\", \"%signing-key-passphrase%\")\n\n            text(\"env.JRELEASER_MAVENCENTRAL_USERNAME\", \"%publish-username%\")\n            password(\"env.JRELEASER_MAVENCENTRAL_TOKEN\", \"%publish-password%\")\n          }\n\n          steps {\n            setVersion(\"Set release version\", \"%releaseVersion%\", javaVersion)\n\n            commitAndPush(\n                \"Push release version\",\n                \"build: release version %releaseVersion%\",\n                dryRunParameter = DRY_RUN,\n            )\n\n            script {\n              scriptContent =\n                  \"\"\"\n                #!/bin/bash\n                \n                set -eux\n                \n                apt-get update\n                apt-get install -o Acquire::Retries=10 --yes build-essential curl git unzip zip\n                \n                # Get the jreleaser downloader\n                curl -sL https://raw.githubusercontent.com/jreleaser/release-action/refs/tags/2.5.0/get_jreleaser.java > get_jreleaser.java\n\n                # Download JReleaser\n                java get_jreleaser.java 1.22.0\n\n                if [ \"%dry-run%\" = \"true\" ]; then\n                  echo \"we are on a dry run, only performing upload to maven central\"\n                  export JRELEASER_MAVENCENTRAL_STAGE=UPLOAD\n                  export JRELEASER_ANNOUNCE_SLACK_ACTIVE=NEVER\n                else\n                  echo \"we will do a full deploy to maven central\"\n                  export JRELEASER_MAVENCENTRAL_STAGE=FULL\n                  export JRELEASER_ANNOUNCE_SLACK_ACTIVE=ALWAYS\n                fi\n                \n                # Execute JReleaser\n                java -jar jreleaser-cli.jar assemble\n                java -jar jreleaser-cli.jar full-release --debug\n              \"\"\"\n                      .trimIndent()\n\n              dockerImagePlatform = ScriptBuildStep.ImagePlatform.Linux\n              dockerImage = javaVersion.dockerImage\n              dockerRunParameters =\n                  \"--volume /var/run/docker.sock:/var/run/docker.sock --volume %teamcity.build.checkoutDir%/signingkeysandbox:/root/.gnupg\"\n            }\n\n            setVersion(\"Set next snapshot version\", \"%nextSnapshotVersion%\", javaVersion)\n\n            commitAndPush(\n                \"Push next snapshot version\",\n                \"build: update version to %nextSnapshotVersion%\",\n                dryRunParameter = DRY_RUN,\n            )\n          }\n\n          artifactRules =\n              \"\"\"\n            +:artifacts => artifacts\n            +:out/jreleaser => jreleaser\n            \"\"\"\n                  .trimIndent()\n\n          dependencies {\n            artifacts(AbsoluteId(\"Tools_ReleaseTool\")) {\n              buildRule = lastSuccessful()\n              artifactRules = \"rt.jar => lib\"\n            }\n          }\n\n          requirements { runOnLinux(LinuxSize.SMALL) }\n        },\n    )\n"
  },
  {
    "path": ".teamcity/builds/SemgrepCheck.kt",
    "content": "package builds\n\nimport jetbrains.buildServer.configs.kotlin.buildSteps.ScriptBuildStep\n\nclass SemgrepCheck(id: String, name: String, scalaVersion: ScalaVersion) :\n    Maven(\n        id,\n        name,\n        \"dependency:tree\",\n        JavaVersion.V_17,\n        scalaVersion,\n        Neo4jVersion.V_NONE,\n        \"-DoutputFile=maven_dep_tree.txt\") {\n\n  init {\n\n    params.password(\"env.SEMGREP_APP_TOKEN\", \"%semgrep-app-token%\")\n    params.text(\"env.SEMGREP_REPO_NAME\", FULL_GITHUB_REPOSITORY)\n    params.text(\"env.SEMGREP_REPO_URL\", GITHUB_URL)\n    params.text(\"env.SEMGREP_BRANCH\", \"%teamcity.build.branch%\")\n    params.text(\"env.SEMGREP_JOB_URL\", \"%env.BUILD_URL%\")\n    params.text(\"env.SEMGREP_COMMIT\", \"%env.BUILD_VCS_NUMBER%\")\n\n    steps.step(\n        ScriptBuildStep {\n          scriptContent = \"semgrep ci --no-git-ignore\"\n          dockerImagePlatform = ScriptBuildStep.ImagePlatform.Linux\n          dockerImage = SEMGREP_DOCKER_IMAGE\n          dockerRunParameters =\n              \"--volume /var/run/docker.sock:/var/run/docker.sock --volume %teamcity.build.checkoutDir%/signingkeysandbox:/root/.gnupg\"\n        })\n  }\n}\n"
  },
  {
    "path": ".teamcity/builds/WhiteListCheck.kt",
    "content": "package builds\n\nimport jetbrains.buildServer.configs.kotlin.AbsoluteId\nimport jetbrains.buildServer.configs.kotlin.BuildType\nimport jetbrains.buildServer.configs.kotlin.buildSteps.script\nimport jetbrains.buildServer.configs.kotlin.toId\n\nclass WhiteListCheck(id: String, name: String) :\n    BuildType({\n      this.id(id.toId())\n      this.name = name\n\n      dependencies {\n        artifacts(AbsoluteId(\"Tools_WhitelistCheck\")) {\n          buildRule = lastSuccessful()\n          cleanDestination = true\n          artifactRules = \"whitelist-check.tar.gz!** => whitelist-check/\"\n        }\n      }\n\n      steps {\n        script {\n          scriptContent =\n              \"\"\"\n                #!/bin/bash -eu\n                \n                BRANCH=%teamcity.pullRequest.source.branch%\n                if [[ \"${'$'}BRANCH\" =~ dependabot/.* ]]; then\n                  echo \"Raised by dependabot, skipping the white list check\"\n                  exit 0\n                fi\n                \n                echo \"Checking committers on PR %teamcity.build.branch%\"\n                TOKEN=\"%github-pull-request-token%\"\n                \n                # process pull request\n                ./whitelist-check/bin/examine-pull-request $GITHUB_OWNER $GITHUB_REPOSITORY \"${'$'}{TOKEN}\" %teamcity.build.branch% whitelist-check/cla-database.csv\n            \"\"\"\n                  .trimIndent()\n          formatStderrAsError = true\n        }\n      }\n\n      requirements { runOnLinux(LinuxSize.SMALL) }\n    })\n"
  },
  {
    "path": ".teamcity/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project>\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.jetbrains.teamcity</groupId>\n        <artifactId>configs-dsl-kotlin-parent</artifactId>\n        <version>1.0-SNAPSHOT</version>\n        <relativePath/>\n    </parent>\n    <groupId>Connectors_Neo4jSparkConnector</groupId>\n    <artifactId>teamcity-pipeline</artifactId>\n    <version>1.0-SNAPSHOT</version>\n    <name>Connectors_Neo4jSparkConnector Config DSL Script</name>\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <sortpom-maven-plugin.version>4.0.0</sortpom-maven-plugin.version>\n        <spotless-maven-plugin.version>2.40.0</spotless-maven-plugin.version>\n    </properties>\n    <dependencies>\n        <dependency>\n            <groupId>org.jetbrains.kotlin</groupId>\n            <artifactId>kotlin-script-runtime</artifactId>\n            <version>${kotlin.version}</version>\n            <scope>compile</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.jetbrains.kotlin</groupId>\n            <artifactId>kotlin-stdlib-jdk8</artifactId>\n            <version>${kotlin.version}</version>\n            <scope>compile</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.jetbrains.teamcity</groupId>\n            <artifactId>configs-dsl-kotlin-latest</artifactId>\n            <version>${teamcity.dsl.version}</version>\n            <scope>compile</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.jetbrains.teamcity</groupId>\n            <artifactId>configs-dsl-kotlin-plugins-latest</artifactId>\n            <version>1.0-SNAPSHOT</version>\n            <type>pom</type>\n            <scope>compile</scope>\n        </dependency>\n    </dependencies>\n    <repositories>\n        <repository>\n            <snapshots>\n                <enabled>true</enabled>\n            </snapshots>\n            <id>jetbrains-all</id>\n            <url>https://download.jetbrains.com/teamcity-repository</url>\n        </repository>\n        <repository>\n            <snapshots>\n                <enabled>true</enabled>\n            </snapshots>\n            <id>teamcity-server</id>\n            <url>https://live.neo4j-build.io/app/dsl-plugins-repository</url>\n        </repository>\n    </repositories>\n    <pluginRepositories>\n        <pluginRepository>\n            <id>JetBrains</id>\n            <url>https://download.jetbrains.com/teamcity-repository</url>\n        </pluginRepository>\n    </pluginRepositories>\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.jetbrains.kotlin</groupId>\n                <artifactId>kotlin-maven-plugin</artifactId>\n                <version>${kotlin.version}</version>\n                <configuration/>\n                <executions>\n                    <execution>\n                        <id>compile</id>\n                        <goals>\n                            <goal>compile</goal>\n                        </goals>\n                        <phase>process-sources</phase>\n                    </execution>\n                    <execution>\n                        <id>test-compile</id>\n                        <goals>\n                            <goal>test-compile</goal>\n                        </goals>\n                        <phase>process-test-sources</phase>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.jetbrains.teamcity</groupId>\n                <artifactId>teamcity-configs-maven-plugin</artifactId>\n                <version>${teamcity.dsl.version}</version>\n                <configuration>\n                    <format>kotlin</format>\n                    <dstDir>target/generated-configs</dstDir>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>com.github.ekryd.sortpom</groupId>\n                <artifactId>sortpom-maven-plugin</artifactId>\n                <version>${sortpom-maven-plugin.version}</version>\n                <configuration>\n                    <encoding>${project.build.sourceEncoding}</encoding>\n                    <keepBlankLines>false</keepBlankLines>\n                    <indentAttribute>schemaLocation</indentAttribute>\n                    <nrOfIndentSpace>4</nrOfIndentSpace>\n                    <sortProperties>true</sortProperties>\n                    <sortDependencies>scope,groupId,artifactId</sortDependencies>\n                    <createBackupFile>false</createBackupFile>\n                    <expandEmptyElements>false</expandEmptyElements>\n                </configuration>\n                <executions>\n                    <execution>\n                        <goals>\n                            <goal>verify</goal>\n                        </goals>\n                        <phase>validate</phase>\n                        <configuration>\n                            <verifyFail>STOP</verifyFail>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>com.diffplug.spotless</groupId>\n                <artifactId>spotless-maven-plugin</artifactId>\n                <version>${spotless-maven-plugin.version}</version>\n                <configuration>\n                    <kotlin>\n                        <!-- These are the defaults, you can override if you want -->\n                        <includes>\n                            <include>**/*.kt</include>\n                            <include>**/*.kts</include>\n                        </includes>\n                        <ktfmt>\n                            <version>0.46</version>\n                            <style>DEFAULT</style>\n                            <blockIndent>2</blockIndent>\n                            <continuationIndent>4</continuationIndent>\n                            <removeUnusedImport>true</removeUnusedImport>\n                            <maxWidth>100</maxWidth>\n                        </ktfmt>\n                    </kotlin>\n                </configuration>\n                <executions>\n                    <execution>\n                        <goals>\n                            <goal>check</goal>\n                        </goals>\n                        <phase>compile</phase>\n                    </execution>\n                </executions>\n            </plugin>\n        </plugins>\n        <sourceDirectory>${basedir}</sourceDirectory>\n    </build>\n</project>\n"
  },
  {
    "path": ".teamcity/settings.kts",
    "content": "import builds.Build\nimport builds.DEFAULT_BRANCH\nimport builds.JavaVersion\nimport builds.Neo4jSparkConnectorVcs\nimport builds.Neo4jVersion\nimport builds.PySparkVersion\nimport builds.ScalaVersion\nimport jetbrains.buildServer.configs.kotlin.Project\nimport jetbrains.buildServer.configs.kotlin.failureConditions.BuildFailureOnText\nimport jetbrains.buildServer.configs.kotlin.failureConditions.failOnText\nimport jetbrains.buildServer.configs.kotlin.project\nimport jetbrains.buildServer.configs.kotlin.triggers.schedule\nimport jetbrains.buildServer.configs.kotlin.triggers.vcs\nimport jetbrains.buildServer.configs.kotlin.version\n\nversion = \"2025.11\"\n\nproject {\n  params {\n    text(\"default-spark-branch\", DEFAULT_BRANCH)\n\n    text(\"osssonatypeorg-username\", \"%publish-username%\")\n    password(\"osssonatypeorg-password\", \"%publish-password%\")\n    password(\"signing-key-passphrase\", \"%publish-signing-key-password%\")\n    password(\"github-commit-status-token\", \"%github-token%\")\n    password(\"github-pull-request-token\", \"%github-token%\")\n    password(\"semgrep-app-token\", \"%semgrep-token%\")\n  }\n\n  vcsRoot(Neo4jSparkConnectorVcs)\n\n  subProject(\n      Build(\n          name = \"main\",\n          javaVersions =\n              setOf(JavaVersion.V_8, JavaVersion.V_11, JavaVersion.V_17, JavaVersion.V_21),\n          scalaVersions = setOf(ScalaVersion.V2_12, ScalaVersion.V2_13),\n          pysparkVersions = setOf(PySparkVersion.V3_4, PySparkVersion.V3_5),\n          neo4jVersions = setOf(Neo4jVersion.V_4_4, Neo4jVersion.V_5, Neo4jVersion.V_CALVER),\n          forPullRequests = false,\n      ) {\n        triggers {\n          vcs {\n            this.branchFilter = buildString {\n              appendLine(\"+:$DEFAULT_BRANCH\")\n              appendLine(\"+:refs/heads/$DEFAULT_BRANCH\")\n            }\n            this.triggerRules =\n                \"\"\"\n              -:comment=^build.*release version.*:**\n              -:comment=^build.*update version.*:**\n              \"\"\"\n                    .trimIndent()\n          }\n        }\n      },\n  )\n\n  subProject(\n      Build(\n          name = \"pull-request\",\n          javaVersions = setOf(JavaVersion.V_8, JavaVersion.V_11, JavaVersion.V_17),\n          scalaVersions = setOf(ScalaVersion.V2_12, ScalaVersion.V2_13),\n          pysparkVersions = setOf(PySparkVersion.V3_5),\n          neo4jVersions = setOf(Neo4jVersion.V_4_4, Neo4jVersion.V_5, Neo4jVersion.V_CALVER),\n          forPullRequests = true,\n      ) {\n        triggers {\n          vcs {\n            this.branchFilter = buildString {\n              appendLine(\"+:pull/*\")\n              appendLine(\"+:refs/heads/pull/*\")\n            }\n          }\n        }\n\n        // when a PR gets closed, TC falls back to main branch to run the pipeline, which we don't\n        // want\n        failureConditions {\n          failOnText {\n            conditionType = BuildFailureOnText.ConditionType.CONTAINS\n            pattern = \"which does not correspond to any branch monitored by the build VCS roots\"\n            failureMessage = \"Error: The branch %teamcity.build.branch% does not exist\"\n            reverse = false\n            stopBuildOnFailure = true\n          }\n        }\n      },\n  )\n\n  subProject(\n      Project {\n        this.id(\"compatibility\")\n        name = \"compatibility\"\n\n        Neo4jVersion.entries.minus(Neo4jVersion.V_NONE).forEach { neo4j ->\n          subProject(\n              Build(\n                  name = neo4j.version,\n                  javaVersions =\n                      setOf(JavaVersion.V_8, JavaVersion.V_11, JavaVersion.V_17, JavaVersion.V_21),\n                  scalaVersions = setOf(ScalaVersion.V2_12, ScalaVersion.V2_13),\n                  pysparkVersions = setOf(PySparkVersion.V3_4, PySparkVersion.V3_5),\n                  neo4jVersions = setOf(neo4j),\n                  forPullRequests = false,\n                  forCompatibility = true,\n              ) {\n                triggers {\n                  vcs { enabled = false }\n\n                  schedule {\n                    branchFilter = buildString {\n                      appendLine(\"+:$DEFAULT_BRANCH\")\n                      appendLine(\"+:refs/heads/$DEFAULT_BRANCH\")\n                    }\n                    schedulingPolicy = daily {\n                      hour = 7\n                      minute = 0\n                    }\n                    triggerBuild = always()\n                    withPendingChangesOnly = false\n                    enforceCleanCheckout = true\n                    enforceCleanCheckoutForDependencies = true\n                  }\n                }\n              },\n          )\n        }\n      },\n  )\n}\n"
  },
  {
    "path": "LICENSE.txt",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "README.md",
    "content": "# Neo4j Connector for Apache Spark\n\nThis repository contains the Neo4j Connector for Apache Spark.\n\n## License\n\nThis neo4j-connector-apache-spark is Apache 2 Licensed\n\n## Documentation\n\nThe documentation for Neo4j Connector for Apache Spark lives at https://github.com/neo4j/docs-spark repository.\n\n## Building for Spark 3\n\nYou can build for Spark 3.x with both Scala 2.12 and Scala 2.13\n\n```\n./maven-release.sh package 2.12\n./maven-release.sh package 2.13\n```\n\nThese commands will generate the corresponding targets\n* `spark-3/target/neo4j-connector-apache-spark_2.12-<version>_for_spark_3.jar`\n* `spark-3/target/neo4j-connector-apache-spark_2.13-<version>_for_spark_3.jar`\n\n\n## Integration with Apache Spark Applications\n\n**spark-shell, pyspark, or spark-submit**\n\n`$SPARK_HOME/bin/spark-shell --jars neo4j-connector-apache-spark_2.12-<version>_for_spark_3.jar`\n\n`$SPARK_HOME/bin/spark-shell --packages org.neo4j:neo4j-connector-apache-spark_2.12:<version>_for_spark_3`\n\n**sbt**\n\nIf you use the [sbt-spark-package plugin](https://github.com/databricks/sbt-spark-package), in your sbt build file, add:\n\n```scala\nresolvers += \"Spark Packages Repo\" at \"http://dl.bintray.com/spark-packages/maven\"\nlibraryDependencies += \"org.neo4j\" % \"neo4j-connector-apache-spark_2.12\" % \"<version>_for_spark_3\"\n```  \n\n**maven**  \n\nIn your pom.xml, add:   \n\n```xml\n<dependencies>\n  <!-- list of dependencies -->\n  <dependency>\n    <groupId>org.neo4j</groupId>\n    <artifactId>neo4j-connector-apache-spark_2.12</artifactId>\n    <version>[version]_for_spark_3</version>\n  </dependency>\n</dependencies>\n```\n\nFor more info about the available version visit https://neo4j.com/developer/spark/overview/#_compatibility\n"
  },
  {
    "path": "common/LICENSES.txt",
    "content": "This file contains the full license text of the included third party\nlibraries. For an overview of the licenses see the NOTICE.txt file.\n\n\n------------------------------------------------------------------------------\nApache Software License, Version 2.0\n  IntelliJ IDEA Annotations\n  Kotlin Stdlib\n  Netty/Buffer\n  Netty/Codec\n  Netty/Common\n  Netty/Handler\n  Netty/Resolver\n  Netty/TomcatNative [OpenSSL - Classes]\n  Netty/Transport\n  Netty/Transport/Native/Unix/Common\n  Non-Blocking Reactive Foundation for the JVM\n  org.apiguardian:apiguardian-api\n------------------------------------------------------------------------------\n\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n\n\n\n------------------------------------------------------------------------------\nMIT License\n  SLF4J API Module\n------------------------------------------------------------------------------\n\nThe MIT License\n\nCopyright (c) <year> <copyright holders>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n\n\n\n------------------------------------------------------------------------------\nMIT No Attribution License\n  reactive-streams\n------------------------------------------------------------------------------\n\nMIT No Attribution\n\nCopyright <year> <copyright holders>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this\nsoftware and associated documentation files (the \"Software\"), to deal in the Software\nwithout restriction, including without limitation the rights to use, copy, modify,\nmerge, publish, distribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\nINCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A\nPARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\nHOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\n\n\n"
  },
  {
    "path": "common/NOTICE.txt",
    "content": "Copyright (c) \"Neo4j\"\nNeo4j Sweden AB [https://neo4j.com]\n\nThis file is part of Neo4j.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n\nFull license texts are found in LICENSES.txt.\n\n\nThird-party licenses\n--------------------\n\nApache Software License, Version 2.0\n  IntelliJ IDEA Annotations\n  Kotlin Stdlib\n  Netty/Buffer\n  Netty/Codec\n  Netty/Common\n  Netty/Handler\n  Netty/Resolver\n  Netty/TomcatNative [OpenSSL - Classes]\n  Netty/Transport\n  Netty/Transport/Native/Unix/Common\n  Non-Blocking Reactive Foundation for the JVM\n  org.apiguardian:apiguardian-api\n\nMIT License\n  SLF4J API Module\n\nMIT No Attribution License\n  reactive-streams\n\n"
  },
  {
    "path": "common/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n        xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.neo4j</groupId>\n        <artifactId>neo4j-connector-apache-spark_parent</artifactId>\n        <version>5.4.3-SNAPSHOT</version>\n    </parent>\n    <artifactId>neo4j-connector-apache-spark_common</artifactId>\n    <packaging>jar</packaging>\n    <name>neo4j-connector-apache-spark-common</name>\n    <description>Common Services for Neo4j Connector for Apache Spark using the binary Bolt Driver</description>\n    <dependencies>\n        <dependency>\n            <groupId>org.neo4j</groupId>\n            <artifactId>caniuse-core</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.neo4j</groupId>\n            <artifactId>caniuse-neo4j-detection</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.neo4j</groupId>\n            <artifactId>neo4j-cypher-dsl</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.neo4j.connectors</groupId>\n            <artifactId>commons-authn-spi</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.neo4j.connectors</groupId>\n            <artifactId>commons-reauth-driver</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.neo4j.driver</groupId>\n            <artifactId>neo4j-java-driver-slim</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.spark</groupId>\n            <artifactId>spark-core_${scala.binary.version}</artifactId>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.spark</groupId>\n            <artifactId>spark-sql_${scala.binary.version}</artifactId>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.scala-lang</groupId>\n            <artifactId>scala-library</artifactId>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.scala-lang</groupId>\n            <artifactId>scala-reflect</artifactId>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.neo4j.connectors</groupId>\n            <artifactId>commons-authn-provided</artifactId>\n            <scope>runtime</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.neo4j</groupId>\n            <artifactId>neo4j-connector-apache-spark_test-support</artifactId>\n            <version>${project.version}</version>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.scalatest</groupId>\n            <artifactId>scalatest_${scala.binary.version}</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.scalatestplus</groupId>\n            <artifactId>junit-4-13_${scala.binary.version}</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>pl.pragmatists</groupId>\n            <artifactId>JUnitParams</artifactId>\n            <version>1.1.1</version>\n            <scope>test</scope>\n        </dependency>\n    </dependencies>\n    <build>\n        <resources>\n            <resource>\n                <filtering>true</filtering>\n                <directory>src/main/resources</directory>\n            </resource>\n        </resources>\n        <plugins>\n            <plugin>\n                <groupId>net.alchim31.maven</groupId>\n                <artifactId>scala-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-failsafe-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "common/src/main/java/org/neo4j/spark/util/ReflectionUtils.java",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark.util;\n\nimport org.apache.spark.sql.connector.expressions.Expression;\nimport org.apache.spark.sql.connector.expressions.NamedReference;\nimport org.apache.spark.sql.connector.expressions.aggregate.Aggregation;\n\nimport java.lang.invoke.MethodHandle;\nimport java.lang.invoke.MethodHandles;\nimport java.lang.invoke.MethodType;\nimport java.util.Optional;\nimport java.util.stream.Stream;\n\npublic class ReflectionUtils {\n\n    private static final MethodHandles.Lookup lookup = MethodHandles.lookup();\n\n    private static Optional<MethodHandle> getGroupByColumns() {\n        try {\n            return Optional.of(lookup\n                    .findVirtual(Aggregation.class, \"groupByColumns\", MethodType.methodType(NamedReference[].class))\n                    .asType(MethodType.methodType(Expression[].class, Aggregation.class)));\n        } catch (Exception e) {\n            return Optional.empty();\n        }\n    }\n\n    private static Optional<MethodHandle> getGroupByExpressions() {\n        try {\n            return Optional.of(lookup\n                    .findVirtual(Aggregation.class, \"groupByExpressions\", MethodType.methodType(Expression[].class)));\n        } catch (Exception e) {\n            return Optional.empty();\n        }\n    }\n\n    private static final Optional<MethodHandle> groupByColumns = getGroupByColumns();\n    private static final Optional<MethodHandle> groupByExpressions = getGroupByExpressions();\n\n    private static final Expression[] EMPTY = new Expression[0];\n\n    public static Expression[] groupByCols(Aggregation agg) {\n        return Stream.of(groupByExpressions, groupByColumns)\n                .filter(Optional::isPresent)\n                .map(Optional::get)\n                .map(mh -> {\n                    try {\n                        return (Expression[]) mh.invokeExact(agg);\n                    } catch (Throwable e) {\n                        return EMPTY;\n                    }\n                })\n                .findFirst()\n                .orElse(EMPTY);\n    }\n\n}"
  },
  {
    "path": "common/src/main/resources/neo4j-spark-connector.properties",
    "content": "version=${project.version}"
  },
  {
    "path": "common/src/main/scala/org/neo4j/spark/config/TopN.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark.config\n\nimport org.apache.spark.sql.connector.expressions.SortOrder\n\ncase class TopN(limit: Long, orders: Array[SortOrder] = Array.empty)\n"
  },
  {
    "path": "common/src/main/scala/org/neo4j/spark/converter/DataConverter.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark.converter\n\nimport org.apache.spark.sql.catalyst.InternalRow\nimport org.apache.spark.sql.catalyst.expressions.GenericRow\nimport org.apache.spark.sql.catalyst.expressions.GenericRowWithSchema\nimport org.apache.spark.sql.catalyst.expressions.UnsafeRow\nimport org.apache.spark.sql.catalyst.util.ArrayBasedMapData\nimport org.apache.spark.sql.catalyst.util.ArrayData\nimport org.apache.spark.sql.catalyst.util.DateTimeUtils\nimport org.apache.spark.sql.catalyst.util.MapData\nimport org.apache.spark.sql.types._\nimport org.apache.spark.unsafe.types.UTF8String\nimport org.neo4j.driver.Value\nimport org.neo4j.driver.Values\nimport org.neo4j.driver.internal._\nimport org.neo4j.driver.types.IsoDuration\nimport org.neo4j.driver.types.Node\nimport org.neo4j.driver.types.Relationship\nimport org.neo4j.spark.service.SchemaService\nimport org.neo4j.spark.util.Neo4jOptions\nimport org.neo4j.spark.util.Neo4jUtil\n\nimport java.time._\nimport java.time.format.DateTimeFormatter\n\nimport scala.annotation.tailrec\nimport scala.collection.JavaConverters._\n\ntrait DataConverter[T] {\n  def convert(value: Any, dataType: DataType = null): T\n\n  @tailrec\n  final private[converter] def extractStructType(dataType: DataType): StructType = dataType match {\n    case structType: StructType => structType\n    case mapType: MapType       => extractStructType(mapType.valueType)\n    case arrayType: ArrayType   => extractStructType(arrayType.elementType)\n    case _                      => throw new UnsupportedOperationException(s\"$dataType not supported\")\n  }\n}\n\nobject SparkToNeo4jDataConverter {\n  def apply(options: Neo4jOptions): SparkToNeo4jDataConverter = new SparkToNeo4jDataConverter(options)\n\n  private def dayTimeMicrosToNeo4jDuration(micros: Long): Value = {\n    val oneSecondInMicros = 1000000L\n    val oneDayInMicros = 24 * 3600 * oneSecondInMicros\n    val numberDays = Math.floorDiv(micros, oneDayInMicros)\n    val remainderMicros = Math.floorMod(micros, oneDayInMicros)\n    val numberSeconds = Math.floorDiv(remainderMicros, oneSecondInMicros)\n    val numberNanos = Math.floorMod(remainderMicros, oneSecondInMicros) * 1000\n    Values.isoDuration(0L, numberDays, numberSeconds, numberNanos.toInt)\n  }\n\n  // while Neo4j supports years, this driver version's API does not expose it.\n  private def yearMonthIntervalToNeo4jDuration(months: Int): Value = {\n    Values.isoDuration(months.toLong, 0L, 0L, 0)\n  }\n}\n\nclass SparkToNeo4jDataConverter(options: Neo4jOptions) extends DataConverter[Value] {\n\n  override def convert(value: Any, dataType: DataType): Value = {\n    value match {\n      case date: java.sql.Date => convert(date.toLocalDate, dataType)\n      case timestamp: java.sql.Timestamp =>\n        if (options.legacyTypeConversionEnabled) {\n          convert(timestamp.toLocalDateTime, dataType)\n        } else {\n          convert(timestamp.toInstant.atZone(ZoneOffset.UTC), dataType)\n        }\n      case intValue: Int if dataType == DataTypes.DateType =>\n        convert(\n          DateTimeUtils\n            .toJavaDate(intValue),\n          dataType\n        )\n      case intValue: Int if dataType.isInstanceOf[YearMonthIntervalType] && !options.legacyTypeConversionEnabled =>\n        SparkToNeo4jDataConverter.yearMonthIntervalToNeo4jDuration(intValue)\n      case longValue: Long if dataType == DataTypes.TimestampType =>\n        convert(DateTimeUtils.toJavaTimestamp(longValue), dataType)\n      case longValue: Long if dataType == DataTypes.TimestampNTZType && !options.legacyTypeConversionEnabled =>\n        convert(DateTimeUtils.microsToLocalDateTime(longValue), dataType)\n      case longValue: Long if dataType.isInstanceOf[DayTimeIntervalType] && !options.legacyTypeConversionEnabled =>\n        SparkToNeo4jDataConverter.dayTimeMicrosToNeo4jDuration(longValue)\n      case unsafeRow: UnsafeRow => {\n        val structType = extractStructType(dataType)\n        val row = new GenericRowWithSchema(unsafeRow.toSeq(structType).toArray, structType)\n        convert(row)\n      }\n      case struct: GenericRow => {\n        def toMap(struct: GenericRow): Value = {\n          Values.value(\n            struct.schema.fields.map(f => f.name -> convert(struct.getAs(f.name), f.dataType)).toMap.asJava\n          )\n        }\n\n        try {\n          struct.getAs[UTF8String](\"type\").toString match {\n            case SchemaService.POINT_TYPE_2D => Values.point(\n                struct.getAs[Number](\"srid\").intValue(),\n                struct.getAs[Number](\"x\").doubleValue(),\n                struct.getAs[Number](\"y\").doubleValue()\n              )\n            case SchemaService.POINT_TYPE_3D => Values.point(\n                struct.getAs[Number](\"srid\").intValue(),\n                struct.getAs[Number](\"x\").doubleValue(),\n                struct.getAs[Number](\"y\").doubleValue(),\n                struct.getAs[Number](\"z\").doubleValue()\n              )\n            case SchemaService.DURATION_TYPE => Values.isoDuration(\n                struct.getAs[Number](\"months\").longValue(),\n                struct.getAs[Number](\"days\").longValue(),\n                struct.getAs[Number](\"seconds\").longValue(),\n                struct.getAs[Number](\"nanoseconds\").intValue()\n              )\n            case SchemaService.TIME_TYPE_OFFSET =>\n              Values.value(OffsetTime.parse(struct.getAs[UTF8String](\"value\").toString))\n            case SchemaService.TIME_TYPE_LOCAL =>\n              Values.value(LocalTime.parse(struct.getAs[UTF8String](\"value\").toString))\n            case _ => toMap(struct)\n          }\n        } catch {\n          case _: Throwable => toMap(struct)\n        }\n      }\n      case unsafeArray: ArrayData => {\n        val sparkType = dataType match {\n          case arrayType: ArrayType => arrayType.elementType\n          case _                    => dataType\n        }\n        if (sparkType == DataTypes.ByteType && !options.legacyTypeConversionEnabled) {\n          Values.value(unsafeArray.toByteArray)\n        } else {\n          val javaList = unsafeArray.toSeq[AnyRef](sparkType)\n            .map(elem => convert(elem, sparkType))\n            .asJava\n          Values.value(javaList)\n        }\n      }\n      case unsafeMapData: MapData => { // Neo4j only supports Map[String, AnyRef]\n        val mapType = dataType.asInstanceOf[MapType]\n        val map: Map[String, AnyRef] = (0 until unsafeMapData.numElements())\n          .map(i =>\n            (unsafeMapData.keyArray().getUTF8String(i).toString, unsafeMapData.valueArray().get(i, mapType.valueType))\n          )\n          .toMap[String, AnyRef]\n          .mapValues(innerValue => convert(innerValue, mapType.valueType))\n          .toMap[String, AnyRef]\n        Values.value(map.asJava)\n      }\n      case string: UTF8String                                     => convert(string.toString)\n      case decimal: Decimal if dataType.isInstanceOf[DecimalType] => Values.value(decimal.toString)\n      case _                                                      => Values.value(value)\n    }\n  }\n}\n\nobject Neo4jToSparkDataConverter {\n  def apply(options: Neo4jOptions): Neo4jToSparkDataConverter = new Neo4jToSparkDataConverter(options)\n}\n\nclass Neo4jToSparkDataConverter(options: Neo4jOptions) extends DataConverter[Any] {\n\n  override def convert(value: Any, dataType: DataType): Any = {\n    if (dataType != null && dataType == DataTypes.StringType && value != null && !value.isInstanceOf[String]) {\n      convert(Neo4jUtil.mapper.writeValueAsString(value), dataType)\n    } else {\n      value match {\n        case node: Node => {\n          val map = node.asMap()\n          val structType = extractStructType(dataType)\n          val fields = structType\n            .filter(field => field.name != Neo4jUtil.INTERNAL_ID_FIELD && field.name != Neo4jUtil.INTERNAL_LABELS_FIELD)\n            .map(field => convert(map.get(field.name), field.dataType))\n          InternalRow.fromSeq(Seq(convert(node.id()), convert(node.labels())) ++ fields)\n        }\n        case rel: Relationship => {\n          val map = rel.asMap()\n          val structType = extractStructType(dataType)\n          val fields = structType\n            .filter(field =>\n              field.name != Neo4jUtil.INTERNAL_REL_ID_FIELD\n                && field.name != Neo4jUtil.INTERNAL_REL_TYPE_FIELD\n                && field.name != Neo4jUtil.INTERNAL_REL_SOURCE_ID_FIELD\n                && field.name != Neo4jUtil.INTERNAL_REL_TARGET_ID_FIELD\n            )\n            .map(field => convert(map.get(field.name), field.dataType))\n          InternalRow.fromSeq(Seq(\n            convert(rel.id()),\n            convert(rel.`type`()),\n            convert(rel.startNodeId()),\n            convert(rel.endNodeId())\n          ) ++ fields)\n        }\n        case d: IsoDuration => {\n          val months = d.months()\n          val days = d.days()\n          val nanoseconds: Integer = d.nanoseconds()\n          val seconds = d.seconds()\n          InternalRow.fromSeq(Seq(\n            UTF8String.fromString(SchemaService.DURATION_TYPE),\n            months,\n            days,\n            seconds,\n            nanoseconds,\n            UTF8String.fromString(d.toString)\n          ))\n        }\n        case zt: ZonedDateTime => DateTimeUtils.instantToMicros(zt.toInstant)\n        case dt: LocalDateTime => {\n          if (options.legacyTypeConversionEnabled) {\n            DateTimeUtils.instantToMicros(dt.toInstant(ZoneOffset.UTC))\n          } else {\n            DateTimeUtils.localDateTimeToMicros(dt)\n          }\n        }\n        case d: LocalDate => d.toEpochDay.toInt\n        case lt: LocalTime => {\n          InternalRow.fromSeq(Seq(\n            UTF8String.fromString(SchemaService.TIME_TYPE_LOCAL),\n            UTF8String.fromString(lt.format(DateTimeFormatter.ISO_TIME))\n          ))\n        }\n        case t: OffsetTime => {\n          InternalRow.fromSeq(Seq(\n            UTF8String.fromString(SchemaService.TIME_TYPE_OFFSET),\n            UTF8String.fromString(t.format(DateTimeFormatter.ISO_TIME))\n          ))\n        }\n        case p: InternalPoint2D => {\n          val srid: Integer = p.srid()\n          InternalRow.fromSeq(Seq(UTF8String.fromString(SchemaService.POINT_TYPE_2D), srid, p.x(), p.y(), null))\n        }\n        case p: InternalPoint3D => {\n          val srid: Integer = p.srid()\n          InternalRow.fromSeq(Seq(UTF8String.fromString(SchemaService.POINT_TYPE_3D), srid, p.x(), p.y(), p.z()))\n        }\n        case l: java.util.List[_] => {\n          val elementType = if (dataType != null) dataType.asInstanceOf[ArrayType].elementType else null\n          ArrayData.toArrayData(l.asScala.map(e => convert(e, elementType)).toArray)\n        }\n        case map: java.util.Map[_, _] => {\n          if (dataType != null) {\n            val mapType = dataType.asInstanceOf[MapType]\n            ArrayBasedMapData(map.asScala.map(t => (convert(t._1, mapType.keyType), convert(t._2, mapType.valueType))))\n          } else {\n            ArrayBasedMapData(map.asScala.map(t => (convert(t._1), convert(t._2))))\n          }\n        }\n        case s: String => UTF8String.fromString(s)\n        case _         => value\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "common/src/main/scala/org/neo4j/spark/converter/TypeConverter.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark.converter\n\nimport org.apache.spark.sql.types.DataType\nimport org.apache.spark.sql.types.DataTypes\nimport org.apache.spark.sql.types.DayTimeIntervalType\nimport org.apache.spark.sql.types.DecimalType\nimport org.apache.spark.sql.types.YearMonthIntervalType\nimport org.neo4j.driver.types.Entity\nimport org.neo4j.spark.converter.CypherToSparkTypeConverter.cleanTerms\nimport org.neo4j.spark.converter.CypherToSparkTypeConverter.durationType\nimport org.neo4j.spark.converter.CypherToSparkTypeConverter.pointType\nimport org.neo4j.spark.converter.CypherToSparkTypeConverter.timeType\nimport org.neo4j.spark.converter.SparkToCypherTypeConverter.mapping\nimport org.neo4j.spark.service.SchemaService.normalizedClassName\nimport org.neo4j.spark.util.Neo4jImplicits.EntityImplicits\nimport org.neo4j.spark.util.Neo4jOptions\n\nimport scala.collection.JavaConverters._\n\ntrait TypeConverter[SOURCE_TYPE, DESTINATION_TYPE] {\n  def convert(sourceType: SOURCE_TYPE, value: Any = null): DESTINATION_TYPE\n}\n\nobject CypherToSparkTypeConverter {\n  def apply(options: Neo4jOptions): CypherToSparkTypeConverter = new CypherToSparkTypeConverter(options)\n\n  private val cleanTerms: String = \"Unmodifiable|Internal|Iso|2D|3D|Offset\"\n\n  val durationType: DataType = DataTypes.createStructType(Array(\n    DataTypes.createStructField(\"type\", DataTypes.StringType, false),\n    DataTypes.createStructField(\"months\", DataTypes.LongType, false),\n    DataTypes.createStructField(\"days\", DataTypes.LongType, false),\n    DataTypes.createStructField(\"seconds\", DataTypes.LongType, false),\n    DataTypes.createStructField(\"nanoseconds\", DataTypes.IntegerType, false),\n    DataTypes.createStructField(\"value\", DataTypes.StringType, false)\n  ))\n\n  val pointType: DataType = DataTypes.createStructType(Array(\n    DataTypes.createStructField(\"type\", DataTypes.StringType, false),\n    DataTypes.createStructField(\"srid\", DataTypes.IntegerType, false),\n    DataTypes.createStructField(\"x\", DataTypes.DoubleType, false),\n    DataTypes.createStructField(\"y\", DataTypes.DoubleType, false),\n    DataTypes.createStructField(\"z\", DataTypes.DoubleType, true)\n  ))\n\n  val timeType: DataType = DataTypes.createStructType(Array(\n    DataTypes.createStructField(\"type\", DataTypes.StringType, false),\n    DataTypes.createStructField(\"value\", DataTypes.StringType, false)\n  ))\n}\n\nclass CypherToSparkTypeConverter(options: Neo4jOptions) extends TypeConverter[String, DataType] {\n\n  override def convert(sourceType: String, value: Any = null): DataType = {\n    var cleanedSourceType = sourceType.replaceAll(cleanTerms, \"\")\n    if (options.legacyTypeConversionEnabled) {\n      cleanedSourceType = cleanedSourceType.replaceAll(\"Local|Zoned\", \"\")\n    }\n    cleanedSourceType match {\n      case \"Node\" | \"Relationship\" =>\n        if (value != null) value.asInstanceOf[Entity].toStruct(options) else DataTypes.NullType\n      case \"NodeArray\" | \"RelationshipArray\" =>\n        if (value != null) DataTypes.createArrayType(value.asInstanceOf[Entity].toStruct(options))\n        else DataTypes.NullType\n      case \"Boolean\"                    => DataTypes.BooleanType\n      case \"Long\"                       => DataTypes.LongType\n      case \"Double\"                     => DataTypes.DoubleType\n      case \"Point\"                      => pointType\n      case \"DateTime\" | \"ZonedDateTime\" => DataTypes.TimestampType\n      case \"LocalDateTime\" =>\n        if (options.legacyTypeConversionEnabled) {\n          DataTypes.TimestampType\n        } else {\n          DataTypes.TimestampNTZType\n        }\n      case \"Time\" | \"LocalTime\" => timeType\n      case \"Date\" | \"LocalDate\" => DataTypes.DateType\n      case \"Duration\"           => durationType\n      case \"ByteArray\"          => DataTypes.BinaryType\n      case \"Map\" => {\n        val valueType = if (value == null) {\n          DataTypes.NullType\n        } else {\n          val map = value.asInstanceOf[java.util.Map[String, AnyRef]].asScala\n          val types = map.values\n            .map(value => normalizedClassName(value, options))\n            .toSet\n          if (types.size == 1) convert(types.head, map.values.head) else DataTypes.StringType\n        }\n        DataTypes.createMapType(DataTypes.StringType, valueType)\n      }\n      case \"Array\" => {\n        val valueType = if (value == null) {\n          DataTypes.NullType\n        } else {\n          val list = value.asInstanceOf[java.util.List[AnyRef]].asScala\n          val types = list\n            .map(value => normalizedClassName(value, options))\n            .toSet\n          if (types.size == 1) convert(types.head, list.head) else DataTypes.StringType\n        }\n        DataTypes.createArrayType(valueType)\n      }\n      // These are from APOC\n      case \"StringArray\"                          => DataTypes.createArrayType(DataTypes.StringType)\n      case \"LongArray\"                            => DataTypes.createArrayType(DataTypes.LongType)\n      case \"DoubleArray\"                          => DataTypes.createArrayType(DataTypes.DoubleType)\n      case \"BooleanArray\"                         => DataTypes.createArrayType(DataTypes.BooleanType)\n      case \"PointArray\"                           => DataTypes.createArrayType(pointType)\n      case \"DateTimeArray\" | \"ZonedDateTimeArray\" => DataTypes.createArrayType(DataTypes.TimestampType)\n      case \"TimeArray\" | \"LocalTimeArray\"         => DataTypes.createArrayType(timeType)\n      case \"DateArray\" | \"LocalDateArray\"         => DataTypes.createArrayType(DataTypes.DateType)\n      case \"DurationArray\"                        => DataTypes.createArrayType(durationType)\n      // Default is String\n      case _ => DataTypes.StringType\n    }\n  }\n}\n\nobject SparkToCypherTypeConverter {\n  def apply(options: Neo4jOptions): SparkToCypherTypeConverter = new SparkToCypherTypeConverter(options)\n\n  private val baseMappings: Map[DataType, String] = Map(\n    DataTypes.BooleanType -> \"BOOLEAN\",\n    DataTypes.StringType -> \"STRING\",\n    DecimalType.SYSTEM_DEFAULT -> \"STRING\",\n    DataTypes.ByteType -> \"INTEGER\",\n    DataTypes.ShortType -> \"INTEGER\",\n    DataTypes.IntegerType -> \"INTEGER\",\n    DataTypes.LongType -> \"INTEGER\",\n    DataTypes.FloatType -> \"FLOAT\",\n    DataTypes.DoubleType -> \"FLOAT\",\n    DataTypes.DateType -> \"DATE\",\n    durationType -> \"DURATION\",\n    pointType -> \"POINT\",\n    // Cypher graph entities do not allow null values in arrays\n    DataTypes.createArrayType(DataTypes.BooleanType, false) -> \"LIST<BOOLEAN NOT NULL>\",\n    DataTypes.createArrayType(DataTypes.StringType, false) -> \"LIST<STRING NOT NULL>\",\n    DataTypes.createArrayType(DecimalType.SYSTEM_DEFAULT, false) -> \"LIST<STRING NOT NULL>\",\n    DataTypes.createArrayType(DataTypes.ShortType, false) -> \"LIST<INTEGER NOT NULL>\",\n    DataTypes.createArrayType(DataTypes.IntegerType, false) -> \"LIST<INTEGER NOT NULL>\",\n    DataTypes.createArrayType(DataTypes.LongType, false) -> \"LIST<INTEGER NOT NULL>\",\n    DataTypes.createArrayType(DataTypes.FloatType, false) -> \"LIST<FLOAT NOT NULL>\",\n    DataTypes.createArrayType(DataTypes.DoubleType, false) -> \"LIST<FLOAT NOT NULL>\",\n    DataTypes.createArrayType(DataTypes.DateType, false) -> \"LIST<DATE NOT NULL>\",\n    DataTypes.createArrayType(durationType, false) -> \"LIST<DURATION NOT NULL>\",\n    DataTypes.createArrayType(pointType, false) -> \"LIST<POINT NOT NULL>\"\n  )\n\n  private def mapping(sourceType: DataType, options: Neo4jOptions): String = {\n    val mappings = sourceTypeMappings(options)\n    mappings(sourceType)\n  }\n\n  private def sourceTypeMappings(options: Neo4jOptions): Map[DataType, String] = {\n    var result = baseMappings\n    if (options.legacyTypeConversionEnabled) {\n      result += (DataTypes.TimestampType -> \"LOCAL DATETIME\")\n      result += (DataTypes.createArrayType(DataTypes.TimestampType, false) -> \"LIST<LOCAL DATETIME NOT NULL>\")\n      result += (DataTypes.createArrayType(DataTypes.TimestampType, true) -> \"LIST<LOCAL DATETIME NOT NULL>\")\n    } else {\n      result += (DataTypes.TimestampType -> \"ZONED DATETIME\")\n      result += (DataTypes.TimestampNTZType -> \"LOCAL DATETIME\")\n      result += (DayTimeIntervalType() -> \"DURATION\")\n      result += (YearMonthIntervalType() -> \"DURATION\")\n      result += (DataTypes.createArrayType(DataTypes.ByteType, false) -> \"ByteArray\")\n      result += (DataTypes.createArrayType(DataTypes.TimestampType, false) -> \"LIST<ZONED DATETIME NOT NULL>\")\n      result += (DataTypes.createArrayType(DataTypes.TimestampNTZType, false) -> \"LIST<LOCAL DATETIME NOT NULL>\")\n      result += (DataTypes.createArrayType(DayTimeIntervalType(), false) -> \"LIST<DURATION NOT NULL>\")\n      result += (DataTypes.createArrayType(DayTimeIntervalType(), true) -> \"LIST<DURATION NOT NULL>\")\n      result += (DataTypes.createArrayType(YearMonthIntervalType(), false) -> \"LIST<DURATION NOT NULL>\")\n      result += (DataTypes.createArrayType(YearMonthIntervalType(), true) -> \"LIST<DURATION NOT NULL>\")\n    }\n    result\n  }\n}\n\nclass SparkToCypherTypeConverter(options: Neo4jOptions) extends TypeConverter[DataType, String] {\n  override def convert(sourceType: DataType, value: Any): String = mapping(sourceType, options)\n}\n"
  },
  {
    "path": "common/src/main/scala/org/neo4j/spark/cypher/Cypher5Renderer.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark.cypher\n\nimport org.neo4j.caniuse.Neo4j\nimport org.neo4j.caniuse.Neo4jVersion\nimport org.neo4j.cypherdsl.core.Statement\nimport org.neo4j.cypherdsl.core.renderer.Configuration\nimport org.neo4j.cypherdsl.core.renderer.Dialect\nimport org.neo4j.cypherdsl.core.renderer.Renderer\nimport org.neo4j.spark.cypher.Cypher5Renderer.Neo4jV5\nimport org.neo4j.spark.cypher.CypherVersionSelector.selectCypherVersionClause\n\nclass Cypher5Renderer(neo4j: Neo4j) extends Renderer {\n\n  private val delegate =\n    Renderer.getRenderer(\n      Configuration.newConfig()\n        .withDialect(\n          if (neo4j.getVersion.compareTo(Neo4jV5) < 0) {\n            Dialect.DEFAULT\n          } else {\n            Dialect.NEO4J_5\n          }\n        )\n        .build()\n    )\n\n  override def render(statement: Statement): String = {\n    val rendered = delegate.render(statement)\n    s\"${selectCypherVersionClause(neo4j)}$rendered\"\n  }\n\n}\n\nprivate object Cypher5Renderer {\n  private val Neo4jV5 = new Neo4jVersion(5, 0, 0)\n}\n"
  },
  {
    "path": "common/src/main/scala/org/neo4j/spark/cypher/CypherVersionSelector.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark.cypher\n\nimport org.neo4j.caniuse.CanIUse.INSTANCE.canIUse\nimport org.neo4j.caniuse.Cypher.{INSTANCE => Cypher}\nimport org.neo4j.caniuse.Neo4j\n\nobject CypherVersionSelector {\n\n  def selectCypherVersionClause(neo4j: Neo4j): String = {\n    if (canIUse(Cypher.explicitCypher5Selection()).withNeo4j(neo4j)) {\n      \"CYPHER 5 \"\n    } else {\n      \"\"\n    }\n  }\n}\n"
  },
  {
    "path": "common/src/main/scala/org/neo4j/spark/reader/BasePartitionReader.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark.reader\n\nimport org.apache.spark.internal.Logging\nimport org.apache.spark.sql.catalyst.InternalRow\nimport org.apache.spark.sql.connector.expressions.aggregate.AggregateFunc\nimport org.apache.spark.sql.sources.Filter\nimport org.apache.spark.sql.types.StructType\nimport org.neo4j.caniuse.Neo4j\nimport org.neo4j.driver.Record\nimport org.neo4j.driver.Session\nimport org.neo4j.driver.Transaction\nimport org.neo4j.driver.Values\nimport org.neo4j.spark.service.MappingService\nimport org.neo4j.spark.service.Neo4jQueryReadStrategy\nimport org.neo4j.spark.service.Neo4jQueryService\nimport org.neo4j.spark.service.Neo4jQueryStrategy\nimport org.neo4j.spark.service.Neo4jReadMappingStrategy\nimport org.neo4j.spark.service.PartitionPagination\nimport org.neo4j.spark.util.DriverCache\nimport org.neo4j.spark.util.Neo4jOptions\nimport org.neo4j.spark.util.Neo4jUtil\nimport org.neo4j.spark.util.QueryType\n\nimport java.io.IOException\nimport java.time.Duration\nimport java.util\nimport java.util.concurrent.atomic.AtomicInteger\nimport java.util.concurrent.locks.LockSupport\n\nimport scala.collection.JavaConverters._\n\nabstract class BasePartitionReader(\n  private val neo4j: Neo4j,\n  private val options: Neo4jOptions,\n  private val filters: Array[Filter],\n  private val schema: StructType,\n  private val jobId: String,\n  private val partitionSkipLimit: PartitionPagination,\n  private val scriptResult: java.util.List[java.util.Map[String, AnyRef]],\n  private val requiredColumns: StructType,\n  private val aggregateColumns: Array[AggregateFunc]\n) extends Logging {\n  private var result: Iterator[Record] = _\n  private var session: Session = _\n  private var transaction: Transaction = _\n\n  protected val name: String =\n    if (partitionSkipLimit.partitionNumber > 0) s\"$jobId-${partitionSkipLimit.partitionNumber}\" else jobId\n  protected val driverCache: DriverCache = new DriverCache(options.connection)\n\n  private var nextRow: InternalRow = _\n\n  private lazy val values = {\n    val params = new java.util.HashMap[String, Any]()\n    params.put(Neo4jQueryStrategy.VARIABLE_SCRIPT_RESULT, scriptResult)\n    Neo4jUtil.paramsFromFilters(filters)\n      .foreach(p => params.put(p._1, p._2))\n\n    if (options.query.queryType == QueryType.GDS) {\n      params.putAll(options.gdsMetadata.parameters)\n    }\n\n    params\n  }\n\n  private val mappingService = new MappingService(new Neo4jReadMappingStrategy(options, requiredColumns), options)\n\n  @volatile\n  private var error: Boolean = false\n\n  private val retries = new AtomicInteger(options.transactionSettings.retries)\n\n  @throws(classOf[IOException])\n  def next: Boolean =\n    try {\n      nextHandler()\n    } catch {\n      case t: Throwable =>\n        if (options.transactionSettings.shouldFailOn(t)) {\n          error = true\n          logError(\"Error while invoking next due to explicitly configured failure condition:\", t)\n          throw new IOException(t)\n        }\n\n        if (Neo4jUtil.isRetryableException(t) && retries.get() > 0) {\n          val currentRetry = retries.decrementAndGet\n          logInfo(\n            s\"encountered a transient exception while reading, retrying ${options.transactionSettings.retries - currentRetry} time(s)\",\n            t\n          )\n\n          close()\n          result = null // Reset result to force new query\n\n          // Wait before retry\n          LockSupport.parkNanos(Duration.ofMillis(options.transactionSettings.retryTimeout).toNanos)\n          next\n        } else {\n          error = true\n          logError(\"Error while invoking next:\", t)\n          throw new IOException(t)\n        }\n    }\n\n  private def nextHandler(): Boolean = {\n    if (result == null) {\n      session = driverCache.getOrCreate().session(options.session.toNeo4jSession())\n      transaction = session.beginTransaction(options.toNeo4jTransactionConfig)\n\n      val queryText = query()\n      val queryParams = queryParameters\n\n      logInfo(s\"Running the following query on Neo4j: $queryText\")\n      logDebug(s\"with parameters $queryParams\")\n\n      result = transaction.run(queryText, Values.value(queryParams))\n        .asScala\n    }\n\n    if (result.hasNext) {\n      nextRow = mappingService.convert(result.next(), schema)\n      true\n    } else {\n      false\n    }\n  }\n\n  def get: InternalRow = nextRow\n\n  def close(): Unit = {\n    Neo4jUtil.closeSafely(transaction, log)\n    Neo4jUtil.closeSafely(session, log)\n    driverCache.close()\n  }\n\n  def hasError(): Boolean = error\n\n  protected def query(): String = {\n    new Neo4jQueryService(\n      options,\n      new Neo4jQueryReadStrategy(\n        neo4j,\n        filters,\n        partitionSkipLimit,\n        requiredColumns.fieldNames,\n        aggregateColumns,\n        jobId\n      )\n    )\n      .createQuery()\n  }\n\n  protected def queryParameters: util.Map[String, Any] = values\n}\n"
  },
  {
    "path": "common/src/main/scala/org/neo4j/spark/service/MappingService.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark.service\n\nimport org.apache.spark.internal.Logging\nimport org.apache.spark.sql.catalyst.InternalRow\nimport org.apache.spark.sql.types.StructType\nimport org.neo4j.driver.Record\nimport org.neo4j.driver.Value\nimport org.neo4j.driver.Values\nimport org.neo4j.driver.internal.value.MapValue\nimport org.neo4j.driver.types.Node\nimport org.neo4j.spark.converter.Neo4jToSparkDataConverter\nimport org.neo4j.spark.converter.SparkToNeo4jDataConverter\nimport org.neo4j.spark.service.Neo4jWriteMappingStrategy.KEYS\nimport org.neo4j.spark.service.Neo4jWriteMappingStrategy.PROPERTIES\nimport org.neo4j.spark.util.Neo4jImplicits._\nimport org.neo4j.spark.util.Neo4jNodeMetadata\nimport org.neo4j.spark.util.Neo4jOptions\nimport org.neo4j.spark.util.Neo4jUtil\nimport org.neo4j.spark.util.QueryType\nimport org.neo4j.spark.util.RelationshipSaveStrategy\n\nimport java.util\nimport java.util.function\nimport java.util.function.BiConsumer\n\nimport scala.collection.JavaConverters._\nimport scala.collection.mutable\n\nclass Neo4jWriteMappingStrategy(private val options: Neo4jOptions)\n    extends Neo4jMappingStrategy[InternalRow, Option[java.util.Map[String, AnyRef]]]\n    with Logging {\n\n  private val dataConverter = SparkToNeo4jDataConverter(options)\n\n  override def node(row: InternalRow, schema: StructType): Option[java.util.Map[String, AnyRef]] = {\n    val rowMap: java.util.Map[String, Object] = new java.util.HashMap[String, Object]\n    val keys: java.util.Map[String, Object] = new java.util.HashMap[String, Object]\n    val properties: java.util.Map[String, Object] = new java.util.HashMap[String, Object]\n    rowMap.put(KEYS, keys)\n    rowMap.put(PROPERTIES, properties)\n\n    query(row, schema)\n      .get\n      .forEach(new BiConsumer[String, AnyRef] {\n        override def accept(key: String, value: AnyRef): Unit = if (options.nodeMetadata.nodeKeys.contains(key)) {\n          keys.put(options.nodeMetadata.nodeKeys.getOrElse(key, key), value)\n        } else {\n          properties.put(options.nodeMetadata.properties.getOrElse(key, key), value)\n        }\n      })\n\n    if (options.nodeMetadata.skipNullKeys && containsNull(keys)) {\n      logSkipping(\"node keys\", options.nodeMetadata.nodeKeys.values)\n      None\n    } else {\n      Some(rowMap)\n    }\n  }\n\n  private def nativeStrategyConsumer(): MappingBiConsumer = new MappingBiConsumer {\n\n    override def accept(key: String, value: AnyRef): Unit = {\n      if (key.startsWith(Neo4jUtil.RELATIONSHIP_ALIAS.concat(\".\"))) {\n        relMap.get(PROPERTIES).put(key.removeAlias(), value)\n      } else if (key.startsWith(Neo4jUtil.RELATIONSHIP_SOURCE_ALIAS.concat(\".\"))) {\n        if (options.relationshipMetadata.source.nodeKeys.contains(key)) {\n          sourceNodeMap.get(KEYS).put(key.removeAlias(), value)\n        } else {\n          sourceNodeMap.get(PROPERTIES).put(key.removeAlias(), value)\n        }\n      } else if (key.startsWith(Neo4jUtil.RELATIONSHIP_TARGET_ALIAS.concat(\".\"))) {\n        if (options.relationshipMetadata.target.nodeKeys.contains(key)) {\n          targetNodeMap.get(KEYS).put(key.removeAlias(), value)\n        } else {\n          targetNodeMap.get(PROPERTIES).put(key.removeAlias(), value)\n        }\n      }\n    }\n  }\n\n  private def addToNodeMap(\n    nodeMap: util.Map[String, util.Map[String, AnyRef]],\n    nodeMetadata: Neo4jNodeMetadata,\n    key: String,\n    value: AnyRef\n  ): Unit = {\n    if (nodeMetadata.nodeKeys.contains(key)) {\n      nodeMap.get(KEYS).put(nodeMetadata.nodeKeys.getOrElse(key, key), value)\n    }\n    if (nodeMetadata.properties.contains(key)) {\n      nodeMap.get(PROPERTIES).put(nodeMetadata.properties.getOrElse(key, key), value)\n    }\n  }\n\n  private def keysStrategyConsumer(): MappingBiConsumer = new MappingBiConsumer {\n\n    override def accept(key: String, value: AnyRef): Unit = {\n      val source = options.relationshipMetadata.source\n      val target = options.relationshipMetadata.target\n\n      addToNodeMap(sourceNodeMap, source, key, value)\n      addToNodeMap(targetNodeMap, target, key, value)\n\n      if (options.relationshipMetadata.relationshipKeys.contains(key)) {\n        relMap.get(KEYS).put(options.relationshipMetadata.relationshipKeys.getOrElse(key, key), value)\n      } else {\n        val propertyKey = options.relationshipMetadata.properties match {\n          case Some(relProperties) => relProperties.get(key)\n          case None =>\n            if (!source.includesProperty(key) && !target.includesProperty(key)) {\n              Some(key)\n            } else {\n              None\n            }\n        }\n        propertyKey.foreach(k => relMap.get(PROPERTIES).put(k, value))\n      }\n    }\n  }\n\n  override def relationship(row: InternalRow, schema: StructType): Option[java.util.Map[String, AnyRef]] = {\n    val rowMap: java.util.Map[String, AnyRef] = new java.util.HashMap[String, AnyRef]\n\n    val consumer = options.relationshipMetadata.saveStrategy match {\n      case RelationshipSaveStrategy.NATIVE => nativeStrategyConsumer()\n      case RelationshipSaveStrategy.KEYS   => keysStrategyConsumer()\n    }\n\n    query(row, schema).get.forEach(consumer)\n\n    if (\n      options.relationshipMetadata.saveStrategy.equals(RelationshipSaveStrategy.NATIVE)\n      && consumer.relMap.get(PROPERTIES).isEmpty\n      && consumer.sourceNodeMap.get(PROPERTIES).isEmpty && consumer.sourceNodeMap.get(KEYS).isEmpty\n      && consumer.targetNodeMap.get(PROPERTIES).isEmpty && consumer.targetNodeMap.get(KEYS).isEmpty\n    ) {\n      throw new IllegalArgumentException(\n        \"NATIVE write strategy requires a schema like: rel.[props], source.[props], target.[props]. \" +\n          \"All of these columns are empty in the current schema.\"\n      )\n    }\n\n    if (options.relationshipMetadata.skipNullKeys && containsNull(consumer.relMap, KEYS)) {\n      logSkipping(\"relationship keys\", options.relationshipMetadata.relationshipKeys.values)\n      None\n    } else if (options.relationshipMetadata.source.skipNullKeys && containsNull(consumer.sourceNodeMap, KEYS)) {\n      logSkipping(\"source node keys\", options.relationshipMetadata.source.nodeKeys.values)\n      None\n    } else if (options.relationshipMetadata.target.skipNullKeys && containsNull(consumer.targetNodeMap, KEYS)) {\n      logSkipping(\"target node keys\", options.relationshipMetadata.target.nodeKeys.values)\n      None\n    } else {\n      rowMap.put(Neo4jUtil.RELATIONSHIP_ALIAS, consumer.relMap)\n      rowMap.put(Neo4jUtil.RELATIONSHIP_SOURCE_ALIAS, consumer.sourceNodeMap)\n      rowMap.put(Neo4jUtil.RELATIONSHIP_TARGET_ALIAS, consumer.targetNodeMap)\n      Some(rowMap)\n    }\n  }\n\n  override def query(row: InternalRow, schema: StructType): Option[java.util.Map[String, AnyRef]] = {\n    val seq = row.toSeq(schema)\n    Some(\n      schema.indices\n        .flatMap(i => {\n          val field = schema(i)\n          val neo4jValue = dataConverter.convert(seq(i), field.dataType)\n          neo4jValue match {\n            case map: MapValue =>\n              map.asMap().asScala.toMap\n                .flattenMap(field.name, options.schemaMetadata.mapGroupDuplicateKeys)\n                .mapValues(value => Values.value(value).asInstanceOf[AnyRef])\n                .toSeq\n            case _ => Seq((field.name, neo4jValue))\n          }\n        })\n        .toMap\n        .asJava\n    )\n  }\n\n  // Helper methods\n\n  private def containsNull(map: java.util.Map[String, Object]): Boolean = {\n    map.containsValue(Values.NULL)\n  }\n\n  private def containsNull(map: java.util.Map[String, java.util.Map[String, AnyRef]], key: String): Boolean = {\n    map.get(key).containsValue(Values.NULL)\n  }\n\n  private def logSkipping(keyType: String, keys: Iterable[String]): Unit = {\n    logTrace(s\"Skipping row because it contains null value for one of the $keyType: [${keys.mkString(\", \")}]\")\n  }\n}\n\nclass Neo4jReadMappingStrategy(private val options: Neo4jOptions, requiredColumns: StructType)\n    extends Neo4jMappingStrategy[Record, InternalRow] {\n\n  private val dataConverter = Neo4jToSparkDataConverter(options)\n\n  override def node(record: Record, schema: StructType): InternalRow = {\n    if (requiredColumns.nonEmpty) {\n      query(record, schema)\n    } else {\n      val node = record.get(Neo4jUtil.NODE_ALIAS).asNode()\n      val nodeMap = new util.HashMap[String, Any](node.asMap())\n      nodeMap.put(Neo4jUtil.INTERNAL_ID_FIELD, node.id())\n      nodeMap.put(Neo4jUtil.INTERNAL_LABELS_FIELD, node.labels())\n\n      mapToInternalRow(nodeMap, schema)\n    }\n  }\n\n  private def mapToInternalRow(map: util.Map[String, Any], schema: StructType) = InternalRow\n    .fromSeq(\n      schema.map(field => dataConverter.convert(map.get(field.name), field.dataType))\n    )\n\n  private def flatRelNodeMapping(node: Node, alias: String): mutable.Map[String, Any] = {\n    val nodeMap: mutable.Map[String, Any] = node.asMap().asScala\n      .map(t => (s\"$alias.${t._1}\", t._2))\n    nodeMap.put(\n      s\"<$alias.${\n          Neo4jUtil.INTERNAL_ID_FIELD\n            .replaceAll(\"[<|>]\", \"\")\n        }>\",\n      node.id()\n    )\n    nodeMap.put(\n      s\"<$alias.${\n          Neo4jUtil.INTERNAL_LABELS_FIELD\n            .replaceAll(\"[<|>]\", \"\")\n        }>\",\n      node.labels()\n    )\n    nodeMap\n  }\n\n  private def mapRelNodeMapping(node: Node, alias: String): Map[String, util.Map[String, String]] = {\n    val nodeMap: util.Map[String, String] =\n      new util.HashMap[String, String](node.asMap(new function.Function[Value, String] {\n        override def apply(t: Value): String = t.toString\n      }))\n\n    nodeMap.put(Neo4jUtil.INTERNAL_ID_FIELD, Neo4jUtil.mapper.writeValueAsString(node.id()))\n    nodeMap.put(Neo4jUtil.INTERNAL_LABELS_FIELD, Neo4jUtil.mapper.writeValueAsString(node.labels()))\n    Map(s\"<$alias>\" -> nodeMap)\n  }\n\n  override def relationship(record: Record, schema: StructType): InternalRow = {\n    if (requiredColumns.nonEmpty) {\n      query(record, schema)\n    } else {\n      val rel = record.get(Neo4jUtil.RELATIONSHIP_ALIAS).asRelationship()\n      val relMap = new util.HashMap[String, Any](rel.asMap())\n        .asScala\n        .map(t => (s\"rel.${t._1}\", t._2))\n        .asJava\n      relMap.put(Neo4jUtil.INTERNAL_REL_ID_FIELD, rel.id())\n      relMap.put(Neo4jUtil.INTERNAL_REL_TYPE_FIELD, rel.`type`())\n\n      val source = record.get(Neo4jUtil.RELATIONSHIP_SOURCE_ALIAS).asNode()\n      val target = record.get(Neo4jUtil.RELATIONSHIP_TARGET_ALIAS).asNode()\n\n      val (sourceMap, targetMap) = if (options.relationshipMetadata.nodeMap) {\n        (\n          mapRelNodeMapping(source, Neo4jUtil.RELATIONSHIP_SOURCE_ALIAS),\n          mapRelNodeMapping(target, Neo4jUtil.RELATIONSHIP_TARGET_ALIAS)\n        )\n      } else {\n        (\n          flatRelNodeMapping(source, Neo4jUtil.RELATIONSHIP_SOURCE_ALIAS),\n          flatRelNodeMapping(target, Neo4jUtil.RELATIONSHIP_TARGET_ALIAS)\n        )\n      }\n\n      relMap.putAll(sourceMap.toMap.asJava)\n      relMap.putAll(targetMap.toMap.asJava)\n\n      mapToInternalRow(relMap, schema)\n    }\n  }\n\n  override def query(elem: Record, schema: StructType): InternalRow = mapToInternalRow(\n    elem.asMap(new function.Function[Value, Any] {\n      override def apply(t: Value): Any = t.asObject()\n    }),\n    schema\n  )\n}\n\nabstract class Neo4jMappingStrategy[IN, OUT] extends Serializable {\n  def node(elem: IN, schema: StructType): OUT\n\n  def relationship(elem: IN, schema: StructType): OUT\n\n  def query(elem: IN, schema: StructType): OUT\n}\n\nclass MappingService[IN, OUT](private val strategy: Neo4jMappingStrategy[IN, OUT], private val options: Neo4jOptions)\n    extends Serializable {\n\n  def convert(record: IN, schema: StructType): OUT = options.query.queryType match {\n    case QueryType.LABELS       => strategy.node(record, schema)\n    case QueryType.RELATIONSHIP => strategy.relationship(record, schema)\n    case QueryType.QUERY        => strategy.query(record, schema)\n    case QueryType.GDS          => strategy.query(record, schema)\n  }\n\n}\n\nobject Neo4jWriteMappingStrategy {\n  val KEYS = \"keys\"\n  val PROPERTIES = \"properties\"\n}\n\nabstract private class MappingBiConsumer extends BiConsumer[String, AnyRef] {\n\n  val relMap = new util.HashMap[String, util.Map[String, AnyRef]]()\n  val sourceNodeMap = new util.HashMap[String, util.Map[String, AnyRef]]()\n  val targetNodeMap = new util.HashMap[String, util.Map[String, AnyRef]]()\n\n  relMap.put(KEYS, new util.HashMap[String, AnyRef]())\n  relMap.put(PROPERTIES, new util.HashMap[String, AnyRef]())\n  sourceNodeMap.put(PROPERTIES, new util.HashMap[String, AnyRef]())\n  sourceNodeMap.put(KEYS, new util.HashMap[String, AnyRef]())\n  targetNodeMap.put(PROPERTIES, new util.HashMap[String, AnyRef]())\n  targetNodeMap.put(KEYS, new util.HashMap[String, AnyRef]())\n}\n"
  },
  {
    "path": "common/src/main/scala/org/neo4j/spark/service/Neo4jQueryService.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark.service\n\nimport org.apache.commons.lang3.StringUtils\nimport org.apache.spark.internal.Logging\nimport org.apache.spark.sql.SaveMode\nimport org.apache.spark.sql.connector.expressions.SortDirection\nimport org.apache.spark.sql.connector.expressions.SortOrder\nimport org.apache.spark.sql.connector.expressions.aggregate._\nimport org.apache.spark.sql.sources.And\nimport org.apache.spark.sql.sources.Filter\nimport org.apache.spark.sql.sources.Or\nimport org.neo4j.caniuse.Neo4j\nimport org.neo4j.cypherdsl.core._\nimport org.neo4j.cypherdsl.core.renderer.Renderer\nimport org.neo4j.spark.cypher.Cypher5Renderer\nimport org.neo4j.spark.cypher.CypherVersionSelector.selectCypherVersionClause\nimport org.neo4j.spark.util.Neo4jImplicits._\nimport org.neo4j.spark.util.Neo4jOptions\nimport org.neo4j.spark.util.Neo4jUtil\nimport org.neo4j.spark.util.NodeSaveMode\nimport org.neo4j.spark.util.QueryType\n\nimport scala.collection.JavaConverters._\n\nclass Neo4jQueryWriteStrategy(private val neo4j: Neo4j, private val saveMode: SaveMode) extends Neo4jQueryStrategy {\n\n  override def createStatementForQuery(options: Neo4jOptions): String =\n    s\"\"\"WITH ${\"$\"}scriptResult AS ${Neo4jQueryStrategy.VARIABLE_SCRIPT_RESULT}\n       |UNWIND ${\"$\"}events AS ${Neo4jQueryStrategy.VARIABLE_EVENT}\n       |${options.query.value}\n       |\"\"\".stripMargin\n\n  private def createPropsList(props: Map[String, String], prefix: String): String = {\n    props\n      .map(key => {\n        s\"${key._2.quote()}: ${Neo4jQueryStrategy.VARIABLE_EVENT}.$prefix.${key._2.quote()}\"\n      }).mkString(\", \")\n  }\n\n  private def keywordFromSaveMode(saveMode: Any): String = {\n    saveMode match {\n      case NodeSaveMode.Overwrite | SaveMode.Overwrite                                                 => \"MERGE\"\n      case NodeSaveMode.ErrorIfExists | SaveMode.ErrorIfExists | SaveMode.Append | NodeSaveMode.Append => \"CREATE\"\n      case NodeSaveMode.Match                                                                          => \"MATCH\"\n      case _ => throw new UnsupportedOperationException(s\"SaveMode $saveMode not supported\")\n    }\n  }\n\n  private def createQueryPart(keyword: String, labels: String, keys: String, alias: String): String = {\n    val setStatement = if (!keyword.equals(\"MATCH\"))\n      s\" SET $alias += ${Neo4jQueryStrategy.VARIABLE_EVENT}.$alias.${Neo4jWriteMappingStrategy.PROPERTIES}\"\n    else \"\"\n    s\"\"\"$keyword ($alias${if (labels.isEmpty) \"\" else s\":$labels\"} ${\n        if (keys.isEmpty) \"\"\n        else s\"{$keys}\"\n      })$setStatement\"\"\".stripMargin\n  }\n\n  override def createStatementForRelationships(options: Neo4jOptions): String = {\n    val relationshipKeyword = keywordFromSaveMode(saveMode)\n    val sourceKeyword = keywordFromSaveMode(options.relationshipMetadata.sourceSaveMode)\n    val targetKeyword = keywordFromSaveMode(options.relationshipMetadata.targetSaveMode)\n\n    val relationship = options.relationshipMetadata.relationshipType.quote()\n\n    val sourceLabels = options.relationshipMetadata.source.labels\n      .map(_.quote())\n      .mkString(\":\")\n\n    val targetLabels = options.relationshipMetadata.target.labels\n      .map(_.quote())\n      .mkString(\":\")\n\n    val sourceKeys = createPropsList(\n      options.relationshipMetadata.source.nodeKeys,\n      s\"source.${Neo4jWriteMappingStrategy.KEYS}\"\n    )\n    val targetKeys = createPropsList(\n      options.relationshipMetadata.target.nodeKeys,\n      s\"target.${Neo4jWriteMappingStrategy.KEYS}\"\n    )\n    val sourceQueryPart = createQueryPart(sourceKeyword, sourceLabels, sourceKeys, Neo4jUtil.RELATIONSHIP_SOURCE_ALIAS)\n    val targetQueryPart = createQueryPart(targetKeyword, targetLabels, targetKeys, Neo4jUtil.RELATIONSHIP_TARGET_ALIAS)\n\n    val withQueryPart = if (sourceKeyword != \"MATCH\" && targetKeyword == \"MATCH\")\n      \"\\nWITH source, event\"\n    else {\n      \"\"\n    }\n\n    val relKeys = if (options.relationshipMetadata.relationshipKeys.nonEmpty) {\n      options.relationshipMetadata.relationshipKeys\n        .map(t =>\n          s\"${t._2}: ${Neo4jQueryStrategy.VARIABLE_EVENT}.${Neo4jUtil.RELATIONSHIP_ALIAS}.${Neo4jWriteMappingStrategy.KEYS}.${t._1}\"\n        )\n        .mkString(\"{\", \", \", \"}\")\n    } else {\n      \"\"\n    }\n\n    s\"\"\"${selectCypherVersionClause(neo4j)}UNWIND ${\"$\"}events AS ${Neo4jQueryStrategy.VARIABLE_EVENT}\n       |$sourceQueryPart$withQueryPart\n       |$targetQueryPart\n       |$relationshipKeyword (${Neo4jUtil.RELATIONSHIP_SOURCE_ALIAS})-[${Neo4jUtil.RELATIONSHIP_ALIAS}:$relationship$relKeys]->(${Neo4jUtil.RELATIONSHIP_TARGET_ALIAS})\n       |SET ${Neo4jUtil.RELATIONSHIP_ALIAS} += ${Neo4jQueryStrategy.VARIABLE_EVENT}.${Neo4jUtil.RELATIONSHIP_ALIAS}.${Neo4jWriteMappingStrategy.PROPERTIES}\n       |\"\"\".stripMargin\n  }\n\n  override def createStatementForNodes(options: Neo4jOptions): String = {\n    val keyword = keywordFromSaveMode(saveMode)\n\n    val labels = options.nodeMetadata.labels\n      .map(_.quote())\n      .mkString(\":\")\n\n    val keys = createPropsList(\n      options.nodeMetadata.nodeKeys,\n      Neo4jWriteMappingStrategy.KEYS\n    )\n\n    s\"\"\"${selectCypherVersionClause(neo4j)}UNWIND ${\"$\"}events AS ${Neo4jQueryStrategy.VARIABLE_EVENT}\n       |$keyword (node${if (labels.isEmpty) \"\" else s\":$labels\"} ${if (keys.isEmpty) \"\" else s\"{$keys}\"})\n       |SET node += ${Neo4jQueryStrategy.VARIABLE_EVENT}.${Neo4jWriteMappingStrategy.PROPERTIES}\n       |\"\"\".stripMargin\n  }\n\n  override def createStatementForGDS(options: Neo4jOptions): String =\n    throw new UnsupportedOperationException(\"Write operations with GDS are currently not supported\")\n}\n\nclass Neo4jQueryReadStrategy(\n  neo4j: Neo4j,\n  filters: Array[Filter] = Array.empty[Filter],\n  partitionPagination: PartitionPagination = PartitionPagination.EMPTY,\n  requiredColumns: Seq[String] = Seq.empty,\n  aggregateColumns: Array[AggregateFunc] = Array.empty,\n  jobId: String = \"\"\n) extends Neo4jQueryStrategy with Logging {\n  private val renderer: Renderer = new Cypher5Renderer(neo4j)\n\n  private val hasSkipLimit: Boolean = partitionPagination.skip != -1 && partitionPagination.topN.limit != -1\n\n  override def createStatementForQuery(options: Neo4jOptions): String = {\n    if (partitionPagination.topN.orders.nonEmpty) {\n      logWarning(\n        s\"\"\"Top N push-down optimizations with aggregations are not supported for custom queries.\n           |\\tThese aggregations are going to be ignored.\n           |\\tPlease specify the aggregations in the custom query directly\"\"\".stripMargin\n      )\n    }\n\n    val limitedQuery = if (hasSkipLimit) {\n      s\"${options.query.value} SKIP ${partitionPagination.skip} LIMIT ${partitionPagination.topN.limit}\"\n    } else {\n      s\"${options.query.value}\"\n    }\n\n    s\"WITH $$scriptResult AS scriptResult $limitedQuery\"\n  }\n\n  override def createStatementForRelationships(options: Neo4jOptions): String = {\n    val sourceNode = createNode(Neo4jUtil.RELATIONSHIP_SOURCE_ALIAS, options.relationshipMetadata.source.labels)\n    val targetNode = createNode(Neo4jUtil.RELATIONSHIP_TARGET_ALIAS, options.relationshipMetadata.target.labels)\n\n    val relationship = sourceNode.relationshipTo(targetNode, options.relationshipMetadata.relationshipType)\n      .named(Neo4jUtil.RELATIONSHIP_ALIAS)\n\n    val matchQuery: StatementBuilder.OngoingReadingWithoutWhere =\n      filterRelationship(sourceNode, targetNode, relationship)\n    val returnExpressions: Seq[Expression] = buildReturnExpression(sourceNode, targetNode, relationship)\n    val stmt = if (aggregateColumns.isEmpty) {\n      val query = matchQuery.returning(returnExpressions: _*)\n      buildStatement(options, query, relationship)\n    } else {\n      buildStatementAggregation(options, matchQuery, relationship, returnExpressions)\n    }\n    renderer.render(stmt)\n  }\n\n  private def convertSort(entity: PropertyContainer, order: SortOrder): SortItem = {\n    val sortExpression = order.expression().describe()\n\n    val container: Option[PropertyContainer] = entity match {\n      case relationship: Relationship =>\n        if (sortExpression.contains(s\"${Neo4jUtil.RELATIONSHIP_SOURCE_ALIAS}.\")) {\n          Some(relationship.getLeft)\n        } else if (sortExpression.contains(s\"${Neo4jUtil.RELATIONSHIP_TARGET_ALIAS}.\")) {\n          Some(relationship.getRight)\n        } else if (sortExpression.contains(s\"${Neo4jUtil.RELATIONSHIP_ALIAS}.\")) {\n          Some(relationship)\n        } else {\n          None\n        }\n      case _ => Some(entity)\n    }\n    val direction =\n      if (order.direction() == SortDirection.ASCENDING) SortItem.Direction.ASC else SortItem.Direction.DESC\n\n    Cypher.sort(\n      container\n        .map(_.property(sortExpression.removeAlias()))\n        .getOrElse(Cypher.name(sortExpression.unquote())),\n      direction\n    )\n  }\n\n  private def buildReturnExpression(sourceNode: Node, targetNode: Node, relationship: Relationship): Seq[Expression] = {\n    if (requiredColumns.isEmpty) {\n      Seq(\n        relationship.getRequiredSymbolicName,\n        sourceNode.as(Neo4jUtil.RELATIONSHIP_SOURCE_ALIAS),\n        targetNode.as(Neo4jUtil.RELATIONSHIP_TARGET_ALIAS)\n      )\n    } else {\n      requiredColumns.map(column => {\n        val splatColumn = column.split('.')\n        val entityName = splatColumn.head\n\n        val entity = if (entityName.contains(Neo4jUtil.RELATIONSHIP_ALIAS)) {\n          relationship\n        } else if (entityName.contains(Neo4jUtil.RELATIONSHIP_SOURCE_ALIAS)) {\n          sourceNode\n        } else if (entityName.contains(Neo4jUtil.RELATIONSHIP_TARGET_ALIAS)) {\n          targetNode\n        } else {\n          null\n        }\n\n        if (entity != null && splatColumn.length == 1) {\n          entity match {\n            case n: Node         => n.as(entityName.quote())\n            case r: Relationship => r.getRequiredSymbolicName\n          }\n        } else {\n          getCorrectProperty(column, entity)\n        }\n      })\n    }\n  }\n\n  private def buildStatementAggregation(\n    options: Neo4jOptions,\n    query: StatementBuilder.OngoingReadingWithoutWhere,\n    entity: PropertyContainer,\n    fields: Seq[Expression]\n  ): Statement = {\n    val ret = if (hasSkipLimit) {\n      val id = entity match {\n        case node: Node        => Functions.id(node)\n        case rel: Relationship => Functions.id(rel)\n      }\n      query\n        .`with`(entity)\n        // Spark does not push down limits/top N when aggregation is involved\n        .orderBy(id)\n        .skip(partitionPagination.skip)\n        .limit(partitionPagination.topN.limit)\n        .returning(fields: _*)\n    } else {\n      val orderByProp = options.streamingOrderBy\n      if (StringUtils.isBlank(orderByProp)) {\n        query.returning(fields: _*)\n      } else {\n        query\n          .`with`(entity)\n          .orderBy(entity.property(orderByProp))\n          .ascending()\n          .returning(fields: _*)\n      }\n    }\n    ret.build()\n  }\n\n  private def buildStatement(\n    options: Neo4jOptions,\n    returning: StatementBuilder.TerminalExposesSkip\n      with StatementBuilder.TerminalExposesLimit\n      with StatementBuilder.TerminalExposesOrderBy\n      with StatementBuilder.BuildableStatement[_],\n    entity: PropertyContainer = null\n  ): Statement = {\n\n    def addSkipLimit(ret: StatementBuilder.TerminalExposesSkip\n      with StatementBuilder.TerminalExposesLimit\n      with StatementBuilder.BuildableStatement[_]) = {\n\n      if (partitionPagination.skip == 0) {\n        ret.limit(partitionPagination.topN.limit)\n      } else {\n        ret.skip(partitionPagination.skip)\n          .limit(partitionPagination.topN.limit)\n      }\n    }\n\n    val ret = if (entity == null) {\n      if (hasSkipLimit) addSkipLimit(returning) else returning\n    } else {\n      if (hasSkipLimit) {\n        if (options.partitions == 1 || partitionPagination.topN.orders.nonEmpty) {\n          addSkipLimit(returning.orderBy(partitionPagination.topN.orders.map(order => convertSort(entity, order)): _*))\n        } else {\n          val id = entity match {\n            case node: Node        => Functions.id(node)\n            case rel: Relationship => Functions.id(rel)\n          }\n          addSkipLimit(returning.orderBy(id))\n        }\n      } else {\n        val orderByProp = options.streamingOrderBy\n        if (StringUtils.isBlank(orderByProp)) returning else returning.orderBy(entity.property(orderByProp))\n      }\n    }\n    ret.build()\n  }\n\n  private def filterRelationship(sourceNode: Node, targetNode: Node, relationship: Relationship) = {\n    val matchQuery = Cypher.`match`(sourceNode).`match`(targetNode).`match`(relationship)\n\n    def getContainer(filter: Filter): PropertyContainer = {\n      if (filter.isAttribute(Neo4jUtil.RELATIONSHIP_SOURCE_ALIAS)) {\n        sourceNode\n      } else if (filter.isAttribute(Neo4jUtil.RELATIONSHIP_TARGET_ALIAS)) {\n        targetNode\n      } else if (filter.isAttribute(Neo4jUtil.RELATIONSHIP_ALIAS)) {\n        relationship\n      } else {\n        throw new IllegalArgumentException(s\"Attribute '${filter.getAttribute.get}' is not valid\")\n      }\n    }\n\n    if (filters.nonEmpty) {\n      def mapFilter(filter: Filter): Condition = {\n        filter match {\n          case and: And => mapFilter(and.left).and(mapFilter(and.right))\n          case or: Or   => mapFilter(or.left).or(mapFilter(or.right))\n          case filter: Filter =>\n            Neo4jUtil.mapSparkFiltersToCypher(filter, getContainer(filter), filter.getAttributeWithoutEntityName)\n        }\n      }\n\n      val cypherFilters = filters.map(mapFilter)\n\n      assembleConditionQuery(matchQuery, cypherFilters)\n    }\n    matchQuery\n  }\n\n  private def getCorrectProperty(column: String, entity: PropertyContainer): Expression = {\n    def propertyOrSymbolicName(col: String) = {\n      if (entity != null) entity.property(col) else Cypher.name(col)\n    }\n\n    column match {\n      case Neo4jUtil.INTERNAL_ID_FIELD => Functions.id(entity.asInstanceOf[Node]).as(Neo4jUtil.INTERNAL_ID_FIELD)\n      case Neo4jUtil.INTERNAL_REL_ID_FIELD =>\n        Functions.id(entity.asInstanceOf[Relationship]).as(Neo4jUtil.INTERNAL_REL_ID_FIELD)\n      case Neo4jUtil.INTERNAL_REL_SOURCE_ID_FIELD =>\n        Functions.id(entity.asInstanceOf[Node]).as(Neo4jUtil.INTERNAL_REL_SOURCE_ID_FIELD)\n      case Neo4jUtil.INTERNAL_REL_TARGET_ID_FIELD =>\n        Functions.id(entity.asInstanceOf[Node]).as(Neo4jUtil.INTERNAL_REL_TARGET_ID_FIELD)\n      case Neo4jUtil.INTERNAL_REL_TYPE_FIELD =>\n        Functions.`type`(entity.asInstanceOf[Relationship]).as(Neo4jUtil.INTERNAL_REL_TYPE_FIELD)\n      case Neo4jUtil.INTERNAL_LABELS_FIELD =>\n        Functions.labels(entity.asInstanceOf[Node]).as(Neo4jUtil.INTERNAL_LABELS_FIELD)\n      case Neo4jUtil.INTERNAL_REL_SOURCE_LABELS_FIELD =>\n        Functions.labels(entity.asInstanceOf[Node]).as(Neo4jUtil.INTERNAL_REL_SOURCE_LABELS_FIELD)\n      case Neo4jUtil.INTERNAL_REL_TARGET_LABELS_FIELD =>\n        Functions.labels(entity.asInstanceOf[Node]).as(Neo4jUtil.INTERNAL_REL_TARGET_LABELS_FIELD)\n      case \"*\" => Asterisk.INSTANCE\n      case name => {\n        val cleanedName = name.removeAlias()\n        aggregateColumns.find(_.toString == name)\n          .map {\n            case count: Count => {\n              val col = count.column().describe().unquote().removeAlias()\n              val prop = propertyOrSymbolicName(col)\n              if (count.isDistinct) {\n                Functions.countDistinct(prop).as(name)\n              } else {\n                Functions.count(prop).as(name)\n              }\n            }\n            case countStar: CountStar => Functions.count(Asterisk.INSTANCE).as(name)\n            case max: Max =>\n              val col = max.column().describe().unquote().removeAlias()\n              val prop = propertyOrSymbolicName(col)\n              Functions.max(prop).as(name)\n            case min: Min =>\n              val col = min.column().describe().unquote().removeAlias()\n              val prop = propertyOrSymbolicName(col)\n              Functions.min(prop).as(name)\n            case sum: Sum => {\n              val col = sum.column().describe().unquote().removeAlias()\n              val prop = propertyOrSymbolicName(col)\n              if (sum.isDistinct) {\n                Functions.sumDistinct(prop).as(name)\n              } else {\n                Functions.sum(prop).as(name)\n              }\n            }\n          }\n          .getOrElse(propertyOrSymbolicName(cleanedName).as(name))\n          .asInstanceOf[Expression]\n      }\n    }\n  }\n\n  override def createStatementForNodes(options: Neo4jOptions): String = {\n    val node = createNode(Neo4jUtil.NODE_ALIAS, options.nodeMetadata.labels)\n    val matchQuery = filterNode(node)\n    val expressions = requiredColumns.map(column => getCorrectProperty(column, node))\n    val stmt = if (aggregateColumns.nonEmpty) {\n      buildStatementAggregation(options, matchQuery, node, expressions)\n    } else {\n      val ret = if (requiredColumns.isEmpty) {\n        matchQuery.returning(node)\n      } else {\n        matchQuery.returning(expressions: _*)\n      }\n      buildStatement(options, ret, node)\n    }\n    renderer.render(stmt)\n  }\n\n  private def filterNode(node: Node) = {\n    val matchQuery = Cypher.`match`(node)\n\n    if (filters.nonEmpty) {\n      def mapFilter(filter: Filter): Condition = {\n        filter match {\n          case and: And       => mapFilter(and.left).and(mapFilter(and.right))\n          case or: Or         => mapFilter(or.left).or(mapFilter(or.right))\n          case filter: Filter => Neo4jUtil.mapSparkFiltersToCypher(filter, node)\n        }\n      }\n\n      val cypherFilters = filters.map(mapFilter)\n      assembleConditionQuery(matchQuery, cypherFilters)\n    }\n    matchQuery\n  }\n\n  def createStatementForNodeCount(options: Neo4jOptions): String = {\n    val node = createNode(Neo4jUtil.NODE_ALIAS, options.nodeMetadata.labels)\n    val matchQuery = filterNode(node)\n    renderer.render(buildStatement(options, matchQuery.returning(Functions.count(node).as(\"count\"))))\n  }\n\n  def createStatementForRelationshipCount(options: Neo4jOptions): String = {\n    val sourceNode = createNode(Neo4jUtil.RELATIONSHIP_SOURCE_ALIAS, options.relationshipMetadata.source.labels)\n    val targetNode = createNode(Neo4jUtil.RELATIONSHIP_TARGET_ALIAS, options.relationshipMetadata.target.labels)\n\n    val relationship = sourceNode.relationshipTo(targetNode, options.relationshipMetadata.relationshipType)\n      .named(Neo4jUtil.RELATIONSHIP_ALIAS)\n\n    val matchQuery: StatementBuilder.OngoingReadingWithoutWhere =\n      filterRelationship(sourceNode, targetNode, relationship)\n\n    renderer.render(buildStatement(options, matchQuery.returning(Functions.count(sourceNode).as(\"count\"))))\n  }\n\n  private def assembleConditionQuery(\n    matchQuery: StatementBuilder.OngoingReadingWithoutWhere,\n    filters: Array[Condition]\n  ): StatementBuilder.OngoingReadingWithWhere = {\n    matchQuery.where(\n      filters.fold(Conditions.noCondition()) { (a, b) => a.and(b) }\n    )\n  }\n\n  private def createNode(name: String, labels: Seq[String]) = {\n    val primaryLabel = labels.head\n    val otherLabels = labels.tail\n    if (labels.isEmpty) {\n      Cypher.anyNode(name)\n    } else {\n      Cypher.node(primaryLabel, otherLabels.asJava).named(name)\n    }\n  }\n\n  override def createStatementForGDS(options: Neo4jOptions): String = {\n    val retCols = requiredColumns.map(column => getCorrectProperty(column, null))\n    // we need it in order to parse the field YIELD by the GDS procedure...\n    val (yieldFields, args) = Neo4jUtil.callSchemaService(\n      neo4j,\n      options,\n      jobId,\n      filters,\n      { ss => (ss.struct().fieldNames, ss.inputForGDSProc(options.query.value)) }\n    )\n\n    val cypherParams = args\n      .filter(t => {\n        if (!t._2) {\n          true\n        } else {\n          options.gdsMetadata.parameters.containsKey(t._1)\n        }\n      })\n      .map(_._1)\n      .map(Cypher.parameter)\n    val statement = Cypher.call(options.query.value)\n      .withArgs(cypherParams: _*)\n      .`yield`(yieldFields: _*)\n      .returning(retCols: _*)\n      .build()\n    renderer.render(statement)\n  }\n}\n\nobject Neo4jQueryStrategy {\n  val VARIABLE_EVENT = \"event\"\n  val VARIABLE_EVENTS = \"events\"\n  val VARIABLE_SCRIPT_RESULT = \"scriptResult\"\n  val VARIABLE_STREAM = \"stream\"\n}\n\nabstract class Neo4jQueryStrategy {\n\n  def createStatementForQuery(options: Neo4jOptions): String\n\n  def createStatementForRelationships(options: Neo4jOptions): String\n\n  def createStatementForNodes(options: Neo4jOptions): String\n\n  def createStatementForGDS(options: Neo4jOptions): String\n}\n\nclass Neo4jQueryService(private val options: Neo4jOptions, val strategy: Neo4jQueryStrategy) extends Serializable {\n\n  def createQuery(): String = options.query.queryType match {\n    case QueryType.LABELS       => strategy.createStatementForNodes(options)\n    case QueryType.RELATIONSHIP => strategy.createStatementForRelationships(options)\n    case QueryType.QUERY        => strategy.createStatementForQuery(options)\n    case QueryType.GDS          => strategy.createStatementForGDS(options)\n    case _ => throw new UnsupportedOperationException(\n        s\"\"\"Query Type not supported.\n           |You provided ${options.query.queryType},\n           |supported types: ${QueryType.values.mkString(\",\")}\"\"\".stripMargin\n      )\n  }\n}\n"
  },
  {
    "path": "common/src/main/scala/org/neo4j/spark/service/SchemaService.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark.service\n\nimport org.apache.commons.lang3.exception.ExceptionUtils\nimport org.apache.spark.internal.Logging\nimport org.apache.spark.sql.sources.Filter\nimport org.apache.spark.sql.types.DataTypes\nimport org.apache.spark.sql.types.StructField\nimport org.apache.spark.sql.types.StructType\nimport org.neo4j.caniuse.Neo4j\nimport org.neo4j.driver.Record\nimport org.neo4j.driver.Session\nimport org.neo4j.driver.Transaction\nimport org.neo4j.driver.TransactionWork\nimport org.neo4j.driver.Value\nimport org.neo4j.driver.Values\nimport org.neo4j.driver.exceptions.ClientException\nimport org.neo4j.driver.summary\nimport org.neo4j.spark.config.TopN\nimport org.neo4j.spark.converter.CypherToSparkTypeConverter\nimport org.neo4j.spark.converter.SparkToCypherTypeConverter\nimport org.neo4j.spark.cypher.CypherVersionSelector.selectCypherVersionClause\nimport org.neo4j.spark.service.SchemaService.normalizedClassName\nimport org.neo4j.spark.service.SchemaService.normalizedClassNameFromGraphEntity\nimport org.neo4j.spark.util.Neo4jImplicits.CypherImplicits\nimport org.neo4j.spark.util.Neo4jImplicits.ValueImplicits\nimport org.neo4j.spark.util.OptimizationType\nimport org.neo4j.spark.util._\n\nimport java.util\nimport java.util.Collections\nimport java.util.function\n\nimport scala.collection.JavaConverters._\nimport scala.collection.mutable\nimport scala.collection.mutable.ArrayBuffer\n\nobject PartitionPagination {\n  val EMPTY: PartitionPagination = PartitionPagination(0, -1, TopN(-1))\n}\n\ncase class PartitionPagination(partitionNumber: Int, skip: Long, topN: TopN)\n\nclass SchemaService(\n  private val neo4j: Neo4j,\n  private val options: Neo4jOptions,\n  private val driverCache: DriverCache,\n  private val filters: Array[Filter] = Array.empty\n) extends AutoCloseable with Logging {\n\n  private val queryReadStrategy = new Neo4jQueryReadStrategy(neo4j, filters)\n\n  private val session: Session = driverCache.getOrCreate().session(options.session.toNeo4jSession())\n\n  private val sessionTransactionConfig = options.toNeo4jTransactionConfig\n\n  private val cypherToSparkTypeConverter = CypherToSparkTypeConverter(options)\n\n  private val sparkToCypherTypeConverter = SparkToCypherTypeConverter(options)\n\n  private def structForNode(labels: Seq[String] = options.nodeMetadata.labels) = {\n    val structFields: mutable.Buffer[StructField] = (try {\n      val query =\n        s\"\"\"${selectCypherVersionClause(neo4j)}CALL apoc.meta.nodeTypeProperties($$config)\n           |YIELD propertyName, propertyTypes\n           |WITH DISTINCT propertyName, propertyTypes\n           |WITH propertyName, collect(propertyTypes) AS propertyTypes\n           |RETURN propertyName, reduce(acc = [], elem IN propertyTypes | acc + elem) AS propertyTypes\n           |\"\"\".stripMargin\n      val apocConfig = options.apocConfig.procedureConfigMap\n        .getOrElse(\"apoc.meta.nodeTypeProperties\", Map.empty[String, AnyRef])\n        .asInstanceOf[Map[String, AnyRef]] ++ Map[String, AnyRef](\"includeLabels\" -> labels.asJava)\n      retrieveSchemaFromApoc(query, Collections.singletonMap(\"config\", apocConfig.asJava))\n    } catch {\n      case e: ClientException =>\n        logResolutionChange(\"Switching to query schema resolution\", e)\n        // TODO get back to Cypher DSL when rand function will be available\n        val query =\n          s\"\"\"${selectCypherVersionClause(neo4j)}MATCH (${Neo4jUtil.NODE_ALIAS}:${labels.map(_.quote()).mkString(\":\")})\n             |RETURN ${Neo4jUtil.NODE_ALIAS}\n             |ORDER BY rand()\n             |LIMIT ${options.schemaMetadata.flattenLimit}\n             |\"\"\".stripMargin\n        val params = Collections.emptyMap[String, AnyRef]()\n        retrieveSchema(query, params, { record => record.get(Neo4jUtil.NODE_ALIAS).asNode.asMap.asScala.toMap })\n    })\n      .sortBy(t => t.name)\n\n    structFields += StructField(\n      Neo4jUtil.INTERNAL_LABELS_FIELD,\n      DataTypes.createArrayType(DataTypes.StringType),\n      nullable = true\n    )\n    structFields += StructField(Neo4jUtil.INTERNAL_ID_FIELD, DataTypes.LongType, nullable = false)\n    StructType(structFields.reverse.toSeq)\n  }\n\n  private def retrieveSchemaFromApoc(\n    query: String,\n    params: java.util.Map[String, AnyRef]\n  ): mutable.Buffer[StructField] = {\n    val fields = session.run(query, params, sessionTransactionConfig)\n      .list\n      .asScala\n      .filter(record => !record.get(\"propertyName\").isNull && !record.get(\"propertyName\").isEmpty)\n      .map(record => {\n        val fieldTypesList = record.get(\"propertyTypes\")\n          .asList(new function.Function[Value, String]() {\n            override def apply(v: Value): String = v.asString()\n          })\n          .asScala\n        val fieldType: String = if (fieldTypesList.size > 1) {\n          log.warn(\n            s\"\"\"\n               |The field ${record.get(\"propertyName\")} has different types: $fieldTypesList\n               |Every value will be casted to string.\n               |\"\"\".stripMargin\n          )\n          \"String\"\n        } else {\n          fieldTypesList.head\n        }\n\n        StructField(record.get(\"propertyName\").asString, cypherToSparkTypeConverter.convert(fieldType))\n      })\n    if (fields.isEmpty) {\n      throw new ClientException(\"Unable to compute the resulting schema from APOC\")\n    }\n    fields\n  }\n\n  private def retrieveSchema(\n    query: String,\n    params: java.util.Map[String, AnyRef],\n    extractFunction: Record => Map[String, AnyRef]\n  ): mutable.Buffer[StructField] = {\n    session.run(query, params, sessionTransactionConfig).list.asScala\n      .flatMap(extractFunction)\n      .groupBy(_._1)\n      .mapValues(_.map(_._2))\n      .map(t =>\n        options.schemaMetadata.strategy match {\n          case SchemaStrategy.SAMPLE => {\n            val types = t._2.map(value => {\n              if (options.query.queryType == QueryType.QUERY) {\n                normalizedClassName(value, options)\n              } else {\n                normalizedClassNameFromGraphEntity(value, options)\n              }\n            }).toSet\n\n            if (types.size > 1) {\n              log.warn(\n                s\"\"\"\n                   |The field ${t._1} has different types: ${types.toString}\n                   |Every value will be casted to string.\n                   |\"\"\".stripMargin\n              )\n              StructField(t._1, DataTypes.StringType)\n            } else {\n              val value = t._2.head\n              StructField(t._1, cypherToSparkTypeConverter.convert(types.head, value))\n            }\n          }\n          case SchemaStrategy.STRING => StructField(t._1, DataTypes.StringType)\n        }\n      )\n      .toBuffer\n  }\n\n  private def mapStructField(alias: String, field: StructField): StructField = {\n    val name = field.name match {\n      case Neo4jUtil.INTERNAL_ID_FIELD | Neo4jUtil.INTERNAL_LABELS_FIELD =>\n        s\"<$alias.${field.name.replaceAll(\"[<|>]\", \"\")}>\"\n      case _ => s\"$alias.${field.name}\"\n    }\n    StructField(name, field.dataType, field.nullable, field.metadata)\n  }\n\n  private def structForRelationship() = {\n    val structFields: mutable.Buffer[StructField] = ArrayBuffer(\n      StructField(Neo4jUtil.INTERNAL_REL_ID_FIELD, DataTypes.LongType, false),\n      StructField(Neo4jUtil.INTERNAL_REL_TYPE_FIELD, DataTypes.StringType, false)\n    )\n\n    if (options.relationshipMetadata.nodeMap) {\n      structFields += StructField(\n        s\"<${Neo4jUtil.RELATIONSHIP_SOURCE_ALIAS}>\",\n        DataTypes.createMapType(DataTypes.StringType, DataTypes.StringType),\n        false\n      )\n      structFields += StructField(\n        s\"<${Neo4jUtil.RELATIONSHIP_TARGET_ALIAS}>\",\n        DataTypes.createMapType(DataTypes.StringType, DataTypes.StringType),\n        false\n      )\n    } else {\n      structFields ++= structForNode(options.relationshipMetadata.source.labels)\n        .map(field => mapStructField(Neo4jUtil.RELATIONSHIP_SOURCE_ALIAS, field))\n      structFields ++= structForNode(options.relationshipMetadata.target.labels)\n        .map(field => mapStructField(Neo4jUtil.RELATIONSHIP_TARGET_ALIAS, field))\n    }\n\n    structFields ++= (try {\n      val query =\n        s\"\"\"${selectCypherVersionClause(\n            neo4j\n          )}CALL apoc.meta.relTypeProperties($$config) YIELD sourceNodeLabels, targetNodeLabels,\n           | propertyName, propertyTypes\n           |WITH *\n           |WHERE sourceNodeLabels = $$sourceLabels AND targetNodeLabels = $$targetLabels\n           |RETURN *\n           |\"\"\".stripMargin\n      val apocConfig = options.apocConfig.procedureConfigMap\n        .getOrElse(\"apoc.meta.relTypeProperties\", Map.empty[String, AnyRef])\n        .asInstanceOf[Map[String, AnyRef]]\n      val config = apocConfig ++ Map(\"includeRels\" -> Seq(options.relationshipMetadata.relationshipType).asJava)\n      val params = Map[String, AnyRef](\n        \"config\" -> config.asJava,\n        \"sourceLabels\" -> options.relationshipMetadata.source.labels.asJava,\n        \"targetLabels\" -> options.relationshipMetadata.target.labels.asJava\n      )\n        .asJava\n      retrieveSchemaFromApoc(query, params)\n    } catch {\n      case e: ClientException =>\n        logResolutionChange(\"Switching to query schema resolution\", e)\n        // TODO get back to Cypher DSL when rand function will be available\n        val query =\n          s\"\"\"${selectCypherVersionClause(\n              neo4j\n            )}MATCH (${Neo4jUtil.RELATIONSHIP_SOURCE_ALIAS}:${options.relationshipMetadata.source.labels.map(\n              _.quote()\n            ).mkString(\":\")})\n             |MATCH (${Neo4jUtil.RELATIONSHIP_TARGET_ALIAS}:${options.relationshipMetadata.target.labels.map(\n              _.quote()\n            ).mkString(\":\")})\n             |MATCH (${Neo4jUtil.RELATIONSHIP_SOURCE_ALIAS})-[${Neo4jUtil.RELATIONSHIP_ALIAS}:${options.relationshipMetadata.relationshipType}]->(${Neo4jUtil.RELATIONSHIP_TARGET_ALIAS})\n             |RETURN ${Neo4jUtil.RELATIONSHIP_ALIAS}\n             |ORDER BY rand()\n             |LIMIT ${options.schemaMetadata.flattenLimit}\n             |\"\"\".stripMargin\n        val params = Collections.emptyMap[String, AnyRef]()\n        retrieveSchema(\n          query,\n          params,\n          { record => record.get(Neo4jUtil.RELATIONSHIP_ALIAS).asRelationship.asMap.asScala.toMap }\n        )\n    })\n      .map(field => StructField(s\"rel.${field.name}\", field.dataType, field.nullable, field.metadata))\n      .sortBy(t => t.name)\n    StructType(structFields.toSeq)\n  }\n\n  private def structForQuery(): StructType = {\n    val query = queryReadStrategy.createStatementForQuery(options)\n    if (!isValidQuery(query, summary.QueryType.READ_ONLY)) {\n      return new StructType()\n    }\n\n    val params = Map[String, AnyRef](\n      Neo4jQueryStrategy.VARIABLE_SCRIPT_RESULT -> Collections.emptyList(),\n      Neo4jQueryStrategy.VARIABLE_STREAM -> Collections.emptyMap()\n    )\n      .asJava\n\n    val randLimitedQueryForSchema =\n      s\"\"\"\n         |$query\n         |ORDER BY rand()\n         |LIMIT ${options.schemaMetadata.flattenLimit}\n         |\"\"\".stripMargin\n    val randCallLimitedQueryForSchema =\n      s\"\"\"\n         |CALL {\n         |  $query\n         |} RETURN *\n         |ORDER BY rand()\n         |LIMIT ${options.schemaMetadata.flattenLimit}\n         |\"\"\".stripMargin\n\n    val limitedQuery =\n      if (isValidQuery(randLimitedQueryForSchema)) randLimitedQueryForSchema else randCallLimitedQueryForSchema\n\n    val structFields = retrieveSchema(limitedQuery, params, { record => record.asMap.asScala.toMap })\n\n    val columns = getReturnedColumns(query)\n    if (columns.isEmpty && structFields.isEmpty) {\n      throw new ClientException(\n        \"Unable to compute the resulting schema; this may mean your result set is empty or your version of Neo4j does not permit schema inference for empty sets\"\n      )\n    }\n\n    if (columns.isEmpty) {\n      return StructType(structFields.toSeq)\n    }\n\n    val sortedStructFields = if (structFields.isEmpty) {\n      // df: we arrived here because there are no data returned by the query\n      // so we want to return an empty dataset which schema is equals to the columns\n      // specified by the RETURN statement\n      columns.map(StructField(_, DataTypes.StringType))\n    } else {\n      try {\n        columns.map(column => structFields.find(_.name.quote() == column.quote()).orNull).filter(_ != null)\n      } catch {\n        case _: Throwable => structFields.toArray\n      }\n    }\n\n    StructType(sortedStructFields)\n  }\n\n  private def structForGDS() = {\n    val query =\n      s\"\"\"\n         |${selectCypherVersionClause(neo4j)}CALL gds.list() YIELD name, signature, type\n         |WHERE name = $$procName AND type = 'procedure'\n         |WITH split(signature, ') :: (')[1] AS fields\n         |WITH substring(fields, 0, size(fields) - 1) AS fields\n         |WITH split(fields, ',') AS fields\n         |WITH [field IN fields | split(field, ' :: ')] AS fields\n         |UNWIND fields AS field\n         |WITH field\n         |RETURN *\n         |\"\"\".stripMargin\n    val map: util.Map[String, AnyRef] = Map[String, AnyRef](\"procName\" -> options.query.value).asJava\n    val fields = session.run(query, map, sessionTransactionConfig).list.asScala\n      .map(r => r.get(\"field\").asList((t: Value) => t.asString()).asScala)\n      .map(r =>\n        (\n          r.head.trim,\n          r(1).replaceAll(\"\\\\?\", \"\") match {\n            case \"STRING\"                                                       => (\"String\", null)\n            case \"INTEGER\"                                                      => (\"Long\", null)\n            case \"FLOAT\" | \"NUMBER\"                                             => (\"Double\", null)\n            case \"DATETIME\"                                                     => (\"DateTime\", null)\n            case \"BOOLEAN\"                                                      => (\"Boolean\", null)\n            case \"LOCALTIME\"                                                    => (\"LocalTime\", null)\n            case \"LIST OF INTEGER\" | \"LIST<INTEGER>\" | \"LIST<INTEGER NOT NULL>\" => (\"LongArray\", null)\n            case \"LIST OF FLOAT\" | \"LIST<FLOAT>\" | \"LIST<FLOAT NOT NULL>\"       => (\"DoubleArray\", null)\n            case \"LIST OF STRING\" | \"LIST<STRING>\" | \"LIST<STRING NOT NULL>\"    => (\"StringArray\", null)\n            case \"MAP\" =>\n              logWarning(\n                s\"\"\"\n                   |For procedure ${options.query.value}\n                   |Neo4j return type MAP? of field ${r.head.trim} not fully supported.\n                   |We'll coerce it to a Map<String, String>\n                   |\"\"\".stripMargin\n              )\n              (\"Map\", Map(\"key\" -> \"\").asJava) // dummy value\n            case \"LIST OF MAP\" | \"LIST<MAP>\" | \"LIST<MAP NOT NULL>\" =>\n              logWarning(\n                s\"\"\"\n                   |For procedure ${options.query.value}\n                   |Neo4j return type LIST? OF MAP? of field ${r.head.trim} not fully supported.\n                   |We'll coerce it to a [Map<String, String>]\n                   |\"\"\".stripMargin\n              )\n              (\"MapArray\", Seq(Map(\"key\" -> \"\").asJava).asJava) // dummy value\n            case \"PATH\" => (\"Path\", null)\n            case _      => throw new IllegalArgumentException(s\"Neo4j type ${r(1)} not supported\")\n          }\n        )\n      )\n      .map(r => StructField(r._1, cypherToSparkTypeConverter.convert(r._2._1, r._2._2)))\n      .toSeq\n    StructType(fields)\n  }\n\n  def inputForGDSProc(procName: String): Seq[(String, Boolean)] = {\n    val query =\n      \"\"\"\n        |WITH $procName AS procName\n        |CALL gds.list() YIELD name, signature, type\n        |WHERE name = procName AND type = 'procedure'\n        |WITH replace(signature, procName + '(', '') AS signature\n        |WITH split(signature, ') :: (')[0] AS fields\n        |WITH substring(fields, 0, size(fields) - 1) AS fields\n        |WITH split(fields, ',') AS fields\n        |WITH [field IN fields | split(field, ' :: ')] AS fields\n        |UNWIND fields AS field\n        |WITH trim(split(field[0], ' = ')[0]) AS fieldName, field[0] contains ' = ' AS optional\n        |RETURN *\n        |\"\"\".stripMargin\n    val map: util.Map[String, AnyRef] = Map[String, AnyRef](\"procName\" -> procName).asJava\n    session.run(query, map, sessionTransactionConfig)\n      .list\n      .asScala\n      .map(r => (r.get(\"fieldName\").asString(), r.get(\"optional\").asBoolean()))\n      .toSeq\n  }\n\n  private def getReturnedColumns(query: String): Array[String] =\n    session.run(\"EXPLAIN \" + query, sessionTransactionConfig)\n      .keys().asScala.toArray\n\n  def struct(): StructType = {\n    val struct = options.query.queryType match {\n      case QueryType.LABELS       => structForNode()\n      case QueryType.RELATIONSHIP => structForRelationship()\n      case QueryType.QUERY        => structForQuery()\n      case QueryType.GDS          => structForGDS()\n    }\n\n    struct\n  }\n\n  def countForNodeWithQuery(filters: Array[Filter]): Long = {\n    val query = if (filters.isEmpty) {\n      options.nodeMetadata.labels\n        .map(_.quote())\n        .map(label =>\n          s\"\"\"\n             |MATCH (:$label)\n             |RETURN count(*) AS count\"\"\".stripMargin\n        )\n        .mkString(\" UNION ALL \")\n    } else {\n      queryReadStrategy.createStatementForNodeCount(options)\n    }\n    log.info(s\"Executing the following counting query on Neo4j: $query\")\n    session.readTransaction(\n      tx =>\n        tx.run(query, Values.value(Neo4jUtil.paramsFromFilters(filters).asJava))\n          .list()\n          .asScala\n          .map(_.get(\"count\"))\n          .map(count => if (count.isNull) 0L else count.asLong())\n          .min,\n      sessionTransactionConfig\n    )\n  }\n\n  def countForRelationshipWithQuery(filters: Array[Filter]): Long = {\n    val query = if (filters.isEmpty) {\n      val sourceQueries = options.relationshipMetadata.source.labels\n        .map(_.quote())\n        .map(label =>\n          s\"\"\"MATCH (:$label)-[${Neo4jUtil.RELATIONSHIP_ALIAS}:${options.relationshipMetadata.relationshipType.quote()}]->()\n             |RETURN count(${Neo4jUtil.RELATIONSHIP_ALIAS}) AS count\n             |\"\"\".stripMargin\n        )\n      val targetQueries = options.relationshipMetadata.target.labels\n        .map(_.quote())\n        .map(label =>\n          s\"\"\"MATCH ()-[${Neo4jUtil.RELATIONSHIP_ALIAS}:${options.relationshipMetadata.relationshipType.quote()}]->(:$label)\n             |RETURN count(${Neo4jUtil.RELATIONSHIP_ALIAS}) AS count\n             |\"\"\".stripMargin\n        )\n      (sourceQueries ++ targetQueries)\n        .mkString(\" UNION ALL \")\n    } else {\n      queryReadStrategy.createStatementForRelationshipCount(options)\n    }\n    log.info(s\"Executing the following counting query on Neo4j: $query\")\n    session.run(query, sessionTransactionConfig)\n      .list()\n      .asScala\n      .map(_.get(\"count\"))\n      .map(count => if (count.isNull) 0L else count.asLong())\n      .min\n  }\n\n  def countForNode(filters: Array[Filter]): Long =\n    try {\n      /*\n       * we try to leverage the count store in order to have the faster response possible\n       * https://neo4j.com/developer/kb/fast-counts-using-the-count-store/\n       * so in this scenario we have some limitations given the fact that we get the min\n       * for the sequence of counts returned\n       */\n      if (filters.isEmpty) {\n        val query = \"CALL apoc.meta.stats() yield labels RETURN labels\"\n        val map = session.run(query, sessionTransactionConfig).single()\n          .asMap()\n          .asScala\n          .get(\"labels\")\n          .getOrElse(Collections.emptyMap())\n          .asInstanceOf[util.Map[String, Long]].asScala\n        map.filterKeys(k => options.nodeMetadata.labels.contains(k))\n          .values.min\n      } else {\n        countForNodeWithQuery(filters)\n      }\n    } catch {\n      case e: ClientException => {\n        logResolutionChange(\"Switching to query count resolution\", e)\n        countForNodeWithQuery(filters)\n      }\n      case e: Throwable => logExceptionForCount(e)\n    }\n\n  def countForRelationship(filters: Array[Filter]): Long =\n    try {\n      if (filters.isEmpty) {\n        val query = \"CALL apoc.meta.stats() yield relTypes RETURN relTypes\"\n        val map = session.run(query, sessionTransactionConfig).single()\n          .asMap()\n          .asScala\n          .get(\"relTypes\")\n          .getOrElse(Collections.emptyMap())\n          .asInstanceOf[util.Map[String, Long]]\n          .asScala\n        val minFromSource = options.relationshipMetadata.source.labels\n          .map(_.quote())\n          .map(label =>\n            map.get(s\"(:$label)-[:${options.relationshipMetadata.relationshipType}]->()\").getOrElse(Long.MaxValue)\n          )\n          .min\n        val minFromTarget = options.relationshipMetadata.target.labels\n          .map(_.quote())\n          .map(label =>\n            map.get(s\"()-[:${options.relationshipMetadata.relationshipType}]->(:$label)\").getOrElse(Long.MaxValue)\n          )\n          .min\n        Math.min(minFromSource, minFromTarget)\n      } else {\n        countForRelationshipWithQuery(filters)\n      }\n    } catch {\n      case e: ClientException => {\n        logResolutionChange(\"Switching to query count resolution\", e)\n        countForRelationshipWithQuery(filters)\n      }\n      case e: Throwable => logExceptionForCount(e)\n    }\n\n  private def logExceptionForCount(e: Throwable): Long = {\n    log.error(\"Cannot compute the count because the following exception:\", e)\n    -1\n  }\n\n  def skipLimitFromPartition(topN: Option[TopN]): Seq[PartitionPagination] =\n    if (options.partitions == 1) {\n      val skipLimit = topN.map(top => PartitionPagination(0, 0, top)).getOrElse(PartitionPagination.EMPTY)\n      Seq(skipLimit)\n    } else {\n      val count: Long = this.count()\n      if (count <= 0) {\n        Seq(PartitionPagination.EMPTY)\n      } else {\n        val partitionSize = Math.ceil(count.toDouble / options.partitions).toLong\n        (0 until options.partitions)\n          .map(index => PartitionPagination(index, index * partitionSize, TopN(partitionSize)))\n      }\n    }\n\n  def count(filters: Array[Filter] = this.filters): Long = options.query.queryType match {\n    case QueryType.LABELS       => countForNode(filters)\n    case QueryType.RELATIONSHIP => countForRelationship(filters)\n    case QueryType.QUERY        => countForQuery()\n  }\n\n  private def countForQuery(): Long = {\n    val queryCount: String = options.queryMetadata.queryCount\n    if (Neo4jUtil.isLong(queryCount)) {\n      queryCount.trim.toLong\n    } else {\n      val query = if (queryCount.nonEmpty) {\n        options.queryMetadata.queryCount\n      } else {\n        s\"\"\"CALL { ${options.query.value} }\n           |RETURN count(*) AS count\n           |\"\"\".stripMargin\n      }\n      session.run(query, sessionTransactionConfig).single().get(\"count\").asLong()\n    }\n  }\n\n  def isGdsProcedure(procName: String): Boolean = {\n    val params: util.Map[String, AnyRef] = Map[String, AnyRef](\"procName\" -> procName).asJava\n    session.run(\n      \"\"\"\n        |CALL gds.list() YIELD name, type\n        |WHERE name = $procName AND type = 'procedure'\n        |RETURN count(*) = 1\n        |\"\"\".stripMargin,\n      params,\n      sessionTransactionConfig\n    )\n      .single()\n      .get(0)\n      .asBoolean()\n  }\n\n  def validateQuery(query: String, expectedQueryTypes: org.neo4j.driver.summary.QueryType*): String =\n    try {\n      val queryType = session.run(s\"EXPLAIN $query\", sessionTransactionConfig).consume().queryType()\n      if (expectedQueryTypes.isEmpty || expectedQueryTypes.contains(queryType)) {\n        \"\"\n      } else {\n        s\"Invalid query `${cleanQuery(query)}` because the accepted types are [${expectedQueryTypes.mkString(\", \")}], but the actual type is $queryType\"\n      }\n    } catch {\n      case e: Throwable => s\"Query not compiled for the following exception: ${ExceptionUtils.getMessage(e)}\"\n    }\n\n  private def cleanQuery(query: String) = {\n    query\n      .replace(\n        s\"WITH {} AS ${Neo4jQueryStrategy.VARIABLE_EVENT}, [] as ${Neo4jQueryStrategy.VARIABLE_SCRIPT_RESULT}\",\n        \"\"\n      )\n      .replace(s\"WITH [] as ${Neo4jQueryStrategy.VARIABLE_SCRIPT_RESULT}\", \"\")\n      .replace(s\"WITH {} AS ${Neo4jQueryStrategy.VARIABLE_EVENT}\", \"\")\n      .trim\n  }\n\n  def validateQueryCount(query: String): String =\n    try {\n      val resultSummary = session.run(s\"EXPLAIN $query\", sessionTransactionConfig).consume()\n      val queryType = resultSummary.queryType()\n      val plan = resultSummary.plan()\n      val expectedQueryTypes =\n        Set(org.neo4j.driver.summary.QueryType.READ_ONLY, org.neo4j.driver.summary.QueryType.SCHEMA_WRITE)\n      val isReadOnly = expectedQueryTypes.contains(queryType)\n      val hasCountIdentifier = plan.identifiers().asScala.toSet == Set(\"count\")\n      if (isReadOnly && hasCountIdentifier) {\n        \"\"\n      } else {\n        s\"Invalid query `${cleanQuery(query)}` because the expected type should be [${expectedQueryTypes.mkString(\", \")}], but the actual type is $queryType\"\n      }\n    } catch {\n      case e: Throwable => s\"Query count not compiled for the following exception: ${ExceptionUtils.getMessage(e)}\"\n    }\n\n  def isValidQuery(query: String, expectedQueryTypes: org.neo4j.driver.summary.QueryType*): Boolean =\n    try {\n      val queryType = session.run(s\"EXPLAIN $query\", sessionTransactionConfig).consume().queryType()\n      expectedQueryTypes.isEmpty || expectedQueryTypes.contains(queryType)\n    } catch {\n      case e: Throwable => {\n        if (log.isDebugEnabled) {\n          log.debug(\"Query not compiled because of the following exception:\", e)\n        }\n        false\n      }\n    }\n\n  @deprecated(\"use createEntityConstraint instead\")\n  private def createIndexOrConstraint(action: OptimizationType.Value, label: String, props: Seq[String]): Unit =\n    action match {\n      case OptimizationType.NONE => log.info(\"No optimization type provided\")\n      case _ => {\n        try {\n          val quotedLabel = label.quote()\n          val quotedProps = props\n            .map(prop => s\"${Neo4jUtil.NODE_ALIAS}.${prop.quote()}\")\n            .mkString(\", \")\n          val isNeo4j4 = neo4j.getVersion.getMajor == 4\n          val uniqueFieldName = if (!isNeo4j4) \"owningConstraint\" else \"uniqueness\"\n          val dashSeparatedProps = props.mkString(\"-\")\n          val (querySuffix, uniqueCondition) = action match {\n            case OptimizationType.INDEX => (\n                s\"FOR (${Neo4jUtil.NODE_ALIAS}:$quotedLabel) ON ($quotedProps)\",\n                if (!isNeo4j4) s\"$uniqueFieldName IS NULL\" else s\"$uniqueFieldName = 'NONUNIQUE'\"\n              )\n            case OptimizationType.NODE_CONSTRAINTS => {\n              val assertType = if (props.size > 1) \"NODE KEY\" else \"UNIQUE\"\n              (\n                s\"FOR (${Neo4jUtil.NODE_ALIAS}:$quotedLabel) REQUIRE ($quotedProps) IS $assertType\",\n                if (!isNeo4j4) s\"$uniqueFieldName IS NOT NULL\" else s\"$uniqueFieldName = 'UNIQUE'\"\n              )\n            }\n          }\n          val actionName = s\"spark_${action.toString}_${label}_$dashSeparatedProps\".quote()\n          val queryPrefix = action match {\n            case OptimizationType.INDEX            => s\"CREATE INDEX $actionName\"\n            case OptimizationType.NODE_CONSTRAINTS => s\"CREATE CONSTRAINT $actionName\"\n          }\n          val queryCheck =\n            s\"\"\"SHOW INDEXES YIELD labelsOrTypes, properties, $uniqueFieldName\n               |WHERE labelsOrTypes = ${'$'}labels\n               |AND properties = ${'$'}properties\n               |AND $uniqueCondition\n               |RETURN count(*) > 0 AS isPresent\"\"\".stripMargin\n          val params: util.Map[String, AnyRef] = Map(\n            \"labels\" -> Seq(label).asJava,\n            \"properties\" -> props.asJava\n          ).asJava.asInstanceOf[util.Map[String, AnyRef]]\n          val isPresent = session.run(queryCheck, params, sessionTransactionConfig)\n            .single()\n            .get(\"isPresent\")\n            .asBoolean()\n\n          val status = if (isPresent) {\n            \"KEPT\"\n          } else {\n            val query = s\"$queryPrefix $querySuffix\"\n            log.info(s\"Performing the following schema query: $query\")\n            session.run(query, sessionTransactionConfig)\n            \"CREATED\"\n          }\n          log.info(s\"Status for $action named with label $quotedLabel and props $quotedProps is: $status\")\n        } catch {\n          case e: Throwable => log.info(\"Cannot perform the optimization query because of the following exception:\", e)\n        }\n      }\n    }\n\n  private def createEntityConstraint(\n    entityType: String,\n    entityIdentifier: String,\n    constraintsOptimizationType: ConstraintsOptimizationType.Value,\n    keys: Map[String, String]\n  ): Unit = {\n    val constraintType = if (constraintsOptimizationType == ConstraintsOptimizationType.UNIQUE) {\n      \"UNIQUE\"\n    } else {\n      s\"$entityType KEY\"\n    }\n    val dashSeparatedProps = keys.values.mkString(\"-\")\n    val constraintName =\n      s\"spark_${entityType}_${constraintType.replace(s\"$entityType \", \"\")}-CONSTRAINT_${entityIdentifier}_$dashSeparatedProps\".quote()\n    val props = keys.values.map(_.quote()).map(\"e.\" + _).mkString(\", \")\n    val asciiRepresentation: String = createCypherPattern(entityType, entityIdentifier)\n    session.writeTransaction(\n      tx => {\n        tx.run(\n          s\"CREATE CONSTRAINT $constraintName IF NOT EXISTS FOR $asciiRepresentation REQUIRE ($props) IS $constraintType\"\n        )\n      },\n      sessionTransactionConfig\n    )\n  }\n\n  private def createCypherPattern(entityType: String, entityIdentifier: String) = {\n    val asciiRepresentation = entityType match {\n      case \"NODE\"         => s\"(e:${entityIdentifier.quote()})\"\n      case \"RELATIONSHIP\" => s\"()-[e:${entityIdentifier.quote()}]->()\"\n      case _              => throw new IllegalArgumentException(s\"$entityType not supported\")\n    }\n    asciiRepresentation\n  }\n\n  private def createEntityTypeConstraint(\n    entityType: String,\n    entityIdentifier: String,\n    properties: Map[String, String],\n    struct: StructType,\n    constraints: Set[SchemaConstraintsOptimizationType.Value]\n  ): Unit = {\n    val asciiRepresentation: String = createCypherPattern(entityType, entityIdentifier)\n    session.writeTransaction(\n      tx => {\n        properties\n          .filter(t => struct.exists(f => f.name == t._1))\n          .map(t => {\n            val field = struct.find(f => f.name == t._1).get\n            (t._2, sparkToCypherTypeConverter.convert(field.dataType), field.nullable)\n          })\n          .foreach(t => {\n            val prop = t._1.quote()\n            val cypherType = t._2\n            val isNullable = t._3\n            if (constraints.contains(SchemaConstraintsOptimizationType.TYPE)) {\n              val typeConstraintName = s\"spark_$entityType-TYPE-CONSTRAINT-$entityIdentifier-$prop\".quote()\n              tx.run(\n                s\"CREATE CONSTRAINT $typeConstraintName IF NOT EXISTS FOR $asciiRepresentation REQUIRE e.$prop IS :: $cypherType\"\n              ).consume()\n            }\n            if (constraints.contains(SchemaConstraintsOptimizationType.EXISTS)) {\n              if (!isNullable) {\n                val notNullConstraintName = s\"spark_$entityType-NOT_NULL-CONSTRAINT-$entityIdentifier-$prop\".quote()\n                tx.run(\n                  s\"CREATE CONSTRAINT $notNullConstraintName IF NOT EXISTS FOR $asciiRepresentation REQUIRE e.$prop IS NOT NULL\"\n                ).consume()\n              }\n            }\n          })\n      },\n      sessionTransactionConfig\n    )\n  }\n\n  private def createOptimizationsForNode(struct: StructType): Unit = {\n    val schemaMetadata = options.schemaMetadata.optimization\n    if (\n      schemaMetadata.nodeConstraint != ConstraintsOptimizationType.NONE\n      || schemaMetadata.schemaConstraints != Set(SchemaConstraintsOptimizationType.NONE)\n    ) {\n      if (schemaMetadata.nodeConstraint != ConstraintsOptimizationType.NONE) {\n        createEntityConstraint(\n          \"NODE\",\n          options.nodeMetadata.labels.head,\n          schemaMetadata.nodeConstraint,\n          options.nodeMetadata.nodeKeys\n        )\n      }\n      if (schemaMetadata.schemaConstraints.nonEmpty) {\n        val propsFromStruct: Map[String, String] = struct\n          .map(f => (f.name, f.name))\n          .toMap\n        val propsFromMeta: Map[String, String] = options.nodeMetadata.nodeKeys ++ options.nodeMetadata.properties\n        createEntityTypeConstraint(\n          \"NODE\",\n          options.nodeMetadata.labels.head,\n          propsFromStruct ++ propsFromMeta,\n          struct,\n          schemaMetadata.schemaConstraints\n        )\n      }\n    } else { // TODO old behaviour, remove it in the future\n      options.schemaMetadata.optimizationType match {\n        case OptimizationType.INDEX | OptimizationType.NODE_CONSTRAINTS => {\n          createIndexOrConstraint(\n            options.schemaMetadata.optimizationType,\n            options.nodeMetadata.labels.head,\n            options.nodeMetadata.nodeKeys.values.toSeq\n          )\n        }\n        case _ => // do nothing\n      }\n    }\n  }\n\n  private def createOptimizationsForRelationship(struct: StructType): Unit = {\n    val schemaMetadata = options.schemaMetadata.optimization\n    if (\n      schemaMetadata.nodeConstraint != ConstraintsOptimizationType.NONE\n      || schemaMetadata.relConstraint != ConstraintsOptimizationType.NONE\n      || schemaMetadata.schemaConstraints != Set(SchemaConstraintsOptimizationType.NONE)\n    ) {\n      if (schemaMetadata.nodeConstraint != ConstraintsOptimizationType.NONE) {\n        createEntityConstraint(\n          \"NODE\",\n          options.relationshipMetadata.source.labels.head,\n          schemaMetadata.nodeConstraint,\n          options.relationshipMetadata.source.nodeKeys\n        )\n        createEntityConstraint(\n          \"NODE\",\n          options.relationshipMetadata.target.labels.head,\n          schemaMetadata.nodeConstraint,\n          options.relationshipMetadata.target.nodeKeys\n        )\n      }\n      if (schemaMetadata.relConstraint != ConstraintsOptimizationType.NONE) {\n        createEntityConstraint(\n          \"RELATIONSHIP\",\n          options.relationshipMetadata.relationshipType,\n          schemaMetadata.relConstraint,\n          options.relationshipMetadata.relationshipKeys\n        )\n      }\n      if (schemaMetadata.schemaConstraints.nonEmpty) {\n        val sourceNodeProps: Map[String, String] =\n          options.relationshipMetadata.source.nodeKeys ++ options.relationshipMetadata.source.properties\n        val targetNodeProps: Map[String, String] =\n          options.relationshipMetadata.target.nodeKeys ++ options.relationshipMetadata.target.properties\n        val allNodeProps: Map[String, String] = sourceNodeProps ++ targetNodeProps\n        val relStruct: StructType = StructType(struct.filterNot(f => allNodeProps.contains(f.name)))\n        val propsFromRelStruct: Map[String, String] = relStruct\n          .map(f => (f.name, f.name))\n          .toMap\n        val propsFromMeta: Map[String, String] =\n          options.relationshipMetadata.relationshipKeys ++ options.relationshipMetadata.properties.getOrElse(Map.empty)\n        createEntityTypeConstraint(\n          \"RELATIONSHIP\",\n          options.relationshipMetadata.relationshipType,\n          propsFromRelStruct ++ propsFromMeta,\n          struct,\n          schemaMetadata.schemaConstraints\n        )\n        createEntityTypeConstraint(\n          \"NODE\",\n          options.relationshipMetadata.source.labels.head,\n          sourceNodeProps,\n          struct,\n          schemaMetadata.schemaConstraints\n        )\n        createEntityTypeConstraint(\n          \"NODE\",\n          options.relationshipMetadata.target.labels.head,\n          targetNodeProps,\n          struct,\n          schemaMetadata.schemaConstraints\n        )\n      }\n    } else { // TODO old behaviour, remove it in the future\n      options.schemaMetadata.optimizationType match {\n        case OptimizationType.INDEX | OptimizationType.NODE_CONSTRAINTS => {\n          createIndexOrConstraint(\n            options.schemaMetadata.optimizationType,\n            options.relationshipMetadata.source.labels.head,\n            options.relationshipMetadata.source.nodeKeys.values.toSeq\n          )\n          createIndexOrConstraint(\n            options.schemaMetadata.optimizationType,\n            options.relationshipMetadata.target.labels.head,\n            options.relationshipMetadata.target.nodeKeys.values.toSeq\n          )\n        }\n        case _ => // do nothing\n      }\n    }\n  }\n\n  def createOptimizations(struct: StructType): Unit = {\n    Validations.validate(ValidateSchemaOptions(options, struct))\n    options.query.queryType match {\n      case QueryType.LABELS       => createOptimizationsForNode(struct)\n      case QueryType.RELATIONSHIP => createOptimizationsForRelationship(struct)\n      case _                      => // do nothing\n    }\n  }\n\n  def execute(queries: Seq[String]): util.List[util.Map[String, AnyRef]] = {\n    val queryMap = queries\n      .map(query => {\n        (session.run(s\"EXPLAIN $query\", sessionTransactionConfig).consume().queryType(), query)\n      })\n      .groupBy(_._1)\n      .mapValues(_.map(_._2))\n    val schemaQueries = queryMap.getOrElse(org.neo4j.driver.summary.QueryType.SCHEMA_WRITE, Seq.empty[String])\n    schemaQueries.foreach(session.run(_, sessionTransactionConfig))\n    val others = queryMap\n      .filterKeys(key => key != org.neo4j.driver.summary.QueryType.SCHEMA_WRITE)\n      .values\n      .flatten\n      .toSeq\n    if (others.isEmpty) {\n      Collections.emptyList()\n    } else {\n      session\n        .writeTransaction(\n          new TransactionWork[util.List[java.util.Map[String, AnyRef]]] {\n            override def execute(transaction: Transaction): util.List[util.Map[String, AnyRef]] = {\n              others.size match {\n                case 1 => transaction.run(others.head).list()\n                    .asScala\n                    .map(_.asMap())\n                    .asJava\n                case _ => {\n                  others\n                    .slice(0, queries.size - 1)\n                    .foreach(transaction.run)\n                  val result = transaction.run(others.last).list()\n                    .asScala\n                    .map(_.asMap())\n                    .asJava\n                  result\n                }\n              }\n            }\n          },\n          sessionTransactionConfig\n        )\n    }\n  }\n\n  def lastOffset(): Option[Long] = options.query.queryType match {\n    case QueryType.LABELS       => lastOffsetForNode()\n    case QueryType.RELATIONSHIP => lastOffsetForRelationship()\n    case QueryType.QUERY        => lastOffsetForQuery()\n  }\n\n  private def lastOffsetForNode(): Option[Long] = {\n    val label = options.nodeMetadata.labels.head\n    session.run(\n      s\"\"\"MATCH (n:$label)\n         |RETURN max(n.${options.streamingOptions.propertyName}) AS ${options.streamingOptions.propertyName}\"\"\".stripMargin,\n      sessionTransactionConfig\n    )\n      .single()\n      .get(options.streamingOptions.propertyName)\n      .asOptionalLong()\n  }\n\n  private def lastOffsetForRelationship(): Option[Long] = {\n    val sourceLabel = options.relationshipMetadata.source.labels.head.quote()\n    val targetLabel = options.relationshipMetadata.target.labels.head.quote()\n    val relType = options.relationshipMetadata.relationshipType.quote()\n\n    session.run(\n      s\"\"\"MATCH (s:$sourceLabel)-[r:$relType]->(t:$targetLabel)\n         |RETURN max(r.${options.streamingOptions.propertyName}) AS ${options.streamingOptions.propertyName}\"\"\".stripMargin,\n      sessionTransactionConfig\n    )\n      .single()\n      .get(options.streamingOptions.propertyName)\n      .asOptionalLong()\n  }\n\n  private def lastOffsetForQuery(): Option[Long] = {\n    session.run(options.streamingOptions.queryOffset, sessionTransactionConfig)\n      .single()\n      .get(0)\n      .asOptionalLong()\n  }\n\n  private def logResolutionChange(message: String, e: ClientException): Unit = {\n    log.warn(message)\n    if (!e.code().equals(\"Neo.ClientError.Procedure.ProcedureNotFound\")) {\n      log.warn(s\"For the following exception\", e)\n    }\n  }\n\n  override def close(): Unit = {\n    Neo4jUtil.closeSafely(session, log)\n  }\n\n}\n\nobject SchemaService {\n  val POINT_TYPE_2D = \"point-2d\"\n  val POINT_TYPE_3D = \"point-3d\"\n\n  val TIME_TYPE_OFFSET = \"offset-time\"\n  val TIME_TYPE_LOCAL = \"local-time\"\n\n  val DURATION_TYPE = \"duration\"\n\n  def normalizedClassName(value: AnyRef, options: Neo4jOptions): String = value match {\n    case binary: Array[Byte] => if (options.legacyTypeConversionEnabled) value.getClass.getSimpleName else \"ByteArray\"\n    case list: java.util.List[_]       => \"Array\"\n    case map: java.util.Map[String, _] => \"Map\"\n    case null                          => \"String\"\n    case _                             => value.getClass.getSimpleName\n  }\n\n  // from nodes and relationships we cannot have maps as properties and elements in lists are the same type\n  // special treatment for ByteArray required (pattern matching on Array != List)\n  def normalizedClassNameFromGraphEntity(value: AnyRef, options: Neo4jOptions): String = value match {\n    case binary: Array[Byte] => if (options.legacyTypeConversionEnabled) value.getClass.getSimpleName else \"ByteArray\"\n    case list: java.util.List[_] => s\"${list.get(0).getClass.getSimpleName}Array\"\n    case null                    => \"String\"\n    case _                       => value.getClass.getSimpleName\n  }\n}\n"
  },
  {
    "path": "common/src/main/scala/org/neo4j/spark/streaming/BaseStreamingPartitionReader.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark.streaming\n\nimport org.apache.spark.sql.connector.expressions.aggregate.AggregateFunc\nimport org.apache.spark.sql.sources.Filter\nimport org.apache.spark.sql.sources.GreaterThan\nimport org.apache.spark.sql.sources.LessThanOrEqual\nimport org.apache.spark.sql.types.StructType\nimport org.neo4j.caniuse.Neo4j\nimport org.neo4j.cypherdsl.core.Cypher\nimport org.neo4j.spark.reader.BasePartitionReader\nimport org.neo4j.spark.service.Neo4jQueryStrategy\nimport org.neo4j.spark.service.PartitionPagination\nimport org.neo4j.spark.streaming.BaseStreamingPartitionReader.offsetUsagePatterns\nimport org.neo4j.spark.util.Neo4jImplicits._\nimport org.neo4j.spark.util.Neo4jOptions\nimport org.neo4j.spark.util.Neo4jUtil\nimport org.neo4j.spark.util.QueryType._\nimport org.neo4j.spark.util.StreamingFrom\n\nimport java.util\nimport java.util.function.Predicate\nimport java.util.regex.Pattern\n\nimport scala.collection.JavaConverters.mapAsJavaMapConverter\n\nclass BaseStreamingPartitionReader(\n  private val neo4j: Neo4j,\n  private val options: Neo4jOptions,\n  private val filters: Array[Filter],\n  private val schema: StructType,\n  private val jobId: String,\n  private val partitionSkipLimit: PartitionPagination,\n  private val scriptResult: java.util.List[java.util.Map[String, AnyRef]],\n  private val requiredColumns: StructType,\n  private val aggregateColumns: Array[AggregateFunc]\n) extends BasePartitionReader(\n      neo4j,\n      options,\n      filters,\n      schema,\n      jobId,\n      partitionSkipLimit,\n      scriptResult,\n      requiredColumns,\n      aggregateColumns\n    ) {\n\n  private val streamingPropertyName = Neo4jUtil.getStreamingPropertyName(options)\n\n  private val streamStart =\n    filters.find(f => f.getAttribute.contains(streamingPropertyName) && f.isInstanceOf[GreaterThan])\n\n  private val streamEnd =\n    filters.find(f => f.getAttribute.contains(streamingPropertyName) && f.isInstanceOf[LessThanOrEqual])\n\n  logInfo(s\"Creating Streaming Partition reader $name\")\n\n  private lazy val values = {\n    val map = new util.HashMap[String, Any](super.queryParameters)\n    val start: Long = streamStart\n      .flatMap(f => f.getValue)\n      .getOrElse(StreamingFrom.ALL.value())\n      .asInstanceOf[Long]\n    val end: Long = streamEnd\n      .flatMap(f => f.getValue)\n      .get\n      .asInstanceOf[Long]\n    map.put(Neo4jQueryStrategy.VARIABLE_STREAM, Map(\"offset\" -> start, \"from\" -> start, \"to\" -> end).asJava)\n    map\n  }\n\n  override def close(): Unit = {\n    logInfo(s\"Closing Partition reader $name ${if (hasError()) \"with error \" else \"\"}\")\n    super.close()\n  }\n\n  override protected def query(): String = {\n    options.query.queryType match {\n      case QUERY =>\n        val originalQuery = super.query()\n\n        if (offsetUsagePatterns.exists(_.test(originalQuery))) {\n          logWarning(\n            \"Usage of '$stream.offset' is deprecated in favor of '$stream.from' and '$stream.to' parameters which \"\n              + \"describes the range of changes the micro batch refers to. Please update your queries accordingly.\"\n          )\n        }\n\n        val property = Cypher.name(streamingPropertyName)\n        val stream = Cypher.parameter(\"stream\")\n\n        // rewrite query for adding $stream.from and $stream.to filters\n        Cypher.callRawCypher(originalQuery)\n          .`with`(Cypher.asterisk())\n          .where(\n            property.gt(stream.property(\"from\")).and(property.lte(stream.property(\"to\")))\n          )\n          .returning(Cypher.asterisk())\n          .build()\n          .getCypher\n      // we don't need to rewrite the queries for LABELS and RELATIONSHIPS because spark filters already cover our\n      // criteria which are added to the query text in Neo4jQueryService\n      case LABELS       => super.query()\n      case RELATIONSHIP => super.query()\n      case GDS =>\n        throw new UnsupportedOperationException(\"GDS strategy is not supported in structured streaming use cases.\")\n    }\n  }\n\n  override protected def queryParameters: util.Map[String, Any] = values\n\n}\n\nobject BaseStreamingPartitionReader {\n\n  private val offsetUsagePatterns: Seq[Predicate[String]] = Seq(\n    Pattern.compile(\"\\\\$stream\\\\.offset\").asPredicate(),\n    Pattern.compile(\"\\\\$`stream`\\\\.offset\").asPredicate(),\n    Pattern.compile(\"\\\\$stream\\\\.`offset`\").asPredicate(),\n    Pattern.compile(\"\\\\$`stream`\\\\.`offset`\").asPredicate()\n  )\n\n}\n"
  },
  {
    "path": "common/src/main/scala/org/neo4j/spark/util/DriverCache.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark.util\n\nimport org.neo4j.driver.Driver\nimport org.neo4j.spark.util.DriverCache.cache\n\nimport java.util.concurrent.ConcurrentHashMap\nimport java.util.concurrent.atomic.AtomicInteger\n\nobject DriverCache {\n\n  private val cache: ConcurrentHashMap[Neo4jDriverOptions, (Driver, AtomicInteger)] =\n    new ConcurrentHashMap[Neo4jDriverOptions, (Driver, AtomicInteger)]\n}\n\nclass DriverCache(private val options: Neo4jDriverOptions) extends Serializable\n    with AutoCloseable {\n\n  def getOrCreate(): Driver = {\n    val (driver, counter) =\n      cache.computeIfAbsent(options, (t: Neo4jDriverOptions) => (t.createDriver(), new AtomicInteger(0)))\n    counter.incrementAndGet()\n    driver\n  }\n\n  def close(): Unit = {\n    val (driver, counter) = cache.get(options)\n    if (counter.decrementAndGet() == 0) {\n      cache.remove(options)\n      Neo4jUtil.closeSafely(driver)\n    }\n  }\n}\n"
  },
  {
    "path": "common/src/main/scala/org/neo4j/spark/util/Neo4jImplicits.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark.util\n\nimport com.fasterxml.jackson.core.JsonParseException\nimport com.fasterxml.jackson.core.JsonParser\nimport com.fasterxml.jackson.databind.ObjectMapper\nimport org.apache.spark.sql.connector.expressions.Expression\nimport org.apache.spark.sql.connector.expressions.Literal\nimport org.apache.spark.sql.connector.expressions.aggregate.Aggregation\nimport org.apache.spark.sql.connector.expressions.filter\nimport org.apache.spark.sql.connector.expressions.filter.Predicate\nimport org.apache.spark.sql.sources.AlwaysFalse\nimport org.apache.spark.sql.sources.AlwaysTrue\nimport org.apache.spark.sql.sources.And\nimport org.apache.spark.sql.sources.EqualNullSafe\nimport org.apache.spark.sql.sources.EqualTo\nimport org.apache.spark.sql.sources.Filter\nimport org.apache.spark.sql.sources.GreaterThan\nimport org.apache.spark.sql.sources.GreaterThanOrEqual\nimport org.apache.spark.sql.sources.In\nimport org.apache.spark.sql.sources.IsNotNull\nimport org.apache.spark.sql.sources.IsNull\nimport org.apache.spark.sql.sources.LessThan\nimport org.apache.spark.sql.sources.LessThanOrEqual\nimport org.apache.spark.sql.sources.Not\nimport org.apache.spark.sql.sources.Or\nimport org.apache.spark.sql.sources.StringContains\nimport org.apache.spark.sql.sources.StringEndsWith\nimport org.apache.spark.sql.sources.StringStartsWith\nimport org.apache.spark.sql.types.DataTypes\nimport org.apache.spark.sql.types.MapType\nimport org.apache.spark.sql.types.StructField\nimport org.apache.spark.sql.types.StructType\nimport org.neo4j.driver.Value\nimport org.neo4j.driver.types.Entity\nimport org.neo4j.driver.types.Node\nimport org.neo4j.driver.types.Relationship\nimport org.neo4j.spark.converter.CypherToSparkTypeConverter\nimport org.neo4j.spark.converter.SparkToNeo4jDataConverter\nimport org.neo4j.spark.service.SchemaService\n\nimport scala.collection.JavaConverters._\n\nimport javax.lang.model.SourceVersion\n\nobject Neo4jImplicits {\n\n  implicit class CypherImplicits(str: String) {\n    private def isValidCypherIdentifier() = SourceVersion.isIdentifier(str) && !str.trim.startsWith(\"$\")\n\n    def quote(): String = if (!isValidCypherIdentifier() && !str.isQuoted()) s\"`$str`\" else str\n\n    def unquote(): String = str.replaceAll(\"`\", \"\");\n\n    def isQuoted(): Boolean = str.startsWith(\"`\");\n\n    def removeAlias(): String = {\n      val splatString = str.unquote().split('.')\n\n      if (splatString.size > 1) {\n        splatString.tail.mkString(\".\")\n      } else {\n        str\n      }\n    }\n\n    /**\n     * df: we need this to handle scenarios like `WHERE age > 19 and age < 22`,\n     * so we can't basically add a parameter named \\$age.\n     * So we base64 encode the value to ensure a unique parameter name\n     */\n    def toParameterName(value: Any): String = {\n      val attributeValue = if (value == null) {\n        \"NULL\"\n      } else {\n        value.toString\n      }\n\n      val base64ed = java.util.Base64.getEncoder.encodeToString(attributeValue.getBytes())\n\n      s\"${base64ed}_${str.unquote()}\".quote()\n    }\n  }\n\n  implicit class EntityImplicits(entity: Entity) {\n\n    def toStruct(options: Neo4jOptions): StructType = {\n      val fields = entity.asMap().asScala\n        .groupBy(_._1)\n        .map(t => {\n          val value = t._2.head._2\n          val cypherType = SchemaService.normalizedClassNameFromGraphEntity(value, options)\n          StructField(t._1, CypherToSparkTypeConverter(options).convert(cypherType))\n        })\n      val entityFields = entity match {\n        case _: Node => {\n          Seq(\n            StructField(Neo4jUtil.INTERNAL_ID_FIELD, DataTypes.LongType, nullable = false),\n            StructField(\n              Neo4jUtil.INTERNAL_LABELS_FIELD,\n              DataTypes.createArrayType(DataTypes.StringType),\n              nullable = true\n            )\n          )\n        }\n        case _: Relationship => {\n          Seq(\n            StructField(Neo4jUtil.INTERNAL_REL_ID_FIELD, DataTypes.LongType, nullable = false),\n            StructField(Neo4jUtil.INTERNAL_REL_TYPE_FIELD, DataTypes.StringType, nullable = false),\n            StructField(Neo4jUtil.INTERNAL_REL_SOURCE_ID_FIELD, DataTypes.LongType, nullable = false),\n            StructField(Neo4jUtil.INTERNAL_REL_TARGET_ID_FIELD, DataTypes.LongType, nullable = false)\n          )\n        }\n      }\n\n      StructType(entityFields ++ fields)\n    }\n\n    def toMap: java.util.Map[String, Any] = {\n      val entityMap = entity.asMap().asScala\n      val entityFields = entity match {\n        case node: Node => {\n          Map(Neo4jUtil.INTERNAL_ID_FIELD -> node.id(), Neo4jUtil.INTERNAL_LABELS_FIELD -> node.labels())\n        }\n        case relationship: Relationship => {\n          Map(\n            Neo4jUtil.INTERNAL_REL_ID_FIELD -> relationship.id(),\n            Neo4jUtil.INTERNAL_REL_TYPE_FIELD -> relationship.`type`(),\n            Neo4jUtil.INTERNAL_REL_SOURCE_ID_FIELD -> relationship.startNodeId(),\n            Neo4jUtil.INTERNAL_REL_TARGET_ID_FIELD -> relationship.endNodeId()\n          )\n        }\n      }\n      (entityFields ++ entityMap).asJava\n    }\n  }\n\n  implicit class PredicateImplicit(predicate: Predicate) {\n\n    def toFilter(options: Neo4jOptions): Option[Filter] = {\n      predicate.name() match {\n        case \"IS_NULL\"     => Some(IsNull(predicate.rawAttributeName()))\n        case \"IS_NOT_NULL\" => Some(IsNotNull(predicate.rawAttributeName()))\n        case \"STARTS_WITH\" =>\n          predicate.rawLiteralValue(options).map(lit => StringStartsWith(predicate.rawAttributeName(), lit.asString()))\n        case \"ENDS_WITH\" =>\n          predicate.rawLiteralValue(options).map(lit => StringEndsWith(predicate.rawAttributeName(), lit.asString()))\n        case \"CONTAINS\" =>\n          predicate.rawLiteralValue(options).map(lit => StringContains(predicate.rawAttributeName(), lit.asString()))\n        case \"IN\" => Some(In(predicate.rawAttributeName(), predicate.rawLiteralValues(options)))\n        case \"=\" => predicate.rawLiteralValue(options).map(lit => EqualTo(predicate.rawAttributeName(), lit.asObject()))\n        case \"<>\" =>\n          predicate.rawLiteralValue(options).map(lit => Not(EqualTo(predicate.rawAttributeName(), lit.asObject())))\n        case \"<=>\" =>\n          predicate.rawLiteralValue(options).map(lit => EqualNullSafe(predicate.rawAttributeName(), lit.asObject()))\n        case \"<\" =>\n          predicate.rawLiteralValue(options).map(lit => LessThan(predicate.rawAttributeName(), lit.asObject()))\n        case \"<=\" =>\n          predicate.rawLiteralValue(options).map(lit => LessThanOrEqual(predicate.rawAttributeName(), lit.asObject()))\n        case \">\" =>\n          predicate.rawLiteralValue(options).map(lit => GreaterThan(predicate.rawAttributeName(), lit.asObject()))\n        case \">=\" =>\n          predicate.rawLiteralValue(options).map(lit =>\n            GreaterThanOrEqual(predicate.rawAttributeName(), lit.asObject())\n          )\n        case \"AND\" =>\n          val andPredicate = predicate.asInstanceOf[filter.And]\n          (andPredicate.left().toFilter(options), andPredicate.right().toFilter(options)) match {\n            case (_, None)                 => None\n            case (None, _)                 => None\n            case (Some(left), Some(right)) => Some(And(left, right))\n          }\n        case \"OR\" =>\n          val andPredicate = predicate.asInstanceOf[filter.Or]\n          (andPredicate.left().toFilter(options), andPredicate.right().toFilter(options)) match {\n            case (_, None)                 => None\n            case (None, _)                 => None\n            case (Some(left), Some(right)) => Some(Or(left, right))\n          }\n        case \"NOT\" =>\n          val notPredicate = predicate.asInstanceOf[filter.Not]\n          notPredicate.child().toFilter(options).map(Not)\n        case \"ALWAYS_TRUE\"  => Some(AlwaysTrue)\n        case \"ALWAYS_FALSE\" => Some(AlwaysFalse)\n      }\n    }\n\n    def rawAttributeName(): String = {\n      predicate.references().head.fieldNames().mkString(\".\")\n    }\n\n    def rawLiteralValue(options: Neo4jOptions): Option[Value] = {\n      predicate.children()\n        .filter(_.isInstanceOf[Literal[_]])\n        .map(_.asInstanceOf[Literal[_]])\n        .headOption\n        .map(literal => SparkToNeo4jDataConverter(options).convert(literal.value(), literal.dataType()))\n    }\n\n    def rawLiteralValues(options: Neo4jOptions): Array[Any] = {\n      predicate.children()\n        .filter(_.isInstanceOf[Literal[_]])\n        .map(_.asInstanceOf[Literal[_]])\n        .map(v => SparkToNeo4jDataConverter(options).convert(v.value(), v.dataType()).asObject())\n    }\n  }\n\n  implicit class FilterImplicit(filter: Filter) {\n\n    def flattenFilters: Array[Filter] = {\n      filter match {\n        case or: Or    => Array(or.left.flattenFilters, or.right.flattenFilters).flatten\n        case and: And  => Array(and.left.flattenFilters, and.right.flattenFilters).flatten\n        case f: Filter => Array(f)\n      }\n    }\n\n    def getAttribute: Option[String] = Option(filter match {\n      case eqns: EqualNullSafe         => eqns.attribute\n      case eq: EqualTo                 => eq.attribute\n      case gt: GreaterThan             => gt.attribute\n      case gte: GreaterThanOrEqual     => gte.attribute\n      case lt: LessThan                => lt.attribute\n      case lte: LessThanOrEqual        => lte.attribute\n      case in: In                      => in.attribute\n      case notNull: IsNotNull          => notNull.attribute\n      case isNull: IsNull              => isNull.attribute\n      case startWith: StringStartsWith => startWith.attribute\n      case endsWith: StringEndsWith    => endsWith.attribute\n      case contains: StringContains    => contains.attribute\n      case not: Not                    => not.child.getAttribute.orNull\n      case _                           => null\n    })\n\n    def getValue: Option[Any] = Option(filter match {\n      case eqns: EqualNullSafe         => eqns.value\n      case eq: EqualTo                 => eq.value\n      case gt: GreaterThan             => gt.value\n      case gte: GreaterThanOrEqual     => gte.value\n      case lt: LessThan                => lt.value\n      case lte: LessThanOrEqual        => lte.value\n      case in: In                      => in.values\n      case startWith: StringStartsWith => startWith.value\n      case endsWith: StringEndsWith    => endsWith.value\n      case contains: StringContains    => contains.value\n      case not: Not                    => not.child.getValue.orNull\n      case _                           => null\n    })\n\n    def isAttribute(entityType: String): Boolean = {\n      getAttribute.exists(_.contains(s\"$entityType.\"))\n    }\n\n    def getAttributeWithoutEntityName: Option[String] =\n      filter.getAttribute.map(_.unquote().split('.').tail.mkString(\".\"))\n\n    /**\n     * df: we are not handling AND/OR because they are not actually filters\n     * and have a different internal structure. Before calling this function on the filters\n     * it's highly suggested FilterImplicit::flattenFilter() which returns a collection\n     * of filters, including the one contained in the ANDs/ORs objects.\n     */\n    def getAttributeAndValue: Seq[Any] = {\n      filter match {\n        case f: EqualNullSafe      => Seq(f.attribute.toParameterName(f.value), f.value)\n        case f: EqualTo            => Seq(f.attribute.toParameterName(f.value), f.value)\n        case f: GreaterThan        => Seq(f.attribute.toParameterName(f.value), f.value)\n        case f: GreaterThanOrEqual => Seq(f.attribute.toParameterName(f.value), f.value)\n        case f: LessThan           => Seq(f.attribute.toParameterName(f.value), f.value)\n        case f: LessThanOrEqual    => Seq(f.attribute.toParameterName(f.value), f.value)\n        case f: In                 => Seq(f.attribute.toParameterName(f.values), f.values)\n        case f: StringStartsWith   => Seq(f.attribute.toParameterName(f.value), f.value)\n        case f: StringEndsWith     => Seq(f.attribute.toParameterName(f.value), f.value)\n        case f: StringContains     => Seq(f.attribute.toParameterName(f.value), f.value)\n        case f: Not                => f.child.getAttributeAndValue\n        case _                     => Seq()\n      }\n    }\n  }\n\n  implicit class StructTypeImplicit(structType: StructType) {\n\n    private def isValidMapOrStructField(field: String, structFieldName: String) = {\n      val value: String = \"\"\"(`.*`)|([^\\.]*)\"\"\".r.findFirstIn(field).getOrElse(\"\")\n      structFieldName == value.unquote() || structFieldName == value\n    }\n\n    def getByName(name: String): Option[StructField] = {\n      val index = structType.fieldIndex(name)\n      if (index > -1) Some(structType(index)) else None\n    }\n\n    def getFieldIndex(fieldName: String): Long = structType.fields.map(_.name).indexOf(fieldName)\n\n    def getMissingFields(fields: Set[String]): Set[String] = fields\n      .map(field => {\n        val maybeField = structType\n          .find(structField => {\n            structField.dataType match {\n              case _: MapType    => isValidMapOrStructField(field, structField.name)\n              case _: StructType => isValidMapOrStructField(field, structField.name)\n              case _             => structField.name == field.unquote() || structField.name == field\n            }\n          })\n        field -> maybeField.isDefined\n      })\n      .filterNot(e => e._2)\n      .map(e => e._1)\n  }\n\n  implicit class AggregationImplicit(aggregation: Aggregation) {\n    def groupByCols(): Array[Expression] = ReflectionUtils.groupByCols(aggregation)\n  }\n\n  implicit class MapImplicit[K, V](map: Map[String, V]) {\n\n    private def innerFlattenMap(map: Map[String, _], prefix: String): Seq[(String, AnyRef)] = map\n      .toSeq\n      .flatMap(t => {\n        val key: String = if (prefix != \"\") s\"$prefix.${t._1}\" else t._1\n        t._2 match {\n          case nestedMap: Map[String, _]           => innerFlattenMap(nestedMap, key)\n          case nestedMap: java.util.Map[String, _] => innerFlattenMap(nestedMap.asScala.toMap, key)\n          case _                                   => Seq((key, t._2.asInstanceOf[AnyRef]))\n        }\n      })\n      .toList\n\n    def flattenMap(prefix: String = \"\", groupDuplicateKeys: Boolean = false): Map[String, AnyRef] =\n      innerFlattenMap(map, prefix)\n        .groupBy(_._1)\n        .mapValues(seq => if (groupDuplicateKeys && seq.size > 1) seq.map(_._2).asJava else seq.last._2)\n        .toMap\n\n    def flattenKeys(prefix: String = \"\"): Seq[String] = map\n      .flatMap(t => {\n        val key: String = if (prefix != \"\") s\"$prefix.${t._1}\" else t._1\n        t._2 match {\n          case nestedMap: Map[String, _]           => nestedMap.flattenKeys(key)\n          case nestedMap: java.util.Map[String, _] => nestedMap.asScala.toMap.flattenKeys(key)\n          case _                                   => Seq(key)\n        }\n      })\n      .toList\n  }\n\n  implicit class StringMapImplicits(map: Map[String, String]) {\n\n    private val propertyMapper = new ObjectMapper()\n    propertyMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true)\n\n    private def nestingMap(data: Map[String, String]): java.util.Map[String, Any] = {\n      val map = new java.util.HashMap[String, Any]();\n      data.foreach(t => {\n        val splitted = t._1.split(\"\\\\.\")\n        if (splitted.size == 1) {\n          val value =\n            try {\n              propertyMapper.readValue[Any](t._2, classOf[Any])\n            } catch {\n              case _: JsonParseException => t._2\n            }\n          map.put(t._1, value)\n        } else {\n          if (map.containsKey(splitted.head)) {\n            val value = map.get(splitted.head).asInstanceOf[java.util.Map[String, Any]]\n            value.putAll(nestingMap(Map(splitted.drop(1).mkString(\".\") -> t._2)))\n            map.put(splitted.head, value)\n          } else {\n            map.put(splitted.head, nestingMap(Map(splitted.drop(1).mkString(\".\") -> t._2)))\n          }\n        }\n      })\n      map\n    }\n\n    def toNestedJavaMap: java.util.Map[String, Any] = nestingMap(map)\n  }\n\n  implicit class ValueImplicits(value: Value) {\n\n    def asOptionalLong(): Option[Long] = {\n      if (value.isNull) {\n        Option.empty\n      } else {\n        Option(value.asLong())\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "common/src/main/scala/org/neo4j/spark/util/Neo4jOptions.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark.util\n\nimport org.apache.spark.internal.Logging\nimport org.apache.spark.sql.SaveMode\nimport org.apache.spark.sql.SparkSession\nimport org.jetbrains.annotations.TestOnly\nimport org.neo4j.connectors.authn.AuthenticationToken\nimport org.neo4j.connectors.authn.AuthenticationTokenSupplierFactory\nimport org.neo4j.connectors.common.driver.reauth.ReAuthDriverFactory\nimport org.neo4j.driver.Config.TrustStrategy\nimport org.neo4j.driver._\nimport org.neo4j.driver.exceptions.Neo4jException\nimport org.neo4j.driver.net.ServerAddress\nimport org.neo4j.spark.util.Neo4jImplicits.StringMapImplicits\n\nimport java.io.File\nimport java.net.URI\nimport java.time.Duration\nimport java.util\nimport java.util.Locale\nimport java.util.ServiceLoader\nimport java.util.UUID\nimport java.util.concurrent.TimeUnit\nimport java.util.function.Supplier\n\nimport scala.collection.JavaConverters._\nimport scala.language.implicitConversions\n\nclass Neo4jOptions(private val options: java.util.Map[String, String]) extends Serializable with Logging {\n\n  import Neo4jOptions._\n  import QueryType._\n\n  def asMap() = new util.HashMap[String, String](options)\n\n  private def getRequiredParameter(parameter: String): String = {\n    if (!options.containsKey(parameter) || options.get(parameter).isEmpty) {\n      throw new IllegalArgumentException(s\"Parameter '$parameter' is required\")\n    }\n\n    options.get(parameter)\n  }\n\n  private def getParameter(parameter: String, defaultValue: String = \"\"): String =\n    getParameterOption(parameter).getOrElse(defaultValue)\n\n  private def getParameterOption(parameter: String): Option[String] =\n    Some(options.get(parameter))\n      .flatMap(Option(_)) // to turn null into None\n      .map(_.trim)\n\n  private def getAuthenticationParameters: Map[String, String] = {\n    val authType = getParameter(AUTH_TYPE, DEFAULT_AUTH_TYPE)\n    val authNamespace = s\"$AUTH.$authType\"\n    val providedParameters = options.asScala\n      .filterKeys(_.startsWith(authNamespace))\n      .map(t => (t._1.substring(authNamespace.length + 1), t._2))\n      .toMap\n    DEFAULT_AUTH_PARAMETERS ++ providedParameters\n  }\n\n  val saveMode: String = getParameter(SAVE_MODE, DEFAULT_SAVE_MODE.toString)\n\n  val pushdownFiltersEnabled: Boolean =\n    getParameter(PUSHDOWN_FILTERS_ENABLED, DEFAULT_PUSHDOWN_FILTERS_ENABLED.toString).toBoolean\n\n  val pushdownColumnsEnabled: Boolean =\n    getParameter(PUSHDOWN_COLUMNS_ENABLED, DEFAULT_PUSHDOWN_COLUMNS_ENABLED.toString).toBoolean\n\n  val pushdownAggregateEnabled: Boolean =\n    getParameter(PUSHDOWN_AGGREGATE_ENABLED, DEFAULT_PUSHDOWN_AGGREGATE_ENABLED.toString).toBoolean\n\n  val pushdownLimitEnabled: Boolean =\n    getParameter(PUSHDOWN_LIMIT_ENABLED, DEFAULT_PUSHDOWN_LIMIT_ENABLED.toString).toBoolean\n\n  val pushdownTopNEnabled: Boolean =\n    getParameter(PUSHDOWN_TOPN_ENABLED, DEFAULT_PUSHDOWN_TOPN_ENABLED.toString).toBoolean\n\n  val schemaMetadata: Neo4jSchemaMetadata = initSchemaMetadata\n\n  private def initSchemaMetadata = {\n    val deprecatedSchemaOptimization = OptimizationType\n      .withCaseInsensitiveName(getParameter(SCHEMA_OPTIMIZATION_TYPE, DEFAULT_OPTIMIZATION_TYPE.toString).toUpperCase)\n    if (deprecatedSchemaOptimization != OptimizationType.NONE) {\n      logWarning(\n        s\"\"\"\n           |Option `$SCHEMA_OPTIMIZATION_TYPE` is deprecated and will be removed in future implementations,\n           |please move to one of the following depending on your use case:\n           |- `$SCHEMA_OPTIMIZATION_NODE_KEY`\n           |- `$SCHEMA_OPTIMIZATION_RELATIONSHIP_KEY`\n           |\"\"\".stripMargin\n      )\n    }\n\n    val nodeConstr: ConstraintsOptimizationType.Value = ConstraintsOptimizationType\n      .withCaseInsensitiveName(getParameter(\n        SCHEMA_OPTIMIZATION_NODE_KEY,\n        DEFAULT_SCHEMA_OPTIMIZATION_NODE_KEY.toString\n      ).trim)\n    val relConstr: ConstraintsOptimizationType.Value = ConstraintsOptimizationType\n      .withCaseInsensitiveName(getParameter(\n        SCHEMA_OPTIMIZATION_RELATIONSHIP_KEY,\n        DEFAULT_SCHEMA_OPTIMIZATION_RELATIONSHIP_KEY.toString\n      ).trim)\n    val schemaConstraints = getParameter(SCHEMA_OPTIMIZATION, DEFAULT_SCHEMA_OPTIMIZATION.toString)\n      .split(\",\")\n      .map(_.trim)\n      .map(SchemaConstraintsOptimizationType.withCaseInsensitiveName)\n      .toSet\n    Neo4jSchemaMetadata(\n      getParameter(SCHEMA_FLATTEN_LIMIT, DEFAULT_SCHEMA_FLATTEN_LIMIT.toString).toInt,\n      SchemaStrategy.withCaseInsensitiveName(getParameter(\n        SCHEMA_STRATEGY,\n        DEFAULT_SCHEMA_STRATEGY.toString\n      ).toUpperCase),\n      deprecatedSchemaOptimization,\n      Neo4jSchemaOptimizations(nodeConstr, relConstr, schemaConstraints),\n      getParameter(SCHEMA_MAP_GROUP_DUPLICATE_KEYS, DEFAULT_MAP_GROUP_DUPLICATE_KEYS.toString).toBoolean\n    )\n  }\n\n  val indexAwait = getParameter(INDEX_AWAIT_TIMEOUT_SEC, DEFAULT_INDEX_AWAIT_TIMEOUT_SEC.toString).toInt\n\n  val query: Neo4jQueryOptions = (\n    getParameter(QUERY.toString.toLowerCase),\n    getParameter(LABELS.toString.toLowerCase),\n    getParameter(RELATIONSHIP.toString.toLowerCase()),\n    getParameter(GDS.toString.toLowerCase())\n  ) match {\n    case (query, \"\", \"\", \"\") => Neo4jQueryOptions(QUERY, query)\n    case (\"\", label, \"\", \"\") => {\n      val parsed = if (label.trim.startsWith(\":\")) label.substring(1) else label\n      Neo4jQueryOptions(LABELS, parsed)\n    }\n    case (\"\", \"\", relationship, \"\") => Neo4jQueryOptions(RELATIONSHIP, relationship)\n    case (\"\", \"\", \"\", gds)          => Neo4jQueryOptions(GDS, gds)\n    case _ => throw new IllegalArgumentException(\n        s\"You need to specify just one of these options: ${\n            QueryType.values.toSeq.map(value => s\"'${value.toString.toLowerCase()}'\")\n              .sorted.mkString(\", \")\n          }\"\n      )\n  }\n\n  val connection: Neo4jDriverOptions = Neo4jDriverOptions(\n    getRequiredParameter(URL),\n    getParameter(AUTH_TYPE, DEFAULT_AUTH_TYPE),\n    getAuthenticationParameters,\n    getParameter(ENCRYPTION_ENABLED, DEFAULT_ENCRYPTION_ENABLED.toString).toBoolean,\n    Option(getParameter(ENCRYPTION_TRUST_STRATEGY, null)),\n    getParameter(ENCRYPTION_CA_CERTIFICATE_PATH, DEFAULT_EMPTY),\n    getParameter(CONNECTION_MAX_LIFETIME_MSECS, DEFAULT_CONNECTION_MAX_LIFETIME_MSECS.toString).toInt,\n    getParameter(CONNECTION_ACQUISITION_TIMEOUT_MSECS, DEFAULT_TIMEOUT.toString).toInt,\n    getParameter(\n      CONNECTION_LIVENESS_CHECK_TIMEOUT_MSECS,\n      DEFAULT_CONNECTION_LIVENESS_CHECK_TIMEOUT_MSECS.toString\n    ).toInt,\n    getParameter(CONNECTION_TIMEOUT_MSECS, DEFAULT_TIMEOUT.toString).toInt\n  )\n\n  val session: Neo4jSessionOptions = Neo4jSessionOptions(\n    getParameter(DATABASE, DEFAULT_EMPTY),\n    AccessMode.valueOf(getParameter(ACCESS_MODE, DEFAULT_ACCESS_MODE.toString).toUpperCase())\n  )\n\n  val nodeMetadata: Neo4jNodeMetadata = initNeo4jNodeMetadata()\n\n  val legacyTypeConversionEnabled: Boolean = getParameter(\n    TYPE_CONVERSION,\n    DEFAULT_TYPE_CONVERSION\n  ).toLowerCase(Locale.ROOT).equals(\"legacy\")\n\n  private def mapPropsString(strOpt: Option[String]): Option[Map[String, String]] = strOpt.map(str =>\n    str.split(\",\")\n      .map(_.trim)\n      .filter(_.nonEmpty)\n      .map(s => {\n        val keys = if (s.startsWith(\"`\")) {\n          val pattern = \"`[^`]+`\".r\n          val groups = pattern findAllIn s\n          groups\n            .map(_.replaceAll(\"`\", \"\"))\n            .toArray\n        } else {\n          s.split(\":\")\n        }\n        if (keys.length == 2) {\n          (keys(0), keys(1))\n        } else {\n          (keys(0), keys(0))\n        }\n      })\n      .toMap\n  )\n\n  private def initNeo4jNodeMetadata(\n    nodeKeysString: String = getParameter(NODE_KEYS, \"\"),\n    labelsString: String = query.value,\n    nodePropsString: String = \"\",\n    skipNullKeys: Boolean = getParameter(NODE_KEYS_SKIP_NULLS, \"false\").toBoolean\n  ): Neo4jNodeMetadata = {\n\n    val nodeKeys = mapPropsString(Some(nodeKeysString)).getOrElse(Map.empty[String, String])\n    val nodeProps = mapPropsString(Some(nodePropsString)).getOrElse(Map.empty[String, String])\n\n    val labels = labelsString\n      .split(\":\")\n      .map(_.trim)\n      .filter(_.nonEmpty)\n    Neo4jNodeMetadata(labels, nodeKeys, nodeProps, skipNullKeys)\n  }\n\n  val transactionSettings: Neo4jTransactionSettings = initNeo4jTransactionSettings()\n\n  val script: Array[String] = getParameter(SCRIPT)\n    .split(\";\")\n    .map(_.trim)\n    .filterNot(_.isEmpty)\n\n  private def initNeo4jTransactionSettings(): Neo4jTransactionSettings = {\n    val retries = getParameter(TRANSACTION_RETRIES, DEFAULT_TRANSACTION_RETRIES.toString).toInt\n    val failOnTransactionCodes = getParameter(TRANSACTION_CODES_FAIL, DEFAULT_EMPTY)\n      .split(\",\")\n      .map(_.trim)\n      .filter(_.nonEmpty)\n      .toSet\n    val batchSize = getParameter(BATCH_SIZE, DEFAULT_BATCH_SIZE.toString).toInt\n    val retryTimeout = getParameter(TRANSACTION_RETRY_TIMEOUT, DEFAULT_TRANSACTION_RETRY_TIMEOUT.toString).toInt\n    Neo4jTransactionSettings(retries, failOnTransactionCodes, batchSize, retryTimeout)\n  }\n\n  val relationshipMetadata: Neo4jRelationshipMetadata = initNeo4jRelationshipMetadata()\n\n  private def initNeo4jRelationshipMetadata(): Neo4jRelationshipMetadata = {\n    val source = initNeo4jNodeMetadata(\n      getParameter(RELATIONSHIP_SOURCE_NODE_KEYS, \"\"),\n      getParameter(RELATIONSHIP_SOURCE_LABELS, \"\"),\n      getParameter(RELATIONSHIP_SOURCE_NODE_PROPS, \"\"),\n      getParameter(RELATIONSHIP_SOURCE_NODE_KEYS_SKIP_NULLS, \"false\").toBoolean\n    )\n\n    val target = initNeo4jNodeMetadata(\n      getParameter(RELATIONSHIP_TARGET_NODE_KEYS, \"\"),\n      getParameter(RELATIONSHIP_TARGET_LABELS, \"\"),\n      getParameter(RELATIONSHIP_TARGET_NODE_PROPS, \"\"),\n      getParameter(RELATIONSHIP_TARGET_NODE_KEYS_SKIP_NULLS, \"false\").toBoolean\n    )\n\n    val nodeMap = getParameter(RELATIONSHIP_NODES_MAP, DEFAULT_RELATIONSHIP_NODES_MAP.toString).toBoolean\n\n    val relProps = mapPropsString(getParameterOption(RELATIONSHIP_PROPERTIES))\n\n    val writeStrategy = RelationshipSaveStrategy.withCaseInsensitiveName(getParameter(\n      RELATIONSHIP_SAVE_STRATEGY,\n      DEFAULT_RELATIONSHIP_SAVE_STRATEGY.toString\n    ).toUpperCase)\n    val sourceSaveMode = NodeSaveMode.withCaseInsensitiveName(getParameter(\n      RELATIONSHIP_SOURCE_SAVE_MODE,\n      DEFAULT_RELATIONSHIP_SOURCE_SAVE_MODE.toString\n    ))\n    val targetSaveMode = NodeSaveMode.withCaseInsensitiveName(getParameter(\n      RELATIONSHIP_TARGET_SAVE_MODE,\n      DEFAULT_RELATIONSHIP_TARGET_SAVE_MODE.toString\n    ))\n\n    val relationshipKeys = mapPropsString(getParameterOption(RELATIONSHIP_KEYS)).getOrElse(Map.empty)\n\n    Neo4jRelationshipMetadata(\n      source,\n      target,\n      sourceSaveMode,\n      targetSaveMode,\n      relProps,\n      query.value,\n      nodeMap,\n      writeStrategy,\n      relationshipKeys,\n      getParameter(RELATIONSHIP_KEYS_SKIP_NULLS, \"false\").toBoolean\n    )\n  }\n\n  private def initNeo4jQueryMetadata(): Neo4jQueryMetadata = Neo4jQueryMetadata(\n    query.value.trim,\n    getParameter(QUERY_COUNT, \"\").trim\n  )\n\n  val queryMetadata: Neo4jQueryMetadata = initNeo4jQueryMetadata()\n\n  private def initNeo4jGdsMetadata(): Neo4jGdsMetadata = Neo4jGdsMetadata(\n    options.asScala\n      .filterKeys(k => k.startsWith(\"gds.\"))\n      .map(t => (t._1.substring(\"gds.\".length), t._2))\n      .toMap\n      .toNestedJavaMap\n  )\n\n  val gdsMetadata: Neo4jGdsMetadata = initNeo4jGdsMetadata()\n\n  val partitions: Int = getParameter(PARTITIONS, DEFAULT_PARTITIONS.toString).toInt\n\n  val streamingOrderBy: String = getParameter(ORDER_BY, getParameter(STREAMING_PROPERTY_NAME))\n\n  val apocConfig: Neo4jApocConfig = Neo4jApocConfig(options.asScala\n    .filterKeys(_.startsWith(\"apoc.\"))\n    .mapValues(Neo4jUtil.mapper.readValue(_, classOf[java.util.Map[String, AnyRef]]).asScala)\n    .toMap)\n\n  def getTableName: String = query.queryType match {\n    case QueryType.LABELS => s\"table_${nodeMetadata.labels.mkString(\"-\")}\"\n    case QueryType.RELATIONSHIP => s\"table_${relationshipMetadata.source.labels.mkString(\"-\")}\" +\n        s\"_${relationshipMetadata.relationshipType}\" +\n        s\"_${relationshipMetadata.target.labels.mkString(\"-\")}\"\n    case _ => s\"table_query_${UUID.randomUUID()}\"\n  }\n\n  val streamingOptions: Neo4jStreamingOptions = Neo4jStreamingOptions(\n    getParameter(STREAMING_PROPERTY_NAME),\n    StreamingFrom.withCaseInsensitiveName(getParameter(STREAMING_FROM, DEFAULT_STREAMING_FROM.toString)),\n    getParameter(STREAMING_QUERY_OFFSET)\n  )\n\n  def toNeo4jTransactionConfig: TransactionConfig = {\n    val timeout = getParameter(TRANSACTION_TIMEOUT_MSECS, DEFAULT_TRANSACTION_TIMEOUT)\n\n    val builder = TransactionConfig.builder()\n    if (timeout != null) {\n      val duration = Duration.ofMillis(timeout.toInt)\n      builder.withTimeout(duration)\n    }\n\n    builder.build()\n  }\n\n}\n\ncase class Neo4jStreamingOptions(\n  propertyName: String,\n  from: StreamingFrom.Value,\n  queryOffset: String\n)\n\ncase class Neo4jApocConfig(procedureConfigMap: Map[String, AnyRef])\n\ncase class Neo4jSchemaOptimizations(\n  nodeConstraint: ConstraintsOptimizationType.Value,\n  relConstraint: ConstraintsOptimizationType.Value,\n  schemaConstraints: Set[SchemaConstraintsOptimizationType.Value]\n)\n\ncase class Neo4jSchemaMetadata(\n  flattenLimit: Int,\n  strategy: SchemaStrategy.Value,\n  optimizationType: OptimizationType.Value,\n  optimization: Neo4jSchemaOptimizations,\n  mapGroupDuplicateKeys: Boolean\n)\n\ncase class Neo4jTransactionSettings(\n  retries: Int,\n  failOnTransactionCodes: Set[String],\n  batchSize: Int,\n  retryTimeout: Long\n) {\n\n  def shouldFailOn(exception: Throwable): Boolean = {\n    exception match {\n      case e: Neo4jException => failOnTransactionCodes.contains(e.code())\n      case _                 => false\n    }\n  }\n\n}\n\ncase class Neo4jNodeMetadata(\n  labels: Seq[String],\n  nodeKeys: Map[String, String],\n  properties: Map[String, String],\n  skipNullKeys: Boolean = false\n) {\n  def includesProperty(name: String): Boolean = nodeKeys.contains(name) || properties.contains(name)\n}\n\ncase class Neo4jRelationshipMetadata(\n  source: Neo4jNodeMetadata,\n  target: Neo4jNodeMetadata,\n  sourceSaveMode: NodeSaveMode.Value,\n  targetSaveMode: NodeSaveMode.Value,\n  properties: Option[Map[String, String]],\n  relationshipType: String,\n  nodeMap: Boolean,\n  saveStrategy: RelationshipSaveStrategy.Value,\n  relationshipKeys: Map[String, String],\n  skipNullKeys: Boolean = false\n)\n\ncase class Neo4jQueryMetadata(query: String, queryCount: String)\n\ncase class Neo4jGdsMetadata(parameters: util.Map[String, Any])\n\ncase class Neo4jQueryOptions(queryType: QueryType.Value, value: String)\n\ncase class Neo4jSessionOptions(database: String, accessMode: AccessMode = AccessMode.READ) {\n\n  def toNeo4jSession(): SessionConfig = {\n    val builder = SessionConfig.builder()\n      .withDefaultAccessMode(accessMode)\n\n    if (database != null && database != \"\") {\n      builder.withDatabase(database)\n    }\n\n    builder.build()\n  }\n}\n\ncase class Neo4jDriverOptions(\n  url: String,\n  auth: String,\n  authParameters: Map[String, String],\n  encryption: Boolean,\n  trustStrategy: Option[String],\n  certificatePath: String,\n  lifetime: Int,\n  acquisitionTimeout: Int,\n  livenessCheckTimeout: Int,\n  connectionTimeout: Int\n) extends Serializable {\n\n  def createDriver(): Driver = {\n    val (url, _) = connectionUrls\n    ReAuthDriverFactory.driver(url, createAuthTokenSupplier, toDriverConfig)\n  }\n\n  private def toDriverConfig: Config = {\n    val builder = Config.builder()\n      .withUserAgent(s\"neo4j-${Neo4jUtil.connectorEnv}-connector/${Neo4jUtil.connectorVersion}\")\n      .withLogging(Logging.slf4j())\n\n    if (lifetime > -1) builder.withMaxConnectionLifetime(lifetime, TimeUnit.MILLISECONDS)\n    if (acquisitionTimeout > -1) builder.withConnectionAcquisitionTimeout(acquisitionTimeout, TimeUnit.MILLISECONDS)\n    if (livenessCheckTimeout > -1)\n      builder.withConnectionLivenessCheckTimeout(livenessCheckTimeout, TimeUnit.MILLISECONDS)\n    if (connectionTimeout > -1) builder.withConnectionTimeout(connectionTimeout, TimeUnit.MILLISECONDS)\n\n    val (primaryUrl, resolvers) = connectionUrls\n\n    primaryUrl.getScheme match {\n      case \"neo4j+s\" | \"neo4j+ssc\" | \"bolt+s\" | \"bolt+ssc\" => ()\n      case _ => {\n        if (!encryption) {\n          builder.withoutEncryption()\n        } else {\n          builder.withEncryption()\n        }\n        trustStrategy\n          .map(Config.TrustStrategy.Strategy.valueOf)\n          .map {\n            case TrustStrategy.Strategy.TRUST_ALL_CERTIFICATES              => TrustStrategy.trustAllCertificates()\n            case TrustStrategy.Strategy.TRUST_SYSTEM_CA_SIGNED_CERTIFICATES => TrustStrategy.trustSystemCertificates()\n            case TrustStrategy.Strategy.TRUST_CUSTOM_CA_SIGNED_CERTIFICATES =>\n              TrustStrategy.trustCustomCertificateSignedBy(new File(certificatePath))\n          }.foreach(builder.withTrustStrategy)\n      }\n    }\n\n    if (resolvers.nonEmpty) {\n      builder.withResolver(_ => resolvers.asJava)\n    }\n\n    builder.build()\n  }\n\n  // public only for testing purposes\n  @TestOnly\n  def connectionUrls: (URI, Set[ServerAddress]) = {\n    val urls = url.split(\",\").toList\n    val resolved = urls\n      .drop(1)\n      .map(_.trim)\n      .map(URI.create)\n      .map(uri => ServerAddress.of(uri.getHost, if (uri.getPort > -1) uri.getPort else 7687))\n      .toSet\n    (URI.create(urls.head.trim), resolved)\n  }\n\n  private def createAuthTokenSupplier: Supplier[AuthenticationToken] = {\n    if (auth == null || auth.isEmpty) {\n      throw new IllegalArgumentException(s\"Authentication type name is required\")\n    }\n    val supplierFactories = ServiceLoader.load(\n      classOf[AuthenticationTokenSupplierFactory],\n      getClass.getClassLoader\n    ).iterator()\n      .asScala\n      .toList\n\n    val filteredSupplierFactories = supplierFactories.filter(s => s.getName != null && s.getName.equalsIgnoreCase(auth))\n\n    if (filteredSupplierFactories.isEmpty) {\n      throw new IllegalArgumentException(\n        s\"Authentication method '$auth' is not supported. Supported authentication methods are: ${supplierFactories.map(_.getName).mkString(\", \")}\"\n      )\n    }\n    if (filteredSupplierFactories.size > 1) {\n      throw new IllegalArgumentException(\n        s\"Multiple implementation for authentication type '$auth' are found\"\n      )\n    }\n\n    val username = authParameters.get(\"username\")\n    val password = authParameters.get(\"password\")\n    filteredSupplierFactories.head.create(username.orNull, password.orNull, authParameters.asJava)\n  }\n\n}\n\nobject Neo4jOptions {\n\n  // connection options\n  val URL = \"url\"\n\n  // auth\n  val AUTH = \"authentication\"\n  val AUTH_TYPE = \"authentication.type\"\n\n  // driver\n  val ENCRYPTION_ENABLED = \"encryption.enabled\"\n  val ENCRYPTION_TRUST_STRATEGY = \"encryption.trust.strategy\"\n  val ENCRYPTION_CA_CERTIFICATE_PATH = \"encryption.ca.certificate.path\"\n  val CONNECTION_MAX_LIFETIME_MSECS = \"connection.max.lifetime.msecs\"\n  val CONNECTION_LIVENESS_CHECK_TIMEOUT_MSECS = \"connection.liveness.timeout.msecs\"\n  val CONNECTION_ACQUISITION_TIMEOUT_MSECS = \"connection.acquisition.timeout.msecs\"\n  val CONNECTION_TIMEOUT_MSECS = \"connection.timeout.msecs\"\n  val TRANSACTION_TIMEOUT_MSECS = \"db.transaction.timeout\"\n\n  // session options\n  val DATABASE = \"database\"\n  val ACCESS_MODE = \"access.mode\"\n  val SAVE_MODE = \"save.mode\"\n\n  val PUSHDOWN_FILTERS_ENABLED = \"pushdown.filters.enabled\"\n  val PUSHDOWN_COLUMNS_ENABLED = \"pushdown.columns.enabled\"\n  val PUSHDOWN_AGGREGATE_ENABLED = \"pushdown.aggregate.enabled\"\n  val PUSHDOWN_LIMIT_ENABLED = \"pushdown.limit.enabled\"\n  val PUSHDOWN_TOPN_ENABLED = \"pushdown.topN.enabled\"\n\n  // schema options\n  val SCHEMA_STRATEGY = \"schema.strategy\"\n  val SCHEMA_FLATTEN_LIMIT = \"schema.flatten.limit\"\n  // deprecated in favor of...\n  val SCHEMA_OPTIMIZATION_TYPE = \"schema.optimization.type\"\n  // ...these options\n  val SCHEMA_OPTIMIZATION = \"schema.optimization\"\n  val SCHEMA_OPTIMIZATION_NODE_KEY = \"schema.optimization.node.keys\"\n  val SCHEMA_OPTIMIZATION_RELATIONSHIP_KEY = \"schema.optimization.relationship.keys\"\n  // map aggregation\n  val SCHEMA_MAP_GROUP_DUPLICATE_KEYS = \"schema.map.group.duplicate.keys\"\n\n  // index options\n  val INDEX_AWAIT_TIMEOUT_SEC = \"index.await.timeout\"\n\n  // partitions\n  val PARTITIONS = \"partitions\"\n\n  // orderBy\n  val ORDER_BY = \"orderBy\"\n\n  // skip.nulls postfix\n  val SKIP_NULLS = \"skip.nulls\"\n\n  // Node Metadata\n  val NODE_KEYS = \"node.keys\"\n  val NODE_KEYS_SKIP_NULLS = s\"${NODE_KEYS}.${SKIP_NULLS}\"\n  val NODE_PROPS = \"node.properties\"\n\n  val BATCH_SIZE = \"batch.size\"\n  val SUPPORTED_SAVE_MODES = Seq(SaveMode.Overwrite, SaveMode.ErrorIfExists, SaveMode.Append)\n\n  // Relationship Metadata\n  val RELATIONSHIP_SOURCE_LABELS =\n    s\"${QueryType.RELATIONSHIP.toString.toLowerCase}.source.${QueryType.LABELS.toString.toLowerCase}\"\n  val RELATIONSHIP_SOURCE_NODE_KEYS = s\"${QueryType.RELATIONSHIP.toString.toLowerCase}.source.$NODE_KEYS\"\n  val RELATIONSHIP_SOURCE_NODE_KEYS_SKIP_NULLS = s\"${RELATIONSHIP_SOURCE_NODE_KEYS}.${SKIP_NULLS}\"\n  val RELATIONSHIP_SOURCE_NODE_PROPS = s\"${QueryType.RELATIONSHIP.toString.toLowerCase}.source.$NODE_PROPS\"\n  val RELATIONSHIP_SOURCE_SAVE_MODE = s\"${QueryType.RELATIONSHIP.toString.toLowerCase}.source.$SAVE_MODE\"\n\n  val RELATIONSHIP_TARGET_LABELS =\n    s\"${QueryType.RELATIONSHIP.toString.toLowerCase}.target.${QueryType.LABELS.toString.toLowerCase}\"\n  val RELATIONSHIP_TARGET_NODE_KEYS = s\"${QueryType.RELATIONSHIP.toString.toLowerCase}.target.$NODE_KEYS\"\n  val RELATIONSHIP_TARGET_NODE_KEYS_SKIP_NULLS = s\"${RELATIONSHIP_TARGET_NODE_KEYS}.${SKIP_NULLS}\"\n  val RELATIONSHIP_TARGET_NODE_PROPS = s\"${QueryType.RELATIONSHIP.toString.toLowerCase}.target.$NODE_PROPS\"\n  val RELATIONSHIP_TARGET_SAVE_MODE = s\"${QueryType.RELATIONSHIP.toString.toLowerCase}.target.$SAVE_MODE\"\n  val RELATIONSHIP_PROPERTIES = s\"${QueryType.RELATIONSHIP.toString.toLowerCase}.properties\"\n  val RELATIONSHIP_NODES_MAP = s\"${QueryType.RELATIONSHIP.toString.toLowerCase}.nodes.map\"\n  val RELATIONSHIP_SAVE_STRATEGY = s\"${QueryType.RELATIONSHIP.toString.toLowerCase}.save.strategy\"\n  val RELATIONSHIP_KEYS = s\"${QueryType.RELATIONSHIP.toString.toLowerCase}.keys\"\n  val RELATIONSHIP_KEYS_SKIP_NULLS = s\"${RELATIONSHIP_KEYS}.${SKIP_NULLS}\"\n\n  // Query metadata\n  val QUERY_COUNT = \"query.count\"\n\n  // Transaction Metadata\n  val TRANSACTION_RETRIES = \"transaction.retries\"\n  val TRANSACTION_RETRY_TIMEOUT = \"transaction.retry.timeout\"\n  val TRANSACTION_CODES_FAIL = \"transaction.codes.fail\"\n\n  // Streaming\n  val STREAMING_PROPERTY_NAME = \"streaming.property.name\"\n  val STREAMING_FROM = \"streaming.from\"\n  val STREAMING_QUERY_OFFSET = \"streaming.query.offset\"\n\n  val SCRIPT = \"script\"\n\n  // Data conversion\n  val TYPE_CONVERSION = \"type.conversion\"\n\n  // defaults\n  val DEFAULT_EMPTY = \"\"\n  val DEFAULT_TIMEOUT: Int = -1\n  val DEFAULT_ACCESS_MODE = AccessMode.READ\n  val DEFAULT_AUTH_TYPE = \"basic\"\n  val DEFAULT_ENCRYPTION_ENABLED = false\n  val DEFAULT_SCHEMA_FLATTEN_LIMIT = 10\n  val DEFAULT_BATCH_SIZE = 5000\n  val DEFAULT_TRANSACTION_RETRIES = 3\n  val DEFAULT_TRANSACTION_RETRY_TIMEOUT = 0\n  val DEFAULT_TRANSACTION_TIMEOUT = null\n  val DEFAULT_RELATIONSHIP_NODES_MAP = false\n  val DEFAULT_SCHEMA_STRATEGY = SchemaStrategy.SAMPLE\n  val DEFAULT_SCHEMA_OPTIMIZATION_NODE_KEY = ConstraintsOptimizationType.NONE\n  val DEFAULT_SCHEMA_OPTIMIZATION_RELATIONSHIP_KEY = ConstraintsOptimizationType.NONE\n  val DEFAULT_SCHEMA_OPTIMIZATION = SchemaConstraintsOptimizationType.NONE\n  val DEFAULT_RELATIONSHIP_SAVE_STRATEGY: RelationshipSaveStrategy.Value = RelationshipSaveStrategy.NATIVE\n  val DEFAULT_RELATIONSHIP_SOURCE_SAVE_MODE: NodeSaveMode.Value = NodeSaveMode.Match\n  val DEFAULT_RELATIONSHIP_TARGET_SAVE_MODE: NodeSaveMode.Value = NodeSaveMode.Match\n  val DEFAULT_PUSHDOWN_FILTERS_ENABLED = true\n  val DEFAULT_PUSHDOWN_COLUMNS_ENABLED = true\n  val DEFAULT_PUSHDOWN_AGGREGATE_ENABLED = true\n  val DEFAULT_PUSHDOWN_LIMIT_ENABLED = true\n  val DEFAULT_PUSHDOWN_TOPN_ENABLED = true\n  val DEFAULT_PARTITIONS = 1\n  val DEFAULT_OPTIMIZATION_TYPE = OptimizationType.NONE\n  val DEFAULT_SAVE_MODE = SaveMode.Overwrite\n  val DEFAULT_STREAMING_FROM = StreamingFrom.NOW\n\n  // Default values optimizations for Aura please look at: https://aura.support.neo4j.com/hc/en-us/articles/1500002493281-Neo4j-Java-driver-settings-for-Aura\n  val DEFAULT_CONNECTION_MAX_LIFETIME_MSECS = Duration.ofMinutes(8).toMillis\n  val DEFAULT_CONNECTION_LIVENESS_CHECK_TIMEOUT_MSECS = Duration.ofMinutes(2).toMillis\n\n  val DEFAULT_MAP_GROUP_DUPLICATE_KEYS = false\n\n  val DEFAULT_INDEX_AWAIT_TIMEOUT_SEC = 300\n\n  var DEFAULT_AUTH_PARAMETERS: Map[String, String] =\n    Seq(\"username\", \"password\", \"ticket\", \"principal\", \"credentials\", \"realm\", \"scheme\", \"token\")\n      .map(name => name -> DEFAULT_EMPTY).toMap\n\n  private val DEFAULT_TYPE_CONVERSION = \"default\"\n\n  def fromSession(sparkSession: Option[SparkSession], options: java.util.Map[String, String]): Neo4jOptions = {\n    val sessionLevelOptions = sparkSession\n      .map {\n        _.conf\n          .getAll\n          .filterKeys(k => k.startsWith(\"neo4j.\"))\n          .map { elem => (elem._1.substring(\"neo4j.\".length), elem._2) }\n          .toMap\n      }\n      .getOrElse(Map.empty)\n\n    new Neo4jOptions((sessionLevelOptions ++ options.asScala).asJava)\n  }\n}\n\nclass CaseInsensitiveEnumeration extends Enumeration {\n\n  def withCaseInsensitiveName(s: String): Value = {\n    values.find(_.toString.toLowerCase() == s.toLowerCase).getOrElse(\n      throw new NoSuchElementException(s\"No value found for '$s'\")\n    )\n  }\n}\n\nobject StreamingFrom extends CaseInsensitiveEnumeration {\n  val ALL, NOW = Value\n\n  class StreamingFromValue(value: Value) {\n\n    def value(): Long = value match {\n      case ALL => -1L\n      case NOW => System.currentTimeMillis()\n    }\n  }\n\n  implicit def valToStreamingFromValue(value: Value): StreamingFromValue = new StreamingFromValue(value)\n}\n\nobject StorageType extends CaseInsensitiveEnumeration {\n  val NEO4J, SPARK = Value\n}\n\nobject QueryType extends CaseInsensitiveEnumeration {\n  val QUERY, LABELS, RELATIONSHIP, GDS = Value\n}\n\nobject RelationshipSaveStrategy extends CaseInsensitiveEnumeration {\n  val NATIVE, KEYS = Value\n}\n\nobject NodeSaveMode extends CaseInsensitiveEnumeration {\n  val Overwrite, ErrorIfExists, Match, Append = Value\n\n  def fromSaveMode(saveMode: SaveMode): Value = {\n    saveMode match {\n      case SaveMode.Overwrite     => Overwrite\n      case SaveMode.ErrorIfExists => ErrorIfExists\n      case SaveMode.Append        => Append\n      case _                      => throw new IllegalArgumentException(s\"SaveMode $saveMode not supported\")\n    }\n  }\n}\n\nobject SchemaStrategy extends CaseInsensitiveEnumeration {\n  val STRING, SAMPLE = Value\n}\n\nobject OptimizationType extends CaseInsensitiveEnumeration {\n  val INDEX, NODE_CONSTRAINTS, NONE = Value\n}\n\nobject ConstraintsOptimizationType extends CaseInsensitiveEnumeration {\n  val KEY, UNIQUE, NONE = Value\n}\n\nobject SchemaConstraintsOptimizationType extends CaseInsensitiveEnumeration {\n  val TYPE, EXISTS, NONE = Value\n}\n"
  },
  {
    "path": "common/src/main/scala/org/neo4j/spark/util/Neo4jUtil.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark.util\n\nimport com.fasterxml.jackson.core.JsonGenerator\nimport com.fasterxml.jackson.databind.JsonSerializer\nimport com.fasterxml.jackson.databind.ObjectMapper\nimport com.fasterxml.jackson.databind.SerializerProvider\nimport com.fasterxml.jackson.databind.module.SimpleModule\nimport org.apache.spark.sql.sources._\nimport org.neo4j.caniuse.Neo4j\nimport org.neo4j.cypherdsl.core._\nimport org.neo4j.driver.Session\nimport org.neo4j.driver.Transaction\nimport org.neo4j.driver.internal.retry.ExponentialBackoffRetryLogic\nimport org.neo4j.driver.types.Entity\nimport org.neo4j.driver.types.Path\nimport org.neo4j.spark.service.SchemaService\nimport org.neo4j.spark.util.Neo4jImplicits.EntityImplicits\nimport org.neo4j.spark.util.Neo4jImplicits._\nimport org.slf4j.Logger\n\nimport java.time.temporal.Temporal\nimport java.util.Properties\n\nimport scala.annotation.tailrec\n\nobject Neo4jUtil {\n\n  val NODE_ALIAS = \"n\"\n  private val INTERNAL_ID_FIELD_NAME = \"id\"\n  val INTERNAL_ID_FIELD = s\"<${INTERNAL_ID_FIELD_NAME}>\"\n  private val INTERNAL_LABELS_FIELD_NAME = \"labels\"\n  val INTERNAL_LABELS_FIELD = s\"<${INTERNAL_LABELS_FIELD_NAME}>\"\n  val INTERNAL_REL_ID_FIELD = s\"<rel.${INTERNAL_ID_FIELD_NAME}>\"\n  val INTERNAL_REL_TYPE_FIELD = \"<rel.type>\"\n  val RELATIONSHIP_SOURCE_ALIAS = \"source\"\n  val RELATIONSHIP_TARGET_ALIAS = \"target\"\n  val INTERNAL_REL_SOURCE_ID_FIELD = s\"<${RELATIONSHIP_SOURCE_ALIAS}.${INTERNAL_ID_FIELD_NAME}>\"\n  val INTERNAL_REL_TARGET_ID_FIELD = s\"<${RELATIONSHIP_TARGET_ALIAS}.${INTERNAL_ID_FIELD_NAME}>\"\n  val INTERNAL_REL_SOURCE_LABELS_FIELD = s\"<${RELATIONSHIP_SOURCE_ALIAS}.${INTERNAL_LABELS_FIELD_NAME}>\"\n  val INTERNAL_REL_TARGET_LABELS_FIELD = s\"<${RELATIONSHIP_TARGET_ALIAS}.${INTERNAL_LABELS_FIELD_NAME}>\"\n  val RELATIONSHIP_ALIAS = \"rel\"\n\n  private val properties = new Properties()\n  properties.load(Thread.currentThread().getContextClassLoader.getResourceAsStream(\"neo4j-spark-connector.properties\"))\n\n  def closeSafely(autoCloseable: AutoCloseable, logger: Logger = null): Unit = {\n    try {\n      autoCloseable match {\n        case s: Session     => if (s.isOpen) s.close()\n        case t: Transaction => if (t.isOpen) t.close()\n        case null           => ()\n        case _              => autoCloseable.close()\n      }\n    } catch {\n      case t: Throwable => if (logger != null) logger\n          .warn(s\"Cannot close ${autoCloseable.getClass.getSimpleName} because of the following exception:\", t)\n    }\n  }\n\n  val mapper = new ObjectMapper()\n  private val module = new SimpleModule(\"Neo4jApocSerializer\")\n\n  module.addSerializer(\n    classOf[Path],\n    new JsonSerializer[Path]() {\n\n      override def serialize(path: Path, jsonGenerator: JsonGenerator, serializerProvider: SerializerProvider): Unit =\n        jsonGenerator.writeString(path.toString)\n    }\n  )\n\n  module.addSerializer(\n    classOf[Entity],\n    new JsonSerializer[Entity]() {\n\n      override def serialize(\n        entity: Entity,\n        jsonGenerator: JsonGenerator,\n        serializerProvider: SerializerProvider\n      ): Unit = jsonGenerator.writeObject(entity.toMap)\n    }\n  )\n\n  module.addSerializer(\n    classOf[Temporal],\n    new JsonSerializer[Temporal]() {\n\n      override def serialize(\n        entity: Temporal,\n        jsonGenerator: JsonGenerator,\n        serializerProvider: SerializerProvider\n      ): Unit = jsonGenerator.writeRaw(entity.toString)\n    }\n  )\n  mapper.registerModule(module)\n\n  def isLong(str: String): Boolean = {\n    if (str == null) {\n      false\n    } else {\n      try {\n        str.trim.toLong\n        true\n      } catch {\n        case _: NumberFormatException => false\n      }\n    }\n  }\n\n  def connectorVersion: String = properties.getOrDefault(\"version\", \"UNKNOWN\").toString\n\n  def connectorEnv: String = Option(System.getProperty(\"neo4j.spark.platform\"))\n    .getOrElse(defaultConnectorEnv)\n\n  private def defaultConnectorEnv: String = Option(System.getenv(\"DATABRICKS_RUNTIME_VERSION\"))\n    .map(_ => \"databricks\")\n    .getOrElse(\"spark\")\n\n  def getCorrectProperty(container: PropertyContainer, attribute: String): Property = {\n    container.property(attribute.split('.'): _*)\n  }\n\n  def paramsFromFilters(filters: Array[Filter]): Map[String, Any] = {\n    filters.flatMap(f => f.flattenFilters).map(_.getAttributeAndValue)\n      .filter(_.nonEmpty)\n      .map(valAndAtt => valAndAtt.head.toString.unquote() -> toParamValue(valAndAtt(1)))\n      .toMap\n  }\n\n  def toParamValue(value: Any): Any = {\n    value match {\n      case date: java.sql.Date           => date.toString\n      case timestamp: java.sql.Timestamp => timestamp.toLocalDateTime\n      case _                             => value\n    }\n  }\n\n  def valueToCypherExpression(attribute: String, value: Any): Expression = {\n    val parameter = Cypher.parameter(attribute.toParameterName(value))\n    value match {\n      case d: java.sql.Date      => Functions.date(parameter)\n      case t: java.sql.Timestamp => Functions.localdatetime(parameter)\n      case _                     => parameter\n    }\n  }\n\n  def mapSparkFiltersToCypher(\n    filter: Filter,\n    container: PropertyContainer,\n    attributeAlias: Option[String] = None\n  ): Condition = {\n    filter match {\n      case eqns: EqualNullSafe =>\n        val parameter = valueToCypherExpression(eqns.attribute, eqns.value)\n        val property = getCorrectProperty(container, attributeAlias.getOrElse(eqns.attribute))\n        property.isNull.and(parameter.isNull)\n          .or(property.isEqualTo(parameter))\n      case eq: EqualTo =>\n        getCorrectProperty(container, attributeAlias.getOrElse(eq.attribute))\n          .isEqualTo(valueToCypherExpression(eq.attribute, eq.value))\n      case gt: GreaterThan =>\n        getCorrectProperty(container, attributeAlias.getOrElse(gt.attribute))\n          .gt(valueToCypherExpression(gt.attribute, gt.value))\n      case gte: GreaterThanOrEqual =>\n        getCorrectProperty(container, attributeAlias.getOrElse(gte.attribute))\n          .gte(valueToCypherExpression(gte.attribute, gte.value))\n      case lt: LessThan =>\n        getCorrectProperty(container, attributeAlias.getOrElse(lt.attribute))\n          .lt(valueToCypherExpression(lt.attribute, lt.value))\n      case lte: LessThanOrEqual =>\n        getCorrectProperty(container, attributeAlias.getOrElse(lte.attribute))\n          .lte(valueToCypherExpression(lte.attribute, lte.value))\n      case in: In =>\n        getCorrectProperty(container, attributeAlias.getOrElse(in.attribute))\n          .in(valueToCypherExpression(in.attribute, in.values))\n      case startWith: StringStartsWith =>\n        getCorrectProperty(container, attributeAlias.getOrElse(startWith.attribute))\n          .startsWith(valueToCypherExpression(startWith.attribute, startWith.value))\n      case endsWith: StringEndsWith =>\n        getCorrectProperty(container, attributeAlias.getOrElse(endsWith.attribute))\n          .endsWith(valueToCypherExpression(endsWith.attribute, endsWith.value))\n      case contains: StringContains =>\n        getCorrectProperty(container, attributeAlias.getOrElse(contains.attribute))\n          .contains(valueToCypherExpression(contains.attribute, contains.value))\n      case notNull: IsNotNull   => getCorrectProperty(container, attributeAlias.getOrElse(notNull.attribute)).isNotNull\n      case isNull: IsNull       => getCorrectProperty(container, attributeAlias.getOrElse(isNull.attribute)).isNull\n      case not: Not             => mapSparkFiltersToCypher(not.child, container, attributeAlias).not()\n      case filter @ (_: Filter) => throw new IllegalArgumentException(s\"Filter of type `$filter` is not supported.\")\n    }\n  }\n\n  def getStreamingPropertyName(options: Neo4jOptions): String = options.query.queryType match {\n    case QueryType.RELATIONSHIP => s\"rel.${options.streamingOptions.propertyName}\"\n    case _                      => options.streamingOptions.propertyName\n  }\n\n  def callSchemaService[T](\n    neo4j: Neo4j,\n    neo4jOptions: Neo4jOptions,\n    jobId: String,\n    filters: Array[Filter],\n    function: SchemaService => T\n  ): T = {\n    val driverCache = new DriverCache(neo4jOptions.connection)\n    val schemaService = new SchemaService(neo4j, neo4jOptions, driverCache, filters)\n    var hasError = false\n    try {\n      function(schemaService)\n    } catch {\n      case e: Throwable => {\n        hasError = true\n        throw e\n      }\n    } finally {\n      schemaService.close()\n      if (hasError) {\n        driverCache.close()\n      }\n    }\n  }\n\n  @tailrec\n  def isRetryableException(exception: Throwable): Boolean = {\n    if (exception == null) {\n      false\n    } else\n      ExponentialBackoffRetryLogic.isRetryable(exception) || isRetryableException(\n        exception.getCause\n      )\n  }\n\n}\n"
  },
  {
    "path": "common/src/main/scala/org/neo4j/spark/util/ValidationUtil.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark.util\n\nobject ValidationUtil {\n\n  def isNotEmpty(str: String, message: String) = if (str.isEmpty) {\n    throw new IllegalArgumentException(message)\n  }\n\n  def isNotBlank(str: String, message: String) = if (str.trim.isEmpty) {\n    throw new IllegalArgumentException(message)\n  }\n\n  def isBlank(str: String, message: String) = if (!str.trim.isEmpty) {\n    throw new IllegalArgumentException(message)\n  }\n\n  def isNotEmpty(seq: Seq[_], message: String) = if (seq.isEmpty) {\n    throw new IllegalArgumentException(message)\n  }\n\n  def isNotEmpty(map: Map[_, _], message: String) = if (map.isEmpty) {\n    throw new IllegalArgumentException(message)\n  }\n\n  def isTrue(boolean: Boolean, message: String) = if (!boolean) {\n    throw new IllegalArgumentException(message)\n  }\n\n  def isFalse(boolean: Boolean, message: String) = if (boolean) {\n    throw new IllegalArgumentException(message)\n  }\n\n  def isNotValid(message: String) = throw new IllegalArgumentException(message)\n}\n"
  },
  {
    "path": "common/src/main/scala/org/neo4j/spark/util/Validations.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark.util\n\nimport org.apache.spark.internal.Logging\nimport org.apache.spark.sql.SaveMode\nimport org.apache.spark.sql.SparkSession\nimport org.apache.spark.sql.types.StructType\nimport org.neo4j.caniuse.Neo4j\nimport org.neo4j.driver.AccessMode\nimport org.neo4j.driver.summary\nimport org.neo4j.spark.service.Neo4jQueryStrategy\nimport org.neo4j.spark.service.SchemaService\nimport org.neo4j.spark.util\nimport org.neo4j.spark.util.Neo4jImplicits.StructTypeImplicit\n\nimport java.util.Locale\n\nobject Validations {\n  def validate(validations: Validation*): Unit = validations.toSet[Validation].foreach(_.validate())\n}\n\ntrait Validation extends Logging {\n  def validate(): Unit\n\n  def ignoreOption(ignoredOption: String, primaryOption: String): Unit =\n    logWarning(s\"Option `$ignoredOption` is not compatible with `$primaryOption` and will be ignored\")\n}\n\ncase class ValidateSchemaOptions(neo4jOptions: Neo4jOptions, schema: StructType) extends Validation {\n\n  override def validate(): Unit = {\n    val missingFieldsMap = Map(\n      Neo4jOptions.NODE_KEYS -> schema.getMissingFields(neo4jOptions.nodeMetadata.nodeKeys.keySet),\n      Neo4jOptions.NODE_PROPS -> schema.getMissingFields(neo4jOptions.nodeMetadata.properties.keySet),\n      Neo4jOptions.RELATIONSHIP_PROPERTIES -> schema.getMissingFields(\n        neo4jOptions.relationshipMetadata.properties.getOrElse(Map.empty).keySet\n      ),\n      Neo4jOptions.RELATIONSHIP_SOURCE_NODE_PROPS -> schema.getMissingFields(\n        neo4jOptions.relationshipMetadata.source.properties.keySet\n      ),\n      Neo4jOptions.RELATIONSHIP_SOURCE_NODE_KEYS -> schema.getMissingFields(\n        neo4jOptions.relationshipMetadata.source.nodeKeys.keySet\n      ),\n      Neo4jOptions.RELATIONSHIP_TARGET_NODE_PROPS -> schema.getMissingFields(\n        neo4jOptions.relationshipMetadata.target.properties.keySet\n      ),\n      Neo4jOptions.RELATIONSHIP_TARGET_NODE_KEYS -> schema.getMissingFields(\n        neo4jOptions.relationshipMetadata.target.nodeKeys.keySet\n      )\n    )\n\n    val optionsWithMissingFields = missingFieldsMap.filter(_._2.nonEmpty)\n\n    if (optionsWithMissingFields.nonEmpty) {\n      throw new IllegalArgumentException(\n        s\"\"\"Write failed due to the following errors:\n           |${optionsWithMissingFields.map(field =>\n            s\" - Schema is missing ${field._2.mkString(\", \")} from option `${field._1}`\"\n          ).mkString(\"\\n\")}\n           |\n           |The option key and value might be inverted.\"\"\".stripMargin\n      )\n    }\n  }\n}\n\ncase class ValidateSchemaMetadataWrite(neo4jOptions: Neo4jOptions, saveMode: SaveMode) extends Validation {\n\n  override def validate(): Unit = {\n    val schemaMetadata = neo4jOptions.schemaMetadata\n    val hasNodeOptimizations = (schemaMetadata.optimizationType == OptimizationType.NODE_CONSTRAINTS\n      || schemaMetadata.optimization.nodeConstraint != ConstraintsOptimizationType.NONE)\n    val hasOptimizations = (schemaMetadata.optimizationType != OptimizationType.NONE\n      && (schemaMetadata.optimization.nodeConstraint != ConstraintsOptimizationType.NONE\n        || schemaMetadata.optimization.relConstraint != ConstraintsOptimizationType.NONE\n        || schemaMetadata.optimization.schemaConstraints != Set(SchemaConstraintsOptimizationType.NONE)))\n    if (hasOptimizations) {\n      throw new IllegalArgumentException(\n        s\"\"\"You cannot combine `${Neo4jOptions.SCHEMA_OPTIMIZATION_TYPE}` with:\n           |- `${Neo4jOptions.SCHEMA_OPTIMIZATION_NODE_KEY}`\n           |- `${Neo4jOptions.SCHEMA_OPTIMIZATION_RELATIONSHIP_KEY}`\n           |- `${Neo4jOptions.SCHEMA_OPTIMIZATION}`\n      \"\"\"\n      )\n    }\n    neo4jOptions.query.queryType match {\n      case QueryType.QUERY => {\n        neo4jOptions.schemaMetadata.optimizationType match {\n          case OptimizationType.NONE => // are valid\n          case _ => ValidationUtil.isNotValid(\n              s\"\"\"With Query Type ${neo4jOptions.query.queryType} you can\n                 |only use `${Neo4jOptions.SCHEMA_OPTIMIZATION_TYPE}`\n                 |`${OptimizationType.NONE}`\n                 |\"\"\".stripMargin\n            )\n        }\n        if (hasOptimizations) {\n          throw new IllegalArgumentException(\n            s\"With Query Type ${neo4jOptions.query.queryType} you cannot define any optimization\"\n          )\n        }\n      }\n      case QueryType.LABELS => {\n        if (hasNodeOptimizations) {\n          ValidationUtil.isTrue(saveMode == SaveMode.Overwrite, \"This works only with `mode` `Overwrite`\")\n          ValidationUtil.isNotEmpty(\n            neo4jOptions.nodeMetadata.nodeKeys,\n            s\"${Neo4jOptions.NODE_KEYS} is required to define the constraints\"\n          )\n        }\n      }\n      case QueryType.RELATIONSHIP => {\n        if (hasNodeOptimizations) {\n          ValidationUtil.isNotEmpty(\n            neo4jOptions.relationshipMetadata.source.nodeKeys,\n            s\"${Neo4jOptions.RELATIONSHIP_SOURCE_NODE_KEYS} is required to define the constraints\"\n          )\n          ValidationUtil.isNotEmpty(\n            neo4jOptions.relationshipMetadata.target.nodeKeys,\n            s\"${Neo4jOptions.RELATIONSHIP_TARGET_NODE_KEYS} is required to define the constraints\"\n          )\n          ValidationUtil.isTrue(\n            neo4jOptions.relationshipMetadata.sourceSaveMode == NodeSaveMode.Overwrite,\n            s\"This works only with `${Neo4jOptions.RELATIONSHIP_SOURCE_SAVE_MODE}` `${NodeSaveMode.Overwrite}`\"\n          )\n          ValidationUtil.isTrue(\n            neo4jOptions.relationshipMetadata.targetSaveMode == NodeSaveMode.Overwrite,\n            s\"This works only with `${Neo4jOptions.RELATIONSHIP_TARGET_SAVE_MODE}` `${NodeSaveMode.Overwrite}`\"\n          )\n        }\n        if (schemaMetadata.optimization.relConstraint != ConstraintsOptimizationType.NONE) {\n          ValidationUtil.isTrue(saveMode == SaveMode.Overwrite, s\"This works only with `mode` `${SaveMode.Overwrite}`\")\n          ValidationUtil.isNotEmpty(\n            neo4jOptions.relationshipMetadata.relationshipKeys,\n            s\"${Neo4jOptions.RELATIONSHIP_KEYS} is required to define the constraints\"\n          )\n        }\n      }\n      case _ => // do nothing\n    }\n    neo4jOptions.schemaMetadata.optimizationType match {\n      case OptimizationType.NONE => // skip it\n      case _ => neo4jOptions.query.queryType match {\n          case QueryType.LABELS =>\n            ValidationUtil.isTrue(saveMode == SaveMode.Overwrite, \"This works only with `mode` `SaveMode.Overwrite`\")\n          case QueryType.RELATIONSHIP => {\n            ValidationUtil.isTrue(\n              neo4jOptions.relationshipMetadata.sourceSaveMode == NodeSaveMode.Overwrite,\n              s\"This works only with `${Neo4jOptions.RELATIONSHIP_SOURCE_SAVE_MODE}` `Overwrite`\"\n            )\n            ValidationUtil.isTrue(\n              neo4jOptions.relationshipMetadata.targetSaveMode == NodeSaveMode.Overwrite,\n              s\"This works only with `${Neo4jOptions.RELATIONSHIP_TARGET_SAVE_MODE}` `Overwrite`\"\n            )\n          }\n        }\n    }\n  }\n}\n\ncase class ValidateSparkMinVersion(supportedVersions: String*) extends Validation {\n\n  override def validate(): Unit = {\n    val sparkVersion = SparkSession.getActiveSession\n      .map(_.version)\n      .getOrElse(\"UNKNOWN\")\n\n    ValidationUtil.isTrue(\n      isSupported(sparkVersion),\n      s\"\"\"Your current Spark version $sparkVersion is not supported by the current connector.\n         |Please visit https://neo4j.com/developer/spark/overview/#_spark_compatibility to know which connector version you need.\n         |\"\"\".stripMargin\n    )\n  }\n\n  def isSupported(sparkVersion: String): Boolean = {\n    val splittedVersion = sparkVersion.split(\"\\\\.\")\n    if (sparkVersion == \"UNKNOWN\") return true\n    val versions = supportedVersions\n      .flatMap(_.split(\"\\\\.\").zip(splittedVersion))\n      .map(t =>\n        try {\n          (t._1.toInt, t._2.toInt)\n        } catch {\n          case _: NumberFormatException => null\n        }\n      )\n      .filter(p => p != null)\n    for (t <- versions) {\n      val curr = t._2\n      val supported = t._1\n      if (curr > supported) { // if Spark current version (step) is greater than the supported one\n        return true // we can assume that the current version is a greater version, so it's supported\n      }\n      if (curr < supported) { // if Spark current version (step) is lower than the supported one\n        return false // we can assume that the current version is a greater version, so it's supported\n      }\n      // if the versions are equal we can check the next step\n    }\n    true // this happens if the two versions are equal\n  }\n}\n\ncase class ValidateConnection(neo4jOptions: Neo4jOptions, jobId: String) extends Validation {\n\n  override def validate(): Unit = {\n    var driverCache: DriverCache = null\n    var hasError = false\n    try {\n      driverCache = new DriverCache(neo4jOptions.connection)\n      driverCache.getOrCreate().verifyConnectivity()\n    } catch {\n      case e: Throwable => {\n        hasError = true\n        throw e\n      }\n    } finally {\n      if (hasError) {\n        Neo4jUtil.closeSafely(driverCache)\n      }\n    }\n  }\n}\n\ncase class ValidateSaveMode(saveMode: String) extends Validation {\n\n  override def validate(): Unit = {\n    ValidationUtil.isTrue(\n      Neo4jOptions.SUPPORTED_SAVE_MODES.contains(SaveMode.valueOf(saveMode)),\n      s\"\"\"Unsupported SaveMode.\n         |You provided $saveMode, supported are:\n         |${Neo4jOptions.SUPPORTED_SAVE_MODES.mkString(\",\")}\n         |\"\"\".stripMargin\n    )\n  }\n}\n\ncase class ValidateWrite(\n  neo4j: Neo4j,\n  neo4jOptions: Neo4jOptions,\n  jobId: String,\n  saveMode: SaveMode,\n  customValidation: Neo4jOptions => Unit = _ => ()\n) extends Validation {\n\n  override def validate(): Unit = {\n    ValidationUtil.isFalse(\n      neo4jOptions.session.accessMode == AccessMode.READ,\n      s\"Mode READ not supported for Data Source writer\"\n    )\n    val cache = new DriverCache(neo4jOptions.connection)\n    val schemaService = new SchemaService(neo4j, neo4jOptions, cache)\n    try {\n      ValidateConnection(neo4jOptions, jobId).validate()\n      ValidateNeo4jOptionsConsistency(neo4jOptions).validate()\n      ValidateSchemaMetadataWrite(neo4jOptions, saveMode).validate()\n\n      neo4jOptions.query.queryType match {\n        case QueryType.QUERY => {\n          val error = schemaService.validateQuery(\n            s\"\"\"WITH {} AS ${Neo4jQueryStrategy.VARIABLE_EVENT}, [] as ${Neo4jQueryStrategy.VARIABLE_SCRIPT_RESULT}\n               |${neo4jOptions.query.value}\n               |\"\"\".stripMargin,\n            org.neo4j.driver.summary.QueryType.WRITE_ONLY,\n            org.neo4j.driver.summary.QueryType.READ_WRITE\n          )\n          ValidationUtil.isTrue(error.isEmpty, error)\n          neo4jOptions.schemaMetadata.optimizationType match {\n            case OptimizationType.NONE => // are valid\n            case _ => ValidationUtil.isNotValid(\n                s\"\"\"With Query Type ${neo4jOptions.query.queryType} you can\n                   |only use `${Neo4jOptions.SCHEMA_OPTIMIZATION_TYPE}`\n                   |`${OptimizationType.NONE}`\n                   |\"\"\".stripMargin\n              )\n          }\n        }\n        case QueryType.LABELS => {\n          saveMode match {\n            case SaveMode.Overwrite => {\n              ValidationUtil.isNotEmpty(\n                neo4jOptions.nodeMetadata.nodeKeys,\n                s\"${Neo4jOptions.NODE_KEYS} is required when Save Mode is Overwrite\"\n              )\n            }\n            case _ => ()\n          }\n        }\n        case QueryType.RELATIONSHIP => {\n          ValidationUtil.isNotEmpty(\n            neo4jOptions.relationshipMetadata.target.labels,\n            s\"${Neo4jOptions.RELATIONSHIP_SOURCE_LABELS} is required when Save Mode is Overwrite\"\n          )\n          ValidationUtil.isNotEmpty(\n            neo4jOptions.relationshipMetadata.target.labels,\n            s\"${Neo4jOptions.RELATIONSHIP_TARGET_LABELS} is required when Save Mode is Overwrite\"\n          )\n        }\n      }\n      neo4jOptions.script.foreach(query =>\n        ValidationUtil.isTrue(\n          schemaService.isValidQuery(query),\n          s\"The following query inside the `${Neo4jOptions.SCRIPT}` is not valid, please check the syntax: $query\"\n        )\n      )\n\n      customValidation(neo4jOptions)\n    } finally {\n      schemaService.close()\n      cache.close()\n    }\n  }\n}\n\ncase class ValidateRead(neo4j: Neo4j, neo4jOptions: Neo4jOptions, jobId: String) extends Validation {\n\n  override def validate(): Unit = {\n    val cache = new DriverCache(neo4jOptions.connection)\n    val schemaService = new SchemaService(neo4j, neo4jOptions, cache)\n    try {\n      ValidateConnection(neo4jOptions, jobId).validate()\n      ValidateNeo4jOptionsConsistency(neo4jOptions).validate()\n\n      neo4jOptions.query.queryType match {\n        case QueryType.LABELS => {\n          ValidationUtil.isNotEmpty(\n            neo4jOptions.nodeMetadata.labels,\n            s\"You need to set the ${QueryType.LABELS.toString.toLowerCase} option\"\n          )\n        }\n        case QueryType.RELATIONSHIP => {\n          ValidationUtil.isNotBlank(\n            neo4jOptions.relationshipMetadata.relationshipType,\n            s\"You need to set the ${QueryType.RELATIONSHIP.toString.toLowerCase} option\"\n          )\n\n          ValidationUtil.isNotEmpty(\n            neo4jOptions.relationshipMetadata.source.labels,\n            s\"You need to set the ${Neo4jOptions.RELATIONSHIP_SOURCE_LABELS} option\"\n          )\n\n          ValidationUtil.isNotEmpty(\n            neo4jOptions.relationshipMetadata.target.labels,\n            s\"You need to set the ${Neo4jOptions.RELATIONSHIP_TARGET_LABELS} option\"\n          )\n        }\n        case QueryType.QUERY => {\n          ValidationUtil.isFalse(\n            neo4jOptions.query.value.matches(\"(?si).*(LIMIT \\\\d+|SKIP ?\\\\d+)\\\\s*\\\\z\"),\n            \"SKIP/LIMIT are not allowed at the end of the query\"\n          )\n          val queryError = schemaService.validateQuery(\n            s\"\"\"WITH [] as ${Neo4jQueryStrategy.VARIABLE_SCRIPT_RESULT}\n               |${neo4jOptions.query.value}\n               |\"\"\".stripMargin,\n            org.neo4j.driver.summary.QueryType.READ_ONLY\n          )\n          ValidationUtil.isTrue(queryError.isEmpty, queryError)\n          if (neo4jOptions.queryMetadata.queryCount.nonEmpty) {\n            if (!Neo4jUtil.isLong(neo4jOptions.queryMetadata.queryCount)) {\n              val queryCountError = schemaService.validateQueryCount(neo4jOptions.queryMetadata.queryCount)\n              ValidationUtil.isTrue(queryCountError.isEmpty, queryCountError)\n            }\n          }\n        }\n        case QueryType.GDS => {\n          ValidationUtil.isFalse(\n            neo4jOptions.query.value.contains(\".mutate\") || neo4jOptions.query.value.contains(\".write\"),\n            \"You cannot execute GDS mutate or write procedure in a read query\"\n          )\n          ValidationUtil.isTrue(\n            schemaService.isGdsProcedure(neo4jOptions.query.value),\n            s\"GDS procedure ${neo4jOptions.query.value} does not exist\"\n          )\n          ValidationUtil.isTrue(neo4jOptions.partitions == 1, \"For GDS queries we support only one partition\")\n          Validations.validate(ValidateGdsMetadata(neo4jOptions.gdsMetadata))\n        }\n      }\n      val scriptErrors = neo4jOptions.script\n        .map(schemaService.validateQuery(_))\n        .filter(_.nonEmpty)\n        .mkString(\"\\n\")\n      ValidationUtil.isTrue(\n        scriptErrors.isEmpty,\n        s\"\"\"\n           |The following queries inside the `${Neo4jOptions.SCRIPT}` are not valid,\n           |please check their syntax:\n           |$scriptErrors\n           |\"\"\".stripMargin\n      )\n    } finally {\n      schemaService.close()\n      cache.close()\n    }\n  }\n}\n\ncase class ValidateReadNotStreaming(neo4jOptions: Neo4jOptions, jobId: String) extends Validation {\n\n  override def validate(): Unit = {\n    ValidationUtil.isBlank(\n      neo4jOptions.streamingOptions.propertyName,\n      s\"You don't need to set the `${Neo4jOptions.STREAMING_PROPERTY_NAME}` option\"\n    )\n  }\n}\n\n/**\n * df: this method checks for inconsistencies between provided options.\n * Ex: if we use the QueryType.LABELS, we will ignore any relationship options.\n *\n * Plus it throws an exception if no QueryType is provided.\n */\ncase class ValidateNeo4jOptionsConsistency(neo4jOptions: Neo4jOptions) extends Validation {\n\n  override def validate(): Unit = {\n    if (neo4jOptions.query.value.isEmpty) {\n      val reqTypes = QueryType.values.map(qt => s\"`${qt.toString}`\").mkString(\", \")\n      throw new IllegalArgumentException(s\"No valid option found. One of $reqTypes is required\")\n    }\n\n    neo4jOptions.query.queryType match {\n      case QueryType.LABELS =>\n        ignoreQueryMetadata(QueryType.LABELS)\n        ignoreRelMetadata(QueryType.LABELS)\n        ignoreGdsMetadata(QueryType.LABELS)\n      case QueryType.RELATIONSHIP =>\n        ignoreQueryMetadata(QueryType.RELATIONSHIP)\n        ignoreNodeMetadata(QueryType.RELATIONSHIP)\n        ignoreGdsMetadata(QueryType.RELATIONSHIP)\n      case QueryType.QUERY => {\n        ignoreNodeMetadata(QueryType.QUERY)\n        ignoreRelMetadata(QueryType.QUERY)\n        ignoreGdsMetadata(QueryType.QUERY)\n      }\n      case QueryType.GDS =>\n        ignoreQueryMetadata(QueryType.GDS)\n        ignoreNodeMetadata(QueryType.GDS)\n        ignoreRelMetadata(QueryType.GDS)\n    }\n  }\n\n  private def ignoreGdsMetadata(queryType: QueryType.Value): Unit = {\n    if (!neo4jOptions.gdsMetadata.parameters.isEmpty) {\n      ignoreOption(Neo4jOptions.QUERY_COUNT, queryType.toString.toLowerCase(Locale.ENGLISH))\n    }\n  }\n\n  private def ignoreQueryMetadata(queryType: QueryType.Value): Unit = {\n    if (neo4jOptions.queryMetadata.queryCount.nonEmpty) {\n      ignoreOption(Neo4jOptions.QUERY_COUNT, queryType.toString.toLowerCase(Locale.ENGLISH))\n    }\n  }\n\n  private def ignoreRelMetadata(queryType: QueryType.Value): Unit = {\n    val optName = queryTypeAsOptionString(queryType)\n    if (neo4jOptions.relationshipMetadata.source.labels.nonEmpty) {\n      ignoreOption(Neo4jOptions.RELATIONSHIP_SOURCE_LABELS, optName)\n    }\n    if (neo4jOptions.relationshipMetadata.source.properties.nonEmpty) {\n      ignoreOption(Neo4jOptions.RELATIONSHIP_SOURCE_NODE_PROPS, optName)\n    }\n    if (neo4jOptions.relationshipMetadata.source.nodeKeys.nonEmpty) {\n      ignoreOption(Neo4jOptions.RELATIONSHIP_SOURCE_NODE_KEYS, optName)\n    }\n    if (neo4jOptions.relationshipMetadata.target.labels.nonEmpty) {\n      ignoreOption(Neo4jOptions.RELATIONSHIP_TARGET_LABELS, optName)\n    }\n    if (neo4jOptions.relationshipMetadata.target.properties.nonEmpty) {\n      ignoreOption(Neo4jOptions.RELATIONSHIP_TARGET_NODE_PROPS, optName)\n    }\n    if (neo4jOptions.relationshipMetadata.target.nodeKeys.nonEmpty) {\n      ignoreOption(Neo4jOptions.RELATIONSHIP_TARGET_NODE_KEYS, optName)\n    }\n  }\n\n  private def queryTypeAsOptionString(queryType: util.QueryType.Value): String =\n    queryType.toString.toLowerCase(Locale.ENGLISH)\n\n  private def ignoreNodeMetadata(queryType: QueryType.Value): Unit = {\n    val optName = queryTypeAsOptionString(queryType)\n    if (neo4jOptions.nodeMetadata.nodeKeys.nonEmpty) {\n      ignoreOption(Neo4jOptions.NODE_KEYS, optName)\n    }\n    if (neo4jOptions.nodeMetadata.properties.nonEmpty) {\n      ignoreOption(Neo4jOptions.NODE_PROPS, optName)\n    }\n  }\n}\n\ncase class ValidateGdsMetadata(neo4jGdsMetadata: Neo4jGdsMetadata) extends Validation {\n\n  override def validate(): Unit = {\n    val hasGraphName = neo4jGdsMetadata.parameters.get(\"graphName\") != null\n    val hasGraphNameOrConfiguration = neo4jGdsMetadata.parameters.get(\"graphNameOrConfiguration\") != null\n    ValidationUtil.isTrue(\n      hasGraphName || hasGraphNameOrConfiguration,\n      \"One between gds.graphName or gds.graphNameOrConfiguration is required\"\n    )\n  }\n}\n\ncase class ValidateReadStreaming(neo4j: Neo4j, neo4jOptions: Neo4jOptions, jobId: String) extends Validation {\n\n  override def validate(): Unit = {\n    val cache = new DriverCache(neo4jOptions.connection)\n    val schemaService = new SchemaService(neo4j, neo4jOptions, cache)\n    try {\n      ValidationUtil.isTrue(\n        neo4jOptions.partitions == 1,\n        \"For Spark Structured Streaming we support only one partition\"\n      )\n      neo4jOptions.query.queryType match {\n        case QueryType.QUERY => {\n          ValidationUtil.isTrue(\n            schemaService.isValidQuery(neo4jOptions.streamingOptions.queryOffset, summary.QueryType.READ_ONLY),\n            \"\"\"\n              |Please set `streaming.query.offset` with a valid Cypher READ_ONLY query\n              |that returns a long value i.e.\n              |MATCH (p:MyLabel)\n              |RETURN max(p.timestamp)\n              |\"\"\".stripMargin\n          )\n        }\n        case _ =>\n      }\n    } finally {\n      schemaService.close()\n      cache.close()\n    }\n  }\n}\n"
  },
  {
    "path": "common/src/main/scala/org/neo4j/spark/writer/BaseDataWriter.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark.writer\n\nimport org.apache.spark.internal.Logging\nimport org.apache.spark.sql.SaveMode\nimport org.apache.spark.sql.catalyst.InternalRow\nimport org.apache.spark.sql.connector.metric.CustomTaskMetric\nimport org.apache.spark.sql.connector.write.DataWriter\nimport org.apache.spark.sql.types.StructType\nimport org.neo4j.caniuse.Neo4j\nimport org.neo4j.driver.Session\nimport org.neo4j.driver.Transaction\nimport org.neo4j.driver.Values\nimport org.neo4j.driver.exceptions.ServiceUnavailableException\nimport org.neo4j.spark.service._\nimport org.neo4j.spark.util.DriverCache\nimport org.neo4j.spark.util.Neo4jOptions\nimport org.neo4j.spark.util.Neo4jUtil.closeSafely\nimport org.neo4j.spark.util.Neo4jUtil.isRetryableException\n\nimport java.io.Closeable\nimport java.time.Duration\nimport java.util\nimport java.util.concurrent.CountDownLatch\nimport java.util.concurrent.locks.LockSupport\n\nimport scala.annotation.tailrec\nimport scala.collection.JavaConverters._\n\nabstract class BaseDataWriter(\n  neo4j: Neo4j,\n  jobId: String,\n  partitionId: Int,\n  structType: StructType,\n  saveMode: SaveMode,\n  options: Neo4jOptions,\n  scriptResult: java.util.List[java.util.Map[String, AnyRef]]\n) extends Logging with Closeable with DataWriter[InternalRow] {\n\n  private val STOPPED_THREAD_EXCEPTION_MESSAGE =\n    \"Connection to the database terminated. Thread interrupted while committing the transaction\"\n\n  private val driverCache: DriverCache = new DriverCache(options.connection)\n\n  private var transaction: Transaction = _\n  private var session: Session = _\n\n  private val mappingService = new MappingService(new Neo4jWriteMappingStrategy(options), options)\n\n  private val batch: util.List[java.util.Map[String, Object]] = new util.ArrayList[util.Map[String, Object]]()\n\n  private val retries = new CountDownLatch(options.transactionSettings.retries)\n\n  private val query: String =\n    new Neo4jQueryService(options, new Neo4jQueryWriteStrategy(neo4j, saveMode)).createQuery()\n\n  private val metrics = DataWriterMetrics()\n\n  private var skipped = 0\n\n  def write(record: InternalRow): Unit = {\n    val mapped = mappingService.convert(record, structType)\n    mapped match {\n      case Some(m) => batch.add(m)\n      case None =>\n        skipped += 1\n    }\n    if (batch.size() == options.transactionSettings.batchSize) {\n      writeBatch()\n    }\n  }\n\n  @tailrec\n  private def writeBatch(): Unit = {\n    try {\n      if (session == null || !session.isOpen) {\n        session = driverCache.getOrCreate().session(options.session.toNeo4jSession())\n      }\n      if (transaction == null || !transaction.isOpen) {\n        transaction = session.beginTransaction(options.toNeo4jTransactionConfig)\n      }\n      log.info(\n        s\"\"\"Writing a batch of ${batch.size()} elements to Neo4j,\n           |for jobId=$jobId and partitionId=$partitionId\n           |with query: $query\n           |\"\"\".stripMargin\n      )\n      val result = transaction.run(\n        query,\n        Values.value(Map[String, AnyRef](\n          Neo4jQueryStrategy.VARIABLE_EVENTS -> batch,\n          Neo4jQueryStrategy.VARIABLE_SCRIPT_RESULT -> scriptResult\n        ).asJava)\n      )\n      val summary = result.consume()\n      val counters = summary.counters()\n      if (log.isDebugEnabled) {\n        log.debug(\n          s\"\"\"Batch saved into Neo4j data with:\n             | - nodes created: ${counters.nodesCreated()}\n             | - nodes deleted: ${counters.nodesDeleted()}\n             | - relationships created: ${counters.relationshipsCreated()}\n             | - relationships deleted: ${counters.relationshipsDeleted()}\n             | - properties set: ${counters.propertiesSet()}\n             | - labels added: ${counters.labelsAdded()}\n             | - labels removed: ${counters.labelsRemoved()}\n             |\"\"\".stripMargin\n        )\n      }\n      transaction.commit()\n\n      if (skipped > 0) {\n        log.info(s\"Skipped $skipped rows that contained null values in one of their key property values.\")\n        skipped = 0\n      }\n\n      // update metrics\n      metrics.applyCounters(batch.size(), counters)\n\n      closeSafely(transaction)\n      batch.clear()\n    } catch {\n      case e: Throwable =>\n        if (options.transactionSettings.shouldFailOn(e)) {\n          log.error(\"unable to write batch due to explicitly configured failure condition\", e)\n          throw e\n        }\n\n        if (isRetryableException(e) && retries.getCount > 0) {\n          retries.countDown()\n          log.info(\n            s\"encountered a transient exception while writing batch, retrying ${options.transactionSettings.retries - retries.getCount} time\",\n            e\n          )\n          close()\n          LockSupport.parkNanos(Duration.ofMillis(options.transactionSettings.retryTimeout).toNanos)\n          writeBatch()\n        } else {\n          logAndThrowException(e)\n        }\n    }\n  }\n\n  /**\n   * df: we check if the thrown exception is STOPPED_THREAD_EXCEPTION. This is the\n   * exception that is thrown when the streaming query is interrupted, we don't want to cause\n   * any error in this case. The transaction are rolled back automatically.\n   */\n  private def logAndThrowException(e: Throwable): Unit = {\n    if (e.isInstanceOf[ServiceUnavailableException] && e.getMessage == STOPPED_THREAD_EXCEPTION_MESSAGE) {\n      logWarning(e.getMessage)\n    } else {\n      logError(\"unable to write batch\", e)\n    }\n\n    throw e\n  }\n\n  def commit(): Null = {\n    writeBatch()\n    close()\n    null\n  }\n\n  def abort(): Unit = {\n    if (transaction != null && transaction.isOpen) {\n      try {\n        transaction.rollback()\n      } catch {\n        case e: Throwable => log.warn(\"Cannot rollback the transaction because of the following exception\", e)\n      }\n    }\n    close()\n  }\n\n  def close(): Unit = {\n    closeSafely(transaction, log)\n    closeSafely(session, log)\n  }\n\n  override def currentMetricsValues(): Array[CustomTaskMetric] = metrics.metricValues()\n}\n"
  },
  {
    "path": "common/src/main/scala/org/neo4j/spark/writer/DataWriterMetrics.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark.writer\n\nimport org.apache.spark.sql.connector.metric.CustomMetric\nimport org.apache.spark.sql.connector.metric.CustomSumMetric\nimport org.apache.spark.sql.connector.metric.CustomTaskMetric\nimport org.neo4j.driver.summary.SummaryCounters\nimport org.neo4j.spark.writer.DataWriterMetrics.LABELS_ADDED\nimport org.neo4j.spark.writer.DataWriterMetrics.LABELS_REMOVED\nimport org.neo4j.spark.writer.DataWriterMetrics.NODES_CREATED\nimport org.neo4j.spark.writer.DataWriterMetrics.NODES_DELETED\nimport org.neo4j.spark.writer.DataWriterMetrics.PROPERTIES_SET\nimport org.neo4j.spark.writer.DataWriterMetrics.RECORDS_WRITTEN\nimport org.neo4j.spark.writer.DataWriterMetrics.RELATIONSHIPS_CREATED\nimport org.neo4j.spark.writer.DataWriterMetrics.RELATIONSHIPS_DELETED\n\nimport java.util.concurrent.atomic.AtomicLong\n\ncase class DataWriterMetric(name: String, value: Long) extends CustomTaskMetric {}\n\nclass DataWriterMetrics private (\n  recordsProcessed: AtomicLong,\n  nodesCreated: AtomicLong,\n  nodesDeleted: AtomicLong,\n  relationshipsCreated: AtomicLong,\n  relationshipsDeleted: AtomicLong,\n  propertiesSet: AtomicLong,\n  labelsAdded: AtomicLong,\n  labelsRemoved: AtomicLong\n) {\n\n  def applyCounters(recordsWritten: Long, counters: SummaryCounters): Unit = {\n    this.recordsProcessed.addAndGet(recordsWritten)\n    this.nodesCreated.addAndGet(counters.nodesCreated())\n    this.nodesDeleted.addAndGet(counters.nodesDeleted())\n    this.relationshipsCreated.addAndGet(counters.relationshipsCreated())\n    this.relationshipsDeleted.addAndGet(counters.relationshipsDeleted())\n    this.propertiesSet.addAndGet(counters.propertiesSet())\n    this.labelsAdded.addAndGet(counters.labelsAdded())\n    this.labelsRemoved.addAndGet(counters.labelsRemoved())\n  }\n\n  def metricValues(): Array[CustomTaskMetric] = {\n    List[CustomTaskMetric](\n      DataWriterMetric(RECORDS_WRITTEN, recordsProcessed.longValue()),\n      DataWriterMetric(NODES_CREATED, nodesCreated.longValue()),\n      DataWriterMetric(NODES_DELETED, nodesDeleted.longValue()),\n      DataWriterMetric(RELATIONSHIPS_CREATED, relationshipsCreated.longValue()),\n      DataWriterMetric(RELATIONSHIPS_DELETED, relationshipsDeleted.longValue()),\n      DataWriterMetric(PROPERTIES_SET, propertiesSet.longValue()),\n      DataWriterMetric(LABELS_ADDED, labelsAdded.longValue()),\n      DataWriterMetric(LABELS_REMOVED, labelsRemoved.longValue())\n    ).toArray\n  }\n\n}\n\nobject DataWriterMetrics {\n  final val RECORDS_WRITTEN = \"neo4jMetrics.recordsWritten\"\n  final val RECORDS_WRITTEN_DESCRIPTION = \"number of records written\"\n  final val NODES_CREATED = \"neo4jMetrics.nodesCreated\"\n  final val NODES_CREATED_DESCRIPTION = \"number of nodes created\"\n  final val NODES_DELETED = \"neo4jMetrics.nodesDeleted\"\n  final val NODES_DELETED_DESCRIPTION = \"number of nodes deleted\"\n  final val RELATIONSHIPS_CREATED = \"neo4jMetrics.relationshipsCreated\"\n  final val RELATIONSHIPS_CREATED_DESCRIPTION = \"number of relationships created\"\n  final val RELATIONSHIPS_DELETED = \"neo4jMetrics.relationshipsDeleted\"\n  final val RELATIONSHIPS_DELETED_DESCRIPTION = \"number of relationships deleted\"\n  final val PROPERTIES_SET = \"neo4jMetrics.propertiesSet\"\n  final val PROPERTIES_SET_DESCRIPTION = \"number of properties set\"\n  final val LABELS_ADDED = \"neo4jMetrics.labelsAdded\"\n  final val LABELS_ADDED_DESCRIPTION = \"number of labels added\"\n  final val LABELS_REMOVED = \"neo4jMetrics.labelsRemoved\"\n  final val LABELS_REMOVED_DESCRIPTION = \"number of labels removed\"\n\n  def apply(): DataWriterMetrics = {\n    new DataWriterMetrics(\n      new AtomicLong(0),\n      new AtomicLong(0),\n      new AtomicLong(0),\n      new AtomicLong(0),\n      new AtomicLong(0),\n      new AtomicLong(0),\n      new AtomicLong(0),\n      new AtomicLong(0)\n    )\n  }\n\n  def metricDeclarations(): Array[CustomMetric] = {\n    List[CustomMetric](\n      new RecordsWrittenMetric,\n      new NodesCreatedMetric,\n      new NodesDeletedMetric,\n      new RelationshipsCreatedMetric,\n      new RelationshipsDeletedMetric,\n      new PropertiesSetMetric,\n      new LabelsAddedMetric,\n      new LabelsRemovedMetric\n    ).toArray\n  }\n\n}\n\nclass RecordsWrittenMetric extends CustomSumMetric {\n  override def name(): String = DataWriterMetrics.RECORDS_WRITTEN\n\n  override def description(): String = DataWriterMetrics.RECORDS_WRITTEN_DESCRIPTION\n}\n\nclass NodesCreatedMetric extends CustomSumMetric {\n  override def name(): String = DataWriterMetrics.NODES_CREATED\n\n  override def description(): String = DataWriterMetrics.NODES_CREATED_DESCRIPTION\n}\n\nclass NodesDeletedMetric extends CustomSumMetric {\n  override def name(): String = DataWriterMetrics.NODES_DELETED\n\n  override def description(): String = DataWriterMetrics.NODES_DELETED_DESCRIPTION\n}\n\nclass RelationshipsCreatedMetric extends CustomSumMetric {\n  override def name(): String = DataWriterMetrics.RELATIONSHIPS_CREATED\n\n  override def description(): String = DataWriterMetrics.RELATIONSHIPS_CREATED_DESCRIPTION\n}\n\nclass RelationshipsDeletedMetric extends CustomSumMetric {\n  override def name(): String = DataWriterMetrics.RELATIONSHIPS_DELETED\n\n  override def description(): String = DataWriterMetrics.RELATIONSHIPS_DELETED_DESCRIPTION\n}\n\nclass PropertiesSetMetric extends CustomSumMetric {\n  override def name(): String = DataWriterMetrics.PROPERTIES_SET\n\n  override def description(): String = DataWriterMetrics.PROPERTIES_SET_DESCRIPTION\n}\n\nclass LabelsAddedMetric extends CustomSumMetric {\n  override def name(): String = DataWriterMetrics.LABELS_ADDED\n\n  override def description(): String = DataWriterMetrics.LABELS_ADDED_DESCRIPTION\n}\n\nclass LabelsRemovedMetric extends CustomSumMetric {\n  override def name(): String = DataWriterMetrics.LABELS_REMOVED\n\n  override def description(): String = DataWriterMetrics.LABELS_REMOVED_DESCRIPTION\n}\n"
  },
  {
    "path": "common/src/test/scala/org/neo4j/spark/CommonTestSuiteIT.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark\n\nimport org.junit.runner.RunWith\nimport org.junit.runners.Suite\nimport org.neo4j.spark.service.SchemaServiceTSE\n\n@RunWith(classOf[Suite])\n@Suite.SuiteClasses(Array(\n  classOf[SchemaServiceTSE]\n))\nclass CommonTestSuiteIT extends SparkConnectorScalaSuiteIT {}\n"
  },
  {
    "path": "common/src/test/scala/org/neo4j/spark/CommonTestSuiteWithApocIT.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark\n\nimport org.junit.runner.RunWith\nimport org.junit.runners.Suite\nimport org.neo4j.spark.service.SchemaServiceWithApocTSE\n\n@RunWith(classOf[Suite])\n@Suite.SuiteClasses(Array(\n  classOf[SchemaServiceWithApocTSE]\n))\nclass CommonTestSuiteWithApocIT extends SparkConnectorScalaSuiteWithApocIT {}\n"
  },
  {
    "path": "common/src/test/scala/org/neo4j/spark/service/AuthenticationTest.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark.service\n\nimport org.junit.Test\nimport org.junit.runner.RunWith\nimport org.mockito.ArgumentMatchers\nimport org.mockito.ArgumentMatchers._\nimport org.mockito.Mockito.times\nimport org.neo4j.driver.AuthTokens\nimport org.neo4j.driver.Config\nimport org.neo4j.driver.GraphDatabase\nimport org.neo4j.spark.util.DriverCache\nimport org.neo4j.spark.util.Neo4jOptions\nimport org.powermock.api.mockito.PowerMockito\nimport org.powermock.core.classloader.annotations.PowerMockIgnore\nimport org.powermock.core.classloader.annotations.PrepareForTest\nimport org.powermock.modules.junit4.PowerMockRunner\nimport org.testcontainers.shaded.com.google.common.io.BaseEncoding\n\nimport java.net.URI\nimport java.util\n\n@PrepareForTest(Array(classOf[GraphDatabase]))\n@RunWith(classOf[PowerMockRunner])\n@PowerMockIgnore(value = Array(\"javax.management.*\"))\nclass AuthenticationTest {\n\n  @Test\n  def testLdapConnectionToken(): Unit = {\n    val token = BaseEncoding.base64.encode(\"user:password\".getBytes)\n    val options = new util.HashMap[String, String]\n    options.put(\"url\", \"bolt://localhost:7687\")\n    options.put(\"authentication.type\", \"custom\")\n    options.put(\"authentication.custom.credentials\", token)\n    options.put(\"labels\", \"Person\")\n\n    val neo4jOptions = new Neo4jOptions(options)\n    val neo4jDriverOptions = neo4jOptions.connection\n    val driverCache = new DriverCache(neo4jDriverOptions)\n\n    PowerMockito.spy(classOf[GraphDatabase])\n\n    driverCache.getOrCreate()\n\n    PowerMockito.verifyStatic(classOf[GraphDatabase], times(1))\n    GraphDatabase.driver(any[URI](), ArgumentMatchers.eq(AuthTokens.custom(\"\", token, \"\", \"\")), any(classOf[Config]))\n  }\n\n  @Test\n  def testBearerAuthToken(): Unit = {\n    val token = BaseEncoding.base64.encode(\"user:password\".getBytes)\n    val options = new util.HashMap[String, String]\n    options.put(\"url\", \"bolt://localhost:7687\")\n    options.put(\"authentication.type\", \"bearer\")\n    options.put(\"authentication.bearer.token\", token)\n\n    val neo4jOptions = new Neo4jOptions(options)\n    val neo4jDriverOptions = neo4jOptions.connection\n    val driverCache = new DriverCache(neo4jDriverOptions)\n\n    PowerMockito.spy(classOf[GraphDatabase])\n\n    driverCache.getOrCreate()\n\n    PowerMockito.verifyStatic(classOf[GraphDatabase], times(1))\n    GraphDatabase.driver(any[URI](), ArgumentMatchers.eq(AuthTokens.bearer(token)), any())\n  }\n}\n"
  },
  {
    "path": "common/src/test/scala/org/neo4j/spark/service/Neo4jQueryServiceIT.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark.service\n\nimport org.apache.spark.sql.connector.expressions.aggregate.Count\nimport org.apache.spark.sql.connector.expressions.aggregate.Max\nimport org.apache.spark.sql.connector.expressions.aggregate.Min\nimport org.apache.spark.sql.connector.expressions.aggregate.Sum\nimport org.junit.After\nimport org.junit.FixMethodOrder\nimport org.junit.Test\nimport org.junit.runners.MethodSorters\nimport org.neo4j.spark.SparkConnectorScalaSuiteWithGdsBase\nimport org.neo4j.spark.SparkConnectorScalaSuiteWithGdsBase.neo4j\nimport org.neo4j.spark.util.DriverCache\nimport org.neo4j.spark.util.DummyNamedReference\nimport org.neo4j.spark.util.Neo4jOptions\nimport org.scalatest.matchers.must.Matchers.convertToAnyMustWrapper\nimport org.scalatest.matchers.must.Matchers.endWith\n\nimport scala.language.postfixOps\n\n@FixMethodOrder(MethodSorters.JVM)\nclass Neo4jQueryServiceIT extends SparkConnectorScalaSuiteWithGdsBase {\n\n  @After\n  def cleanUp(): Unit = {\n    val options: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    options.put(Neo4jOptions.URL, SparkConnectorScalaSuiteWithGdsBase.server.getBoltUrl)\n    val neo4jOptions: Neo4jOptions = new Neo4jOptions(options)\n    new DriverCache(neo4jOptions.connection).close()\n  }\n\n  @Test\n  def testShouldDoAggregationOnGDS(): Unit = {\n    val options: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    options.put(Neo4jOptions.URL, SparkConnectorScalaSuiteWithGdsBase.server.getBoltUrl)\n    options.put(\"gds\", \"gds.pageRank.stream\")\n    val neo4jOptions: Neo4jOptions = new Neo4jOptions(options)\n\n    val field = new DummyNamedReference(\"score\")\n    val query: String = new Neo4jQueryService(\n      neo4jOptions,\n      new Neo4jQueryReadStrategy(\n        neo4j,\n        Array.empty,\n        PartitionPagination.EMPTY,\n        List(\n          \"nodeId\",\n          \"MAX(score)\",\n          \"MIN(score)\",\n          \"COUNT(score)\",\n          \"COUNT(DISTINCT score)\",\n          \"SUM(score)\",\n          \"SUM(DISTINCT score)\"\n        ),\n        Array(\n          new Max(field),\n          new Min(field),\n          new Sum(field, false),\n          new Count(field, false),\n          new Count(field, true),\n          new Sum(field, false),\n          new Sum(field, true)\n        )\n      )\n    ).createQuery()\n\n    query must endWith(\n      \"\"\"CALL gds.pageRank.stream($graphName)\n        |YIELD nodeId, score\n        |RETURN nodeId AS nodeId, max(score) AS `MAX(score)`, min(score) AS `MIN(score)`, count(score) AS `COUNT(score)`, count(DISTINCT score) AS `COUNT(DISTINCT score)`, sum(score) AS `SUM(score)`, sum(DISTINCT score) AS `SUM(DISTINCT score)`\"\"\"\n        .stripMargin\n        .replaceAll(\"\\n\", \" \")\n    )\n  }\n\n}\n"
  },
  {
    "path": "common/src/test/scala/org/neo4j/spark/service/Neo4jQueryServiceTest.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark.service\n\nimport junitparams.JUnitParamsRunner\nimport junitparams.Parameters\nimport org.apache.spark.sql.SaveMode\nimport org.apache.spark.sql.connector.expressions.Expression\nimport org.apache.spark.sql.connector.expressions.NullOrdering\nimport org.apache.spark.sql.connector.expressions.SortDirection\nimport org.apache.spark.sql.connector.expressions.SortOrder\nimport org.apache.spark.sql.connector.expressions.aggregate.Count\nimport org.apache.spark.sql.connector.expressions.aggregate.Max\nimport org.apache.spark.sql.connector.expressions.aggregate.Min\nimport org.apache.spark.sql.connector.expressions.aggregate.Sum\nimport org.apache.spark.sql.sources._\nimport org.junit.Assert._\nimport org.junit.Test\nimport org.junit.runner.RunWith\nimport org.neo4j.caniuse.Neo4j\nimport org.neo4j.caniuse.Neo4jDeploymentType.SELF_MANAGED\nimport org.neo4j.caniuse.Neo4jEdition\nimport org.neo4j.caniuse.Neo4jEdition.COMMUNITY\nimport org.neo4j.caniuse.Neo4jEdition.ENTERPRISE\nimport org.neo4j.caniuse.Neo4jVersion\nimport org.neo4j.spark.config.TopN\nimport org.neo4j.spark.util.DummyNamedReference\nimport org.neo4j.spark.util.Neo4jImplicits.CypherImplicits\nimport org.neo4j.spark.util.Neo4jOptions\nimport org.neo4j.spark.util.QueryType\n\nimport scala.collection.immutable.HashMap\n\n@RunWith(classOf[JUnitParamsRunner])\nclass Neo4jQueryServiceTest {\n\n  @Test\n  @Parameters(method = \"versions_and_prefixes\")\n  def testNodeOneLabel(neo4j: Neo4j, prefix: String): Unit = {\n    val options: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    options.put(Neo4jOptions.URL, \"bolt://localhost\")\n    options.put(QueryType.LABELS.toString.toLowerCase, \"Person\")\n    val neo4jOptions: Neo4jOptions = new Neo4jOptions(options)\n\n    val query: String = new Neo4jQueryService(neo4jOptions, new Neo4jQueryReadStrategy(neo4j)).createQuery()\n\n    assertEquals(s\"${prefix}MATCH (n:`Person`) RETURN n\", query)\n  }\n\n  @Test\n  @Parameters(method = \"versions_and_prefixes\")\n  def testNodeMultipleLabels(neo4j: Neo4j, prefix: String): Unit = {\n    val options: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    options.put(Neo4jOptions.URL, \"bolt://localhost\")\n    options.put(QueryType.LABELS.toString.toLowerCase, \":Person:Player:Midfield\")\n    val neo4jOptions: Neo4jOptions = new Neo4jOptions(options)\n\n    val query: String = new Neo4jQueryService(neo4jOptions, new Neo4jQueryReadStrategy(neo4j)).createQuery()\n\n    assertEquals(s\"${prefix}MATCH (n:`Person`:`Player`:`Midfield`) RETURN n\", query)\n  }\n\n  @Test\n  @Parameters(method = \"versions_and_prefixes\")\n  def testNodeMultipleLabelsWithPartitions(neo4j: Neo4j, prefix: String): Unit = {\n    val options: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    options.put(Neo4jOptions.URL, \"bolt://localhost\")\n    options.put(QueryType.LABELS.toString.toLowerCase, \":Person:Player:Midfield\")\n    val neo4jOptions: Neo4jOptions = new Neo4jOptions(options)\n\n    val query: String = new Neo4jQueryService(\n      neo4jOptions,\n      new Neo4jQueryReadStrategy(\n        neo4j,\n        partitionPagination = PartitionPagination(0, 0, TopN(100))\n      )\n    ).createQuery()\n\n    assertEquals(s\"${prefix}MATCH (n:`Person`:`Player`:`Midfield`) RETURN n LIMIT 100\", query)\n  }\n\n  @Test\n  @Parameters(method = \"versions_and_prefixes\")\n  def testNodeOneLabelWithOneSelectedColumn(neo4j: Neo4j, prefix: String): Unit = {\n    val options: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    options.put(Neo4jOptions.URL, \"bolt://localhost\")\n    options.put(QueryType.LABELS.toString.toLowerCase, \"Person\")\n    val neo4jOptions: Neo4jOptions = new Neo4jOptions(options)\n\n    val query: String = new Neo4jQueryService(\n      neo4jOptions,\n      new Neo4jQueryReadStrategy(neo4j, Array.empty[Filter], PartitionPagination.EMPTY, Seq(\"name\"))\n    ).createQuery()\n\n    assertEquals(s\"${prefix}MATCH (n:`Person`) RETURN n.name AS name\", query)\n  }\n\n  @Test\n  @Parameters(method = \"versions_and_prefixes\")\n  def testNodeOneLabelWithMultipleColumnSelected(neo4j: Neo4j, prefix: String): Unit = {\n    val options: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    options.put(Neo4jOptions.URL, \"bolt://localhost\")\n    options.put(QueryType.LABELS.toString.toLowerCase, \"Person\")\n    val neo4jOptions: Neo4jOptions = new Neo4jOptions(options)\n\n    val query: String = new Neo4jQueryService(\n      neo4jOptions,\n      new Neo4jQueryReadStrategy(neo4j, Array.empty[Filter], PartitionPagination.EMPTY, List(\"name\", \"bornDate\"))\n    ).createQuery()\n\n    assertEquals(s\"${prefix}MATCH (n:`Person`) RETURN n.name AS name, n.bornDate AS bornDate\", query)\n  }\n\n  @Test\n  @Parameters(method = \"versions_and_prefixes\")\n  def testNodeOneLabelWithInternalIdSelected(neo4j: Neo4j, prefix: String): Unit = {\n    val options: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    options.put(Neo4jOptions.URL, \"bolt://localhost\")\n    options.put(QueryType.LABELS.toString.toLowerCase, \"Person\")\n    val neo4jOptions: Neo4jOptions = new Neo4jOptions(options)\n\n    val query: String = new Neo4jQueryService(\n      neo4jOptions,\n      new Neo4jQueryReadStrategy(neo4j, Array.empty[Filter], PartitionPagination.EMPTY, List(\"<id>\"))\n    ).createQuery()\n\n    assertEquals(s\"${prefix}MATCH (n:`Person`) RETURN id(n) AS `<id>`\", query)\n  }\n\n  @Test\n  @Parameters(method = \"versions_and_prefixes\")\n  def testNodeFilterEqualTo(neo4j: Neo4j, prefix: String): Unit = {\n    val options: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    options.put(Neo4jOptions.URL, \"bolt://localhost\")\n    options.put(QueryType.LABELS.toString.toLowerCase, \"Person\")\n    val neo4jOptions: Neo4jOptions = new Neo4jOptions(options)\n\n    val filters: Array[Filter] = Array[Filter](\n      EqualTo(\"name\", \"John Doe\")\n    )\n\n    val query: String = new Neo4jQueryService(neo4jOptions, new Neo4jQueryReadStrategy(neo4j, filters)).createQuery()\n\n    val paramName = \"$\" + \"name\".toParameterName(\"John Doe\")\n\n    assertEquals(s\"${prefix}MATCH (n:`Person`) WHERE n.name = $paramName RETURN n\", query)\n  }\n\n  @Test\n  @Parameters(method = \"versions_and_prefixes\")\n  def testNodeFilterEqualNullSafe(neo4j: Neo4j, prefix: String): Unit = {\n    val options: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    options.put(Neo4jOptions.URL, \"bolt://localhost\")\n    options.put(QueryType.LABELS.toString.toLowerCase, \"Person\")\n    val neo4jOptions: Neo4jOptions = new Neo4jOptions(options)\n\n    val filters: Array[Filter] = Array[Filter](\n      EqualNullSafe(\"name\", \"John Doe\"),\n      EqualTo(\"age\", 36)\n    )\n\n    val query: String = new Neo4jQueryService(neo4jOptions, new Neo4jQueryReadStrategy(neo4j, filters)).createQuery()\n\n    val nameParameterName = \"$\" + \"name\".toParameterName(\"John Doe\")\n    val ageParameterName = \"$\" + \"age\".toParameterName(36)\n\n    assertEquals(\n      s\"\"\"${prefix}MATCH (n:`Person`)\n         | WHERE (((n.name IS NULL AND $nameParameterName IS NULL)\n         | OR n.name = $nameParameterName) AND n.age = $ageParameterName)\n         | RETURN n\"\"\".stripMargin.replaceAll(\"\\n\", \"\"),\n      query\n    )\n  }\n\n  @Test\n  @Parameters(method = \"versions_and_prefixes\")\n  def testNodeFilterEqualNullSafeWithNullValue(neo4j: Neo4j, prefix: String): Unit = {\n    val options: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    options.put(Neo4jOptions.URL, \"bolt://localhost\")\n    options.put(QueryType.LABELS.toString.toLowerCase, \"Person\")\n    val neo4jOptions: Neo4jOptions = new Neo4jOptions(options)\n\n    val filters: Array[Filter] = Array[Filter](\n      EqualNullSafe(\"name\", null),\n      EqualTo(\"age\", 36)\n    )\n\n    val query: String = new Neo4jQueryService(neo4jOptions, new Neo4jQueryReadStrategy(neo4j, filters)).createQuery()\n\n    val nameParameterName = \"$\" + \"name\".toParameterName(null)\n    val ageParameterName = \"$\" + \"age\".toParameterName(36)\n\n    assertEquals(\n      s\"${prefix}MATCH (n:`Person`) WHERE (((n.name IS NULL AND $nameParameterName IS NULL) OR n.name = $nameParameterName) AND n.age = $ageParameterName) RETURN n\",\n      query\n    )\n  }\n\n  @Test\n  @Parameters(method = \"versions_and_prefixes\")\n  def testNodeFilterStartsEndsWith(neo4j: Neo4j, prefix: String): Unit = {\n    val options: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    options.put(Neo4jOptions.URL, \"bolt://localhost\")\n    options.put(QueryType.LABELS.toString.toLowerCase, \"Person\")\n    val neo4jOptions: Neo4jOptions = new Neo4jOptions(options)\n\n    val filters: Array[Filter] = Array[Filter](\n      StringStartsWith(\"name\", \"Person Name\"),\n      StringEndsWith(\"name\", \"Person Surname\")\n    )\n\n    val query: String = new Neo4jQueryService(neo4jOptions, new Neo4jQueryReadStrategy(neo4j, filters)).createQuery()\n\n    val nameOneParameterName = \"$\" + \"name\".toParameterName(\"Person Name\")\n    val nameTwoParameterName = \"$\" + \"name\".toParameterName(\"Person Surname\")\n\n    assertEquals(\n      s\"\"\"${prefix}MATCH (n:`Person`)\n         | WHERE (n.name STARTS WITH $nameOneParameterName\n         | AND n.name ENDS WITH $nameTwoParameterName)\n         | RETURN n\"\"\".stripMargin.replaceAll(\"\\n\", \"\"),\n      query\n    )\n  }\n\n  @Test\n  @Parameters(method = \"versions_and_prefixes\")\n  def testRelationshipWithOneColumnSelected(neo4j: Neo4j, prefix: String): Unit = {\n    val options: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    options.put(Neo4jOptions.URL, \"bolt://localhost\")\n    options.put(\"relationship\", \"KNOWS\")\n    options.put(\"relationship.nodes.map\", \"false\")\n    options.put(\"relationship.source.labels\", \"Person\")\n    options.put(\"relationship.target.labels\", \"Person\")\n    val neo4jOptions: Neo4jOptions = new Neo4jOptions(options)\n\n    val query: String = new Neo4jQueryService(\n      neo4jOptions,\n      new Neo4jQueryReadStrategy(\n        neo4j,\n        Array.empty[Filter],\n        PartitionPagination.EMPTY,\n        List(\"source.name\")\n      )\n    ).createQuery()\n\n    assertEquals(\n      s\"${prefix}MATCH (source:`Person`) \" +\n        \"MATCH (target:`Person`) \" +\n        \"MATCH (source)-[rel:`KNOWS`]->(target) RETURN source.name AS `source.name`\",\n      query\n    )\n  }\n\n  @Test\n  @Parameters(method = \"versions_and_prefixes\")\n  def testRelationshipWithMoreColumnSelected(neo4j: Neo4j, prefix: String): Unit = {\n    val options: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    options.put(Neo4jOptions.URL, \"bolt://localhost\")\n    options.put(\"relationship\", \"KNOWS\")\n    options.put(\"relationship.nodes.map\", \"false\")\n    options.put(\"relationship.source.labels\", \"Person\")\n    options.put(\"relationship.target.labels\", \"Person\")\n    val neo4jOptions: Neo4jOptions = new Neo4jOptions(options)\n\n    val query: String = new Neo4jQueryService(\n      neo4jOptions,\n      new Neo4jQueryReadStrategy(\n        neo4j,\n        Array.empty[Filter],\n        PartitionPagination.EMPTY,\n        List(\"source.name\", \"<source.id>\")\n      )\n    ).createQuery()\n\n    assertEquals(\n      s\"${prefix}MATCH (source:`Person`) \" +\n        \"MATCH (target:`Person`) \" +\n        \"MATCH (source)-[rel:`KNOWS`]->(target) RETURN source.name AS `source.name`, id(source) AS `<source.id>`\",\n      query\n    )\n  }\n\n  @Test\n  @Parameters(method = \"versions_and_prefixes\")\n  def testRelationshipWithMoreColumnSelectedWithPartitions(neo4j: Neo4j, prefix: String): Unit = {\n    val options: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    options.put(Neo4jOptions.URL, \"bolt://localhost\")\n    options.put(\"relationship\", \"KNOWS\")\n    options.put(\"relationship.nodes.map\", \"false\")\n    options.put(\"relationship.source.labels\", \"Person\")\n    options.put(\"relationship.target.labels\", \"Person\")\n    val neo4jOptions: Neo4jOptions = new Neo4jOptions(options)\n\n    val query: String = new Neo4jQueryService(\n      neo4jOptions,\n      new Neo4jQueryReadStrategy(\n        neo4j,\n        Array.empty[Filter],\n        PartitionPagination(0, 0, TopN(limit = 100)),\n        List(\"source.name\", \"<source.id>\")\n      )\n    ).createQuery()\n\n    assertEquals(\n      s\"\"\"${prefix}MATCH (source:`Person`)\n         |MATCH (target:`Person`)\n         |MATCH (source)-[rel:`KNOWS`]->(target)\n         |RETURN source.name AS `source.name`, id(source) AS `<source.id>`\n         |LIMIT 100\"\"\"\n        .stripMargin\n        .replace(System.lineSeparator(), \" \"),\n      query\n    )\n  }\n\n  @Test\n  @Parameters(method = \"versions_and_prefixes\")\n  def testRelationshipWithMoreColumnsSelected(neo4j: Neo4j, prefix: String): Unit = {\n    val options: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    options.put(Neo4jOptions.URL, \"bolt://localhost\")\n    options.put(\"relationship\", \"KNOWS\")\n    options.put(\"relationship.nodes.map\", \"false\")\n    options.put(\"relationship.source.labels\", \"Person\")\n    options.put(\"relationship.target.labels\", \"Person\")\n    val neo4jOptions: Neo4jOptions = new Neo4jOptions(options)\n\n    val query: String = new Neo4jQueryService(\n      neo4jOptions,\n      new Neo4jQueryReadStrategy(\n        neo4j,\n        Array.empty[Filter],\n        PartitionPagination.EMPTY,\n        List(\"source.name\", \"source.id\", \"rel.someprops\", \"target.date\")\n      )\n    ).createQuery()\n\n    assertEquals(\n      s\"${prefix}MATCH (source:`Person`) \" +\n        \"MATCH (target:`Person`) \" +\n        \"MATCH (source)-[rel:`KNOWS`]->(target) RETURN source.name AS `source.name`, source.id AS `source.id`, rel.someprops AS `rel.someprops`, target.date AS `target.date`\",\n      query\n    )\n  }\n\n  @Test\n  @Parameters(method = \"versions_and_prefixes\")\n  def testRelationshipFilterEqualTo(neo4j: Neo4j, prefix: String): Unit = {\n    val options: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    options.put(Neo4jOptions.URL, \"bolt://localhost\")\n    options.put(\"relationship\", \"KNOWS\")\n    options.put(\"relationship.nodes.map\", \"false\")\n    options.put(\"relationship.source.labels\", \"Person\")\n    options.put(\"relationship.target.labels\", \"Person\")\n    val neo4jOptions: Neo4jOptions = new Neo4jOptions(options)\n\n    val filters: Array[Filter] = Array[Filter](\n      EqualTo(\"source.name\", \"John Doe\")\n    )\n\n    val query: String = new Neo4jQueryService(neo4jOptions, new Neo4jQueryReadStrategy(neo4j, filters)).createQuery()\n\n    val parameterName = \"$\" + \"source.name\".toParameterName(\"John Doe\")\n\n    assertEquals(\n      s\"${prefix}MATCH (source:`Person`) \" +\n        \"MATCH (target:`Person`) \" +\n        s\"MATCH (source)-[rel:`KNOWS`]->(target) WHERE source.name = $parameterName RETURN rel, source AS source, target AS target\",\n      query\n    )\n  }\n\n  @Test\n  @Parameters(method = \"versions_and_prefixes\")\n  def testRelationshipFilterNotEqualTo(neo4j: Neo4j, prefix: String): Unit = {\n    val options: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    options.put(Neo4jOptions.URL, \"bolt://localhost\")\n    options.put(\"relationship\", \"KNOWS\")\n    options.put(\"relationship.nodes.map\", \"false\")\n    options.put(\"relationship.source.labels\", \"Person\")\n    options.put(\"relationship.target.labels\", \"Person\")\n    val neo4jOptions: Neo4jOptions = new Neo4jOptions(options)\n\n    val filters: Array[Filter] = Array[Filter](\n      Or(EqualTo(\"source.name\", \"John Doe\"), EqualTo(\"target.name\", \"John Doe\"))\n    )\n\n    val query: String = new Neo4jQueryService(neo4jOptions, new Neo4jQueryReadStrategy(neo4j, filters)).createQuery()\n\n    val paramOneName = \"$\" + \"source.name\".toParameterName(\"John Doe\")\n    val paramTwoName = \"$\" + \"target.name\".toParameterName(\"John Doe\")\n\n    assertEquals(\n      s\"${prefix}MATCH (source:`Person`) \" +\n        \"MATCH (target:`Person`) \" +\n        s\"MATCH (source)-[rel:`KNOWS`]->(target) WHERE (source.name = $paramOneName OR target.name = $paramTwoName) RETURN rel, source AS source, target AS target\",\n      query\n    )\n  }\n\n  @Test\n  @Parameters(method = \"versions_and_prefixes\")\n  def testRelationshipAndFilterEqualTo(neo4j: Neo4j, prefix: String): Unit = {\n    val options: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    options.put(Neo4jOptions.URL, \"bolt://localhost\")\n    options.put(\"relationship\", \"KNOWS\")\n    options.put(\"relationship.nodes.map\", \"true\")\n    options.put(\"relationship.source.labels\", \"Person\")\n    options.put(\"relationship.target.labels\", \"Person\")\n    val neo4jOptions: Neo4jOptions = new Neo4jOptions(options)\n\n    val filters: Array[Filter] = Array[Filter](\n      EqualTo(\"source.id\", \"14\"),\n      EqualTo(\"target.id\", \"16\")\n    )\n\n    val query: String = new Neo4jQueryService(neo4jOptions, new Neo4jQueryReadStrategy(neo4j, filters)).createQuery()\n\n    val sourceIdParameterName = \"$\" + \"source.id\".toParameterName(14)\n    val targetIdParameterName = \"$\" + \"target.id\".toParameterName(16)\n\n    assertEquals(\n      s\"\"\"${prefix}MATCH (source:`Person`)\n         | MATCH (target:`Person`)\n         | MATCH (source)-[rel:`KNOWS`]->(target)\n         | WHERE (source.id = $sourceIdParameterName AND target.id = $targetIdParameterName)\n         | RETURN rel, source AS source, target AS target\n         |\"\"\".stripMargin.replaceAll(\"\\n\", \"\"),\n      query\n    )\n  }\n\n  @Test\n  @Parameters(method = \"versions_and_prefixes\")\n  def testComplexNodeConditions(neo4j: Neo4j, prefix: String): Unit = {\n    val options: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    options.put(Neo4jOptions.URL, \"bolt://localhost\")\n    options.put(\"labels\", \"Person\")\n    val neo4jOptions: Neo4jOptions = new Neo4jOptions(options)\n\n    val filters: Array[Filter] = Array[Filter](\n      Or(EqualTo(\"name\", \"John Doe\"), EqualTo(\"name\", \"John Scofield\")),\n      Or(EqualTo(\"age\", 15), GreaterThanOrEqual(\"age\", 18)),\n      Or(Not(EqualTo(\"age\", 22)), Not(LessThan(\"age\", 11)))\n    )\n\n    val query: String = new Neo4jQueryService(neo4jOptions, new Neo4jQueryReadStrategy(neo4j, filters)).createQuery()\n\n    val parameterNames: Map[String, String] = HashMap(\n      \"name_1\" -> \"$\".concat(\"name\".toParameterName(\"John Doe\")),\n      \"name_2\" -> \"$\".concat(\"name\".toParameterName(\"John Scofield\")),\n      \"age_1\" -> \"$\".concat(\"age\".toParameterName(15)),\n      \"age_2\" -> \"$\".concat(\"age\".toParameterName(18)),\n      \"age_3\" -> \"$\".concat(\"age\".toParameterName(22)),\n      \"age_4\" -> \"$\".concat(\"age\".toParameterName(11))\n    )\n\n    assertEquals(\n      s\"\"\"${prefix}MATCH (n:`Person`)\n         | WHERE (((n.name = ${parameterNames(\"name_1\")} OR n.name = ${parameterNames(\"name_2\")})\n         | AND (n.age = ${parameterNames(\"age_1\")} OR n.age >= ${parameterNames(\"age_2\")}))\n         | AND (NOT (n.age = ${parameterNames(\"age_3\")}) OR NOT (n.age < ${parameterNames(\"age_4\")})))\n         | RETURN n\"\"\".stripMargin.replaceAll(\"\\n\", \"\"),\n      query\n    )\n  }\n\n  @Test\n  @Parameters(method = \"versions_and_prefixes\")\n  def testRelationshipFilterComplexConditionsNoMap(neo4j: Neo4j, prefix: String): Unit = {\n    val options: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    options.put(Neo4jOptions.URL, \"bolt://localhost\")\n    options.put(\"relationship\", \"KNOWS\")\n    options.put(\"relationship.nodes.map\", \"false\")\n    options.put(\"relationship.source.labels\", \"Person\")\n    options.put(\"relationship.target.labels\", \"Person:Customer\")\n    val neo4jOptions: Neo4jOptions = new Neo4jOptions(options)\n\n    val filters: Array[Filter] = Array[Filter](\n      Or(\n        Or(EqualTo(\"source.name\", \"John Doe\"), EqualTo(\"target.name\", \"John Doraemon\")),\n        EqualTo(\"source.name\", \"Jane Doe\")\n      ),\n      Or(EqualTo(\"target.age\", 34), EqualTo(\"target.age\", 18)),\n      EqualTo(\"rel.score\", 12)\n    )\n\n    val query: String = new Neo4jQueryService(neo4jOptions, new Neo4jQueryReadStrategy(neo4j, filters)).createQuery()\n\n    val parameterNames = Map(\n      \"source.name_1\" -> \"$\".concat(\"source.name\".toParameterName(\"John Doe\")),\n      \"target.name_1\" -> \"$\".concat(\"target.name\".toParameterName(\"John Doraemon\")),\n      \"source.name_2\" -> \"$\".concat(\"source.name\".toParameterName(\"Jane Doe\")),\n      \"target.age_1\" -> \"$\".concat(\"target.age\".toParameterName(34)),\n      \"target.age_2\" -> \"$\".concat(\"target.age\".toParameterName(18)),\n      \"rel.score\" -> \"$\".concat(\"rel.score\".toParameterName(12))\n    )\n\n    assertEquals(\n      s\"\"\"${prefix}MATCH (source:`Person`)\n         | MATCH (target:`Person`:`Customer`)\n         | MATCH (source)-[rel:`KNOWS`]->(target)\n         | WHERE ((source.name = ${parameterNames(\"source.name_1\")} OR target.name = ${\n          parameterNames(\n            \"target.name_1\"\n          )\n        } OR source.name = ${parameterNames(\"source.name_2\")})\n         | AND (target.age = ${parameterNames(\"target.age_1\")} OR target.age = ${parameterNames(\"target.age_2\")})\n         | AND rel.score = ${parameterNames(\"rel.score\")})\n         | RETURN rel, source AS source, target AS target\"\"\".stripMargin.replaceAll(\"\\n\", \"\"),\n      query\n    )\n  }\n\n  @Test\n  @Parameters(method = \"versions_and_prefixes\")\n  def testRelationshipFilterComplexConditionsWithMap(neo4j: Neo4j, prefix: String): Unit = {\n    val options: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    options.put(Neo4jOptions.URL, \"bolt://localhost\")\n    options.put(\"relationship\", \"KNOWS\")\n    options.put(\"relationship.nodes.map\", \"true\")\n    options.put(\"relationship.source.labels\", \"Person\")\n    options.put(\"relationship.target.labels\", \"Person:Customer\")\n    val neo4jOptions: Neo4jOptions = new Neo4jOptions(options)\n\n    val filters: Array[Filter] = Array[Filter](\n      Or(\n        Or(EqualTo(\"source.name\", \"John Doe\"), EqualTo(\"target.name\", \"John Doraemon\")),\n        EqualTo(\"source.name\", \"Jane Doe\")\n      ),\n      Or(EqualTo(\"target.age\", 34), EqualTo(\"target.age\", 18)),\n      EqualTo(\"rel.score\", 12)\n    )\n\n    val query: String = new Neo4jQueryService(neo4jOptions, new Neo4jQueryReadStrategy(neo4j, filters)).createQuery()\n\n    val parameterNames = Map(\n      \"source.name_1\" -> \"$\".concat(\"source.name\".toParameterName(\"John Doe\")),\n      \"target.name_1\" -> \"$\".concat(\"target.name\".toParameterName(\"John Doraemon\")),\n      \"source.name_2\" -> \"$\".concat(\"source.name\".toParameterName(\"Jane Doe\")),\n      \"target.age_1\" -> \"$\".concat(\"target.age\".toParameterName(34)),\n      \"target.age_2\" -> \"$\".concat(\"target.age\".toParameterName(18)),\n      \"rel.score\" -> \"$\".concat(\"rel.score\".toParameterName(12))\n    )\n\n    assertEquals(\n      s\"\"\"${prefix}MATCH (source:`Person`)\n         | MATCH (target:`Person`:`Customer`)\n         | MATCH (source)-[rel:`KNOWS`]->(target)\n         | WHERE ((source.name = ${parameterNames(\"source.name_1\")} OR target.name = ${\n          parameterNames(\n            \"target.name_1\"\n          )\n        } OR source.name = ${parameterNames(\"source.name_2\")})\n         | AND (target.age = ${parameterNames(\"target.age_1\")} OR target.age = ${parameterNames(\"target.age_2\")})\n         | AND rel.score = ${parameterNames(\"rel.score\")})\n         | RETURN rel, source AS source, target AS target\n         |\"\"\".stripMargin.replaceAll(\"\\n\", \"\"),\n      query\n    )\n  }\n\n  @Test\n  @Parameters(method = \"versions_and_prefixes\")\n  def testCompoundKeysForNodes(neo4j: Neo4j, prefix: String): Unit = {\n    val options: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    options.put(Neo4jOptions.URL, \"bolt://localhost\")\n    options.put(\"labels\", \"Location\")\n    options.put(\"node.keys\", \"LocationName:name,LocationType:type,FeatureID:featureId\")\n    val neo4jOptions: Neo4jOptions = new Neo4jOptions(options)\n\n    val query: String =\n      new Neo4jQueryService(neo4jOptions, new Neo4jQueryWriteStrategy(neo4j, SaveMode.Overwrite)).createQuery()\n\n    assertEquals(\n      s\"\"\"${prefix}UNWIND $$events AS event\n         |MERGE (node:Location {name: event.keys.name, type: event.keys.type, featureId: event.keys.featureId})\n         |SET node += event.properties\n         |\"\"\".stripMargin,\n      query\n    )\n  }\n\n  @Test\n  @Parameters(method = \"versions_and_prefixes\")\n  def testCompoundKeysForRelationship(neo4j: Neo4j, prefix: String): Unit = {\n    val options: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    options.put(Neo4jOptions.URL, \"bolt://localhost\")\n    options.put(\"relationship\", \"BOUGHT\")\n    options.put(\"relationship.source.labels\", \"Person\")\n    options.put(\"relationship.source.node.keys\", \"FirstName:name,LastName:lastName\")\n    options.put(\"relationship.target.labels\", \"Product\")\n    options.put(\"relationship.target.node.keys\", \"ProductPrice:price,ProductId:id\")\n\n    val neo4jOptions: Neo4jOptions = new Neo4jOptions(options)\n\n    val query: String =\n      new Neo4jQueryService(neo4jOptions, new Neo4jQueryWriteStrategy(neo4j, SaveMode.Overwrite)).createQuery()\n\n    assertEquals(\n      s\"\"\"${prefix}UNWIND $$events AS event\n         |MATCH (source:Person {name: event.source.keys.name, lastName: event.source.keys.lastName})\n         |MATCH (target:Product {price: event.target.keys.price, id: event.target.keys.id})\n         |MERGE (source)-[rel:BOUGHT]->(target)\n         |SET rel += event.rel.properties\n         |\"\"\".stripMargin,\n      query.stripMargin\n    )\n  }\n\n  @Test\n  @Parameters(method = \"versions_and_prefixes\")\n  def testCompoundKeysForRelationshipMergeMatch(neo4j: Neo4j, prefix: String): Unit = {\n    val options: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    options.put(Neo4jOptions.URL, \"bolt://localhost\")\n    options.put(\"relationship\", \"BOUGHT\")\n    options.put(\"relationship.source.labels\", \"Person\")\n    options.put(\"relationship.source.node.keys\", \"FirstName:name,LastName:lastName\")\n    options.put(\"relationship.source.save.mode\", \"Overwrite\")\n    options.put(\"relationship.target.labels\", \"Product\")\n    options.put(\"relationship.target.node.keys\", \"ProductPrice:price,ProductId:id\")\n    options.put(\"relationship.target.save.mode\", \"match\")\n\n    val neo4jOptions: Neo4jOptions = new Neo4jOptions(options)\n\n    val query: String =\n      new Neo4jQueryService(neo4jOptions, new Neo4jQueryWriteStrategy(neo4j, SaveMode.Overwrite)).createQuery()\n\n    assertEquals(\n      s\"\"\"${prefix}UNWIND $$events AS event\n         |MERGE (source:Person {name: event.source.keys.name, lastName: event.source.keys.lastName}) SET source += event.source.properties\n         |WITH source, event\n         |MATCH (target:Product {price: event.target.keys.price, id: event.target.keys.id})\n         |MERGE (source)-[rel:BOUGHT]->(target)\n         |SET rel += event.rel.properties\n         |\"\"\".stripMargin,\n      query.stripMargin\n    )\n  }\n\n  @Test\n  @Parameters(method = \"versions_and_prefixes\")\n  def testShouldDoSumAggregationOnLabels(neo4j: Neo4j, prefix: String): Unit = {\n    val options: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    options.put(Neo4jOptions.URL, \"bolt://localhost\")\n    options.put(QueryType.LABELS.toString.toLowerCase, \"Person\")\n    val neo4jOptions: Neo4jOptions = new Neo4jOptions(options)\n\n    val ageField = new DummyNamedReference(\"age\")\n    var query: String = new Neo4jQueryService(\n      neo4jOptions,\n      new Neo4jQueryReadStrategy(\n        neo4j,\n        Array.empty[Filter],\n        PartitionPagination.EMPTY,\n        Seq(\"name\", \"SUM(DISTINCT age)\", \"SUM(age)\"),\n        Array(\n          new Sum(ageField, false),\n          new Sum(ageField, true)\n        )\n      )\n    ).createQuery()\n\n    assertEquals(\n      s\"${prefix}MATCH (n:`Person`) RETURN n.name AS name, sum(DISTINCT n.age) AS `SUM(DISTINCT age)`, sum(n.age) AS `SUM(age)`\",\n      query\n    )\n\n    val nameField = new DummyNamedReference(\"name\")\n    query = new Neo4jQueryService(\n      neo4jOptions,\n      new Neo4jQueryReadStrategy(\n        neo4j,\n        Array.empty[Filter],\n        PartitionPagination.EMPTY,\n        Seq(\"name\", \"COUNT(DISTINCT name)\", \"COUNT(name)\"),\n        Array(\n          new Count(nameField, false),\n          new Count(nameField, true)\n        )\n      )\n    ).createQuery()\n\n    assertEquals(\n      s\"${prefix}MATCH (n:`Person`) RETURN n.name AS name, count(DISTINCT n.name) AS `COUNT(DISTINCT name)`, count(n.name) AS `COUNT(name)`\",\n      query\n    )\n\n    query = new Neo4jQueryService(\n      neo4jOptions,\n      new Neo4jQueryReadStrategy(\n        neo4j,\n        Array.empty[Filter],\n        PartitionPagination.EMPTY,\n        Seq(\"name\", \"MAX(age)\", \"MIN(age)\"),\n        Array(\n          new Max(ageField),\n          new Min(ageField)\n        )\n      )\n    ).createQuery()\n\n    assertEquals(\n      s\"${prefix}MATCH (n:`Person`) RETURN n.name AS name, max(n.age) AS `MAX(age)`, min(n.age) AS `MIN(age)`\",\n      query\n    )\n  }\n\n  @Test\n  @Parameters(method = \"versions_and_prefixes\")\n  def testShouldDoSumAggregationOnRelationships(neo4j: Neo4j, prefix: String): Unit = {\n    val options: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    options.put(Neo4jOptions.URL, \"bolt://localhost\")\n    options.put(\"relationship\", \"BOUGHT\")\n    options.put(\"relationship.nodes.map\", \"false\")\n    options.put(\"relationship.source.labels\", \"Person\")\n    options.put(\"relationship.target.labels\", \"Product\")\n    val neo4jOptions: Neo4jOptions = new Neo4jOptions(options)\n\n    val targetPriceField = new DummyNamedReference(\"`target.price`\")\n    var query: String = new Neo4jQueryService(\n      neo4jOptions,\n      new Neo4jQueryReadStrategy(\n        neo4j,\n        Array.empty,\n        PartitionPagination.EMPTY,\n        List(\"source.fullName\", \"SUM(DISTINCT `target.price`)\", \"SUM(`target.price`)\"),\n        Array(\n          new Sum(targetPriceField, false),\n          new Sum(targetPriceField, true)\n        )\n      )\n    ).createQuery()\n\n    assertEquals(\n      s\"\"\"${prefix}MATCH (source:`Person`)\n         |MATCH (target:`Product`)\n         |MATCH (source)-[rel:`BOUGHT`]->(target)\n         |RETURN source.fullName AS `source.fullName`, sum(DISTINCT target.price) AS `SUM(DISTINCT ``target.price``)`, sum(target.price) AS `SUM(``target.price``)`\"\"\"\n        .stripMargin\n        .replaceAll(\"\\n\", \" \"),\n      query\n    )\n\n    val targetIdField = new DummyNamedReference(\"`target.id`\")\n    query = new Neo4jQueryService(\n      neo4jOptions,\n      new Neo4jQueryReadStrategy(\n        neo4j,\n        Array.empty,\n        PartitionPagination.EMPTY,\n        List(\"source.fullName\", \"COUNT(DISTINCT `target.id`)\", \"COUNT(`target.id`)\"),\n        Array(\n          new Count(targetIdField, false),\n          new Count(targetIdField, true)\n        )\n      )\n    ).createQuery()\n\n    assertEquals(\n      s\"\"\"${prefix}MATCH (source:`Person`) MATCH (target:`Product`)\n         |MATCH (source)-[rel:`BOUGHT`]->(target)\n         |RETURN source.fullName AS `source.fullName`, count(DISTINCT target.id) AS `COUNT(DISTINCT ``target.id``)`, count(target.id) AS `COUNT(``target.id``)`\"\"\"\n        .stripMargin\n        .replaceAll(\"\\n\", \" \"),\n      query\n    )\n\n    query = new Neo4jQueryService(\n      neo4jOptions,\n      new Neo4jQueryReadStrategy(\n        neo4j,\n        Array.empty,\n        PartitionPagination.EMPTY,\n        List(\"source.fullName\", \"MAX(`target.price`)\", \"MIN(`target.price`)\"),\n        Array(\n          new Max(targetPriceField),\n          new Min(targetPriceField)\n        )\n      )\n    ).createQuery()\n\n    assertEquals(\n      s\"\"\"${prefix}MATCH (source:`Person`)\n         |MATCH (target:`Product`)\n         |MATCH (source)-[rel:`BOUGHT`]->(target)\n         |RETURN source.fullName AS `source.fullName`, max(target.price) AS `MAX(``target.price``)`, min(target.price) AS `MIN(``target.price``)`\"\"\"\n        .stripMargin\n        .replaceAll(\"\\n\", \" \"),\n      query\n    )\n  }\n\n  @Test\n  @Parameters(method = \"versions_and_prefixes\")\n  def testTopNForLabels(neo4j: Neo4j, prefix: String): Unit = {\n    val options: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    options.put(Neo4jOptions.URL, \"bolt://localhost\")\n    options.put(QueryType.LABELS.toString.toLowerCase, \"Person\")\n    val neo4jOptions: Neo4jOptions = new Neo4jOptions(options)\n\n    val query: String = new Neo4jQueryService(\n      neo4jOptions,\n      new Neo4jQueryReadStrategy(\n        neo4j,\n        partitionPagination = PartitionPagination(\n          0,\n          0,\n          TopN(\n            42,\n            Array(new SortOrder {\n              override def expression(): Expression = new DummyNamedReference(\"name\")\n\n              override def direction(): SortDirection = SortDirection.ASCENDING\n\n              override def nullOrdering(): NullOrdering = direction().defaultNullOrdering()\n            })\n          )\n        )\n      )\n    ).createQuery()\n\n    assertEquals(s\"${prefix}MATCH (n:`Person`) RETURN n ORDER BY n.name ASC LIMIT 42\", query)\n  }\n\n  @Test\n  @Parameters(method = \"versions_and_prefixes\")\n  def testTopNForLabelsWithRequiredColumn(neo4j: Neo4j, prefix: String): Unit = {\n    val options: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    options.put(Neo4jOptions.URL, \"bolt://localhost\")\n    options.put(QueryType.LABELS.toString.toLowerCase, \"Person\")\n    val neo4jOptions: Neo4jOptions = new Neo4jOptions(options)\n\n    val query: String = new Neo4jQueryService(\n      neo4jOptions,\n      new Neo4jQueryReadStrategy(\n        neo4j,\n        requiredColumns = Array(\"name\"),\n        partitionPagination = PartitionPagination(\n          0,\n          0,\n          TopN(\n            42,\n            Array(new SortOrder {\n              override def expression(): Expression = new DummyNamedReference(\"name\")\n\n              override def direction(): SortDirection = SortDirection.ASCENDING\n\n              override def nullOrdering(): NullOrdering = direction().defaultNullOrdering()\n            })\n          )\n        )\n      )\n    ).createQuery()\n\n    assertEquals(s\"${prefix}MATCH (n:`Person`) RETURN n.name AS name ORDER BY n.name ASC LIMIT 42\", query)\n  }\n\n  @Test\n  @Parameters(method = \"versions_and_prefixes\")\n  def testTopNForRelationships(neo4j: Neo4j, prefix: String): Unit = {\n    val options: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    options.put(Neo4jOptions.URL, \"bolt://localhost\")\n    options.put(\"relationship\", \"KNOWS\")\n    options.put(\"relationship.nodes.map\", \"false\")\n    options.put(\"relationship.source.labels\", \"Person\")\n    options.put(\"relationship.target.labels\", \"Person\")\n    val neo4jOptions: Neo4jOptions = new Neo4jOptions(options)\n\n    val query: String = new Neo4jQueryService(\n      neo4jOptions,\n      new Neo4jQueryReadStrategy(\n        neo4j,\n        Array.empty[Filter],\n        PartitionPagination(\n          0,\n          0,\n          TopN(\n            24,\n            Array(new SortOrder {\n              override def expression(): Expression = new DummyNamedReference(\"rel.since\")\n\n              override def direction(): SortDirection = SortDirection.DESCENDING\n\n              override def nullOrdering(): NullOrdering = direction().defaultNullOrdering()\n            })\n          )\n        )\n      )\n    ).createQuery()\n\n    assertEquals(\n      s\"${prefix}MATCH (source:`Person`) \" +\n        \"MATCH (target:`Person`) \" +\n        \"MATCH (source)-[rel:`KNOWS`]->(target) RETURN rel, source AS source, target AS target \" +\n        \"ORDER BY rel.since DESC LIMIT 24\",\n      query\n    )\n  }\n\n  @Test\n  @Parameters(method = \"versions_and_prefixes\")\n  def testTopNForRelationshipWithOneRequiredColumn(neo4j: Neo4j, prefix: String): Unit = {\n    val options: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    options.put(Neo4jOptions.URL, \"bolt://localhost\")\n    options.put(\"relationship\", \"KNOWS\")\n    options.put(\"relationship.nodes.map\", \"false\")\n    options.put(\"relationship.source.labels\", \"Person\")\n    options.put(\"relationship.target.labels\", \"Person\")\n    val neo4jOptions: Neo4jOptions = new Neo4jOptions(options)\n\n    val query: String = new Neo4jQueryService(\n      neo4jOptions,\n      new Neo4jQueryReadStrategy(\n        neo4j,\n        Array.empty[Filter],\n        PartitionPagination(\n          0,\n          0,\n          TopN(\n            24,\n            Array(new SortOrder {\n              override def expression(): Expression = new DummyNamedReference(\"rel.since\")\n\n              override def direction(): SortDirection = SortDirection.DESCENDING\n\n              override def nullOrdering(): NullOrdering = direction().defaultNullOrdering()\n            })\n          )\n        ),\n        Array(\"source.name\")\n      )\n    ).createQuery()\n\n    assertEquals(\n      s\"\"\"${prefix}MATCH (source:`Person`)\n         |MATCH (target:`Person`)\n         |MATCH (source)-[rel:`KNOWS`]->(target) RETURN source.name AS `source.name`\n         |ORDER BY rel.since DESC LIMIT 24\"\"\"\n        .stripMargin\n        .replaceAll(\"\\n\", \" \"),\n      query\n    )\n  }\n\n  @Test\n  @Parameters(method = \"versions_and_prefixes\")\n  def testTopNForCustomQueryIgnoresAggregation(neo4j: Neo4j, ignored: String): Unit = {\n    val options: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    options.put(Neo4jOptions.URL, \"bolt://localhost\")\n    options.put(QueryType.QUERY.toString.toLowerCase, \"MATCH (p:Person) RETURN p\")\n    val neo4jOptions: Neo4jOptions = new Neo4jOptions(options)\n\n    val query: String = new Neo4jQueryService(\n      neo4jOptions,\n      new Neo4jQueryReadStrategy(\n        neo4j,\n        Array.empty[Filter],\n        PartitionPagination(\n          0,\n          0,\n          TopN(\n            24,\n            Array(new SortOrder {\n              override def expression(): Expression = new DummyNamedReference(\"name\")\n\n              override def direction(): SortDirection = SortDirection.DESCENDING\n\n              override def nullOrdering(): NullOrdering = direction().defaultNullOrdering()\n            })\n          )\n        )\n      )\n    ).createQuery()\n\n    assertEquals(\n      \"WITH $scriptResult AS scriptResult MATCH (p:Person) RETURN p SKIP 0 LIMIT 24\",\n      query\n    )\n  }\n\n  def versions_and_prefixes(): Array[Array[Any]] = {\n    Array(\n      Array(neo4j(version(4, 4), COMMUNITY), \"\"),\n      Array(neo4j(version(4, 4), ENTERPRISE), \"\"),\n      Array(neo4j(version(5, 0), COMMUNITY), \"\"),\n      Array(neo4j(version(5, 0), ENTERPRISE), \"\"),\n      Array(neo4j(version(5, 21), COMMUNITY), \"CYPHER 5 \"),\n      Array(neo4j(version(5, 21), ENTERPRISE), \"CYPHER 5 \"),\n      Array(neo4j(version(5, 26), COMMUNITY), \"CYPHER 5 \"),\n      Array(neo4j(version(5, 26), ENTERPRISE), \"CYPHER 5 \"),\n      Array(neo4j(version(2025, 1), COMMUNITY), \"CYPHER 5 \"),\n      Array(neo4j(version(2025, 1), ENTERPRISE), \"CYPHER 5 \")\n    )\n  }\n\n  def neo4j(version: Neo4jVersion, edition: Neo4jEdition): Neo4j = {\n    new Neo4j(version, edition, SELF_MANAGED)\n  }\n\n  def version(major: Int, minor: Int): Neo4jVersion = {\n    new Neo4jVersion(major, minor, 0)\n  }\n}\n"
  },
  {
    "path": "common/src/test/scala/org/neo4j/spark/service/SchemaServiceTSE.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark.service\n\nimport org.apache.spark.sql.types.DataTypes\nimport org.apache.spark.sql.types.StructField\nimport org.apache.spark.sql.types.StructType\nimport org.junit.Assert._\nimport org.junit.Before\nimport org.junit.FixMethodOrder\nimport org.junit.Test\nimport org.junit.runners.MethodSorters\nimport org.neo4j.Closeables.use\nimport org.neo4j.caniuse.Neo4j\nimport org.neo4j.caniuse.Neo4jDeploymentType\nimport org.neo4j.caniuse.Neo4jEdition\nimport org.neo4j.caniuse.Neo4jVersion\nimport org.neo4j.driver.Transaction\nimport org.neo4j.driver.TransactionWork\nimport org.neo4j.driver.summary.ResultSummary\nimport org.neo4j.spark.SparkConnectorScalaBaseTSE\nimport org.neo4j.spark.SparkConnectorScalaSuiteIT\nimport org.neo4j.spark.SparkConnectorScalaSuiteIT.neo4j\nimport org.neo4j.spark.converter.CypherToSparkTypeConverter\nimport org.neo4j.spark.util.DriverCache\nimport org.neo4j.spark.util.Neo4jOptions\nimport org.neo4j.spark.util.Neo4jUtil\nimport org.neo4j.spark.util.QueryType\n\nimport java.util\nimport java.util.UUID\n\n@FixMethodOrder(MethodSorters.JVM)\nclass SchemaServiceTSE extends SparkConnectorScalaBaseTSE {\n\n  @Before\n  def beforeEach(): Unit = {\n    use(SparkConnectorScalaSuiteIT.session(\"system\")) {\n      session =>\n        session.run(\"CREATE OR REPLACE DATABASE neo4j WAIT 30 seconds\")\n          .consume()\n    }\n  }\n\n  @Test\n  def testGetSchemaFromNodeBoolean(): Unit = {\n    initTest(\"CREATE (p:Person {is_hero: true})\")\n    val options: java.util.Map[String, String] = new util.HashMap[String, String]()\n    options.put(QueryType.LABELS.toString.toLowerCase, \"Person\")\n\n    val schema = getSchema(options)\n\n    assertEquals(getExpectedStructType(Seq(StructField(\"is_hero\", DataTypes.BooleanType))), schema)\n  }\n\n  @Test\n  def testGetSchemaFromNodeString(): Unit = {\n    initTest(\"CREATE (p:Person {name: 'John'})\")\n    val options: java.util.Map[String, String] = new util.HashMap[String, String]()\n    options.put(QueryType.LABELS.toString.toLowerCase, \"Person\")\n\n    val schema = getSchema(options)\n\n    assertEquals(getExpectedStructType(Seq(StructField(\"name\", DataTypes.StringType))), schema)\n  }\n\n  @Test\n  def testGetSchemaFromNodeLong(): Unit = {\n    initTest(\"CREATE (p:Person {age: 93})\")\n    val options: java.util.Map[String, String] = new util.HashMap[String, String]()\n    options.put(QueryType.LABELS.toString.toLowerCase, \"Person\")\n\n    val schema = getSchema(options)\n\n    assertEquals(getExpectedStructType(Seq(StructField(\"age\", DataTypes.LongType))), schema)\n  }\n\n  @Test\n  def testGetSchemaFromNodeDouble(): Unit = {\n    initTest(\"CREATE (p:Person {ratio: 43.120})\")\n    val options: java.util.Map[String, String] = new util.HashMap[String, String]()\n    options.put(QueryType.LABELS.toString.toLowerCase, \"Person\")\n\n    val schema = getSchema(options)\n\n    assertEquals(getExpectedStructType(Seq(StructField(\"ratio\", DataTypes.DoubleType))), schema)\n  }\n\n  @Test\n  def testGetSchemaFromNodePoint2D(): Unit = {\n    initTest(\"CREATE (p:Person {location: point({x: 12.32, y: 49.32})})\")\n    val options: java.util.Map[String, String] = new util.HashMap[String, String]()\n    options.put(QueryType.LABELS.toString.toLowerCase, \"Person\")\n\n    val schema = getSchema(options)\n\n    assertEquals(getExpectedStructType(Seq(StructField(\"location\", CypherToSparkTypeConverter.pointType))), schema)\n  }\n\n  @Test\n  def testGetSchemaFromDate(): Unit = {\n    initTest(\"CREATE (p:Person {born_on: date('1998-01-05')})\")\n    val options: java.util.Map[String, String] = new util.HashMap[String, String]()\n    options.put(QueryType.LABELS.toString.toLowerCase, \"Person\")\n\n    val schema = getSchema(options)\n\n    assertEquals(getExpectedStructType(Seq(StructField(\"born_on\", DataTypes.DateType))), schema)\n  }\n\n  @Test\n  def testGetSchemaFromDateTime(): Unit = {\n    initTest(\"CREATE (p:Person {arrived_at: datetime('1998-01-05')})\")\n    val options: java.util.Map[String, String] = new util.HashMap[String, String]()\n    options.put(QueryType.LABELS.toString.toLowerCase, \"Person\")\n\n    val schema = getSchema(options)\n\n    assertEquals(getExpectedStructType(Seq(StructField(\"arrived_at\", DataTypes.TimestampType))), schema)\n  }\n\n  @Test\n  def testGetSchemaFromTime(): Unit = {\n    initTest(\"CREATE (p:Person {arrived_at: time('125035.556+0100')})\")\n    val options: java.util.Map[String, String] = new util.HashMap[String, String]()\n    options.put(QueryType.LABELS.toString.toLowerCase, \"Person\")\n\n    val schema = getSchema(options)\n\n    assertEquals(getExpectedStructType(Seq(StructField(\"arrived_at\", CypherToSparkTypeConverter.timeType))), schema)\n  }\n\n  @Test\n  def testGetSchemaFromStringArray(): Unit = {\n    initTest(\"CREATE (p:Person {names: ['John', 'Doe']})\")\n    val options: java.util.Map[String, String] = new util.HashMap[String, String]()\n    options.put(QueryType.LABELS.toString.toLowerCase, \"Person\")\n\n    val schema = getSchema(options)\n\n    assertEquals(\n      getExpectedStructType(Seq(StructField(\"names\", DataTypes.createArrayType(DataTypes.StringType)))),\n      schema\n    )\n  }\n\n  @Test\n  def testGetSchemaFromDateArray(): Unit = {\n    initTest(\"CREATE (p:Person {names: [date('2019-11-19'), date('2019-11-20')]})\")\n    val options: java.util.Map[String, String] = new util.HashMap[String, String]()\n    options.put(QueryType.LABELS.toString.toLowerCase, \"Person\")\n\n    val schema = getSchema(options)\n\n    assertEquals(\n      getExpectedStructType(Seq(StructField(\"names\", DataTypes.createArrayType(DataTypes.DateType)))),\n      schema\n    )\n  }\n\n  @Test\n  def testGetSchemaFromTimestampArray(): Unit = {\n    initTest(\"CREATE (p:Person {dates: [datetime('2019-11-19'), datetime('2019-11-20')]})\")\n    val options: java.util.Map[String, String] = new util.HashMap[String, String]()\n    options.put(QueryType.LABELS.toString.toLowerCase, \"Person\")\n\n    val schema = getSchema(options)\n\n    assertEquals(\n      getExpectedStructType(Seq(StructField(\"dates\", DataTypes.createArrayType(DataTypes.TimestampType)))),\n      schema\n    )\n  }\n\n  @Test\n  def testGetSchemaFromTimeArray(): Unit = {\n    initTest(\"CREATE (p:Person {dates: [time('125035.556+0100'), time('125125.556+0100')]})\")\n    val options: java.util.Map[String, String] = new util.HashMap[String, String]()\n    options.put(QueryType.LABELS.toString.toLowerCase, \"Person\")\n\n    val schema = getSchema(options)\n\n    assertEquals(\n      getExpectedStructType(Seq(StructField(\"dates\", DataTypes.createArrayType(CypherToSparkTypeConverter.timeType)))),\n      schema\n    )\n  }\n\n  @Test\n  def testGetSchemaFromIntegerArray(): Unit = {\n    initTest(\"CREATE (p:Person {ages: [42, 101]})\")\n    val options: java.util.Map[String, String] = new util.HashMap[String, String]()\n    options.put(QueryType.LABELS.toString.toLowerCase, \"Person\")\n\n    val schema = getSchema(options)\n\n    assertEquals(getExpectedStructType(Seq(StructField(\"ages\", DataTypes.createArrayType(DataTypes.LongType)))), schema)\n  }\n\n  @Test\n  def testGetSchemaFromMultipleNodes(): Unit = {\n    initTest(\n      \"\"\"\n      CREATE (p1:Person {age: 31, name: 'Jane Doe'}),\n        (p2:Person {name: 'John Doe', age: 33, location: null}),\n        (p3:Person {age: 25, location: point({latitude: 12.12, longitude: 31.13})})\n    \"\"\"\n    )\n\n    val options: java.util.Map[String, String] = new util.HashMap[String, String]()\n    options.put(QueryType.LABELS.toString.toLowerCase, \"Person\")\n\n    val schema = getSchema(options)\n\n    assertEquals(\n      getExpectedStructType(Seq(\n        StructField(\"age\", DataTypes.LongType),\n        StructField(\"location\", CypherToSparkTypeConverter.pointType),\n        StructField(\"name\", DataTypes.StringType)\n      )),\n      schema\n    )\n  }\n\n  private def getExpectedStructType(structFields: Seq[StructField]): StructType = {\n    val additionalFields: Seq[StructField] = Seq(\n      StructField(Neo4jUtil.INTERNAL_LABELS_FIELD, DataTypes.createArrayType(DataTypes.StringType), nullable = true),\n      StructField(Neo4jUtil.INTERNAL_ID_FIELD, DataTypes.LongType, nullable = false)\n    )\n    StructType(structFields.union(additionalFields).reverse)\n  }\n\n  private def initTest(query: String): Unit = {\n    SparkConnectorScalaSuiteIT.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(query).consume()\n        }\n      )\n  }\n\n  private def getSchema(options: java.util.Map[String, String]): StructType = {\n    options.put(Neo4jOptions.URL, SparkConnectorScalaSuiteIT.server.getBoltUrl)\n    val neo4jOptions: Neo4jOptions = new Neo4jOptions(options)\n\n    val driverCache = new DriverCache(neo4jOptions.connection)\n    val schemaService: SchemaService = new SchemaService(neo4j, neo4jOptions, driverCache)\n\n    val schema: StructType = schemaService.struct()\n    schemaService.close()\n    driverCache.close()\n\n    schema\n  }\n}\n"
  },
  {
    "path": "common/src/test/scala/org/neo4j/spark/service/SchemaServiceTest.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark.service\n\nimport org.junit.Assert.assertEquals\nimport org.junit.Test\nimport org.mockito.Mockito.RETURNS_DEEP_STUBS\nimport org.mockito.Mockito.mock\nimport org.neo4j.caniuse.Neo4j\nimport org.neo4j.caniuse.Neo4jDeploymentType\nimport org.neo4j.caniuse.Neo4jEdition\nimport org.neo4j.caniuse.Neo4jVersion\nimport org.neo4j.spark.config.TopN\nimport org.neo4j.spark.util.DriverCache\nimport org.neo4j.spark.util.Neo4jOptions\n\nimport scala.annotation.nowarn\nimport scala.collection.JavaConverters\n\nclass SchemaServiceTest {\n\n  @Test\n  def does_not_overflow_when_partition_size_is_over_max_value_of_32bit_integers(): Unit = {\n    // note: _ cannot be used to separate digit groups, as this requires Scala 2.13+\n    val opts = options(\n      \"url\" -> \"bolt://example.com\",\n      \"partitions\" -> 2.toString,\n      \"query.count\" -> (2L * 2147483648L).toString, // 2 * (Integer.MAX_VALUE + 1)\n      \"query\" -> \"MERGE (:Node)\"\n    )\n    val schemaService = new SchemaService(neo4j(), opts, mock(classOf[DriverCache], RETURNS_DEEP_STUBS))\n\n    val pages = schemaService.skipLimitFromPartition(Some(TopN(1024)))\n\n    assertEquals(List(0, 1), pages.map(_.partitionNumber).toList)\n    assertEquals(List(0, 2147483648L), pages.map(_.skip).toList)\n    assertEquals(List(2147483648L, 2147483648L), pages.map(_.topN.limit).toList)\n    assertEquals(List(0, 0), pages.map(_.topN.orders.size).toList)\n  }\n\n  private def options(kv: (String, String)*): Neo4jOptions = {\n    new Neo4jOptions(\n      JavaConverters.mapAsJavaMap(kv.toMap)\n    )\n  }\n\n  private def neo4j(): Neo4j = {\n    new Neo4j(new Neo4jVersion(2025, 1, 0), Neo4jEdition.COMMUNITY, Neo4jDeploymentType.SELF_MANAGED)\n  }\n}\n"
  },
  {
    "path": "common/src/test/scala/org/neo4j/spark/service/SchemaServiceWithApocTSE.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark.service\n\nimport org.apache.spark.sql.types.DataTypes\nimport org.apache.spark.sql.types.StructField\nimport org.apache.spark.sql.types.StructType\nimport org.junit.Assert._\nimport org.junit.Before\nimport org.junit.FixMethodOrder\nimport org.junit.Test\nimport org.junit.runners.MethodSorters\nimport org.neo4j.Closeables.use\nimport org.neo4j.caniuse.Neo4j\nimport org.neo4j.caniuse.Neo4jDeploymentType\nimport org.neo4j.caniuse.Neo4jEdition\nimport org.neo4j.caniuse.Neo4jVersion\nimport org.neo4j.driver.Transaction\nimport org.neo4j.driver.TransactionWork\nimport org.neo4j.driver.summary.ResultSummary\nimport org.neo4j.spark.SparkConnectorScalaBaseWithApocTSE\nimport org.neo4j.spark.SparkConnectorScalaSuiteWithApocIT\nimport org.neo4j.spark.converter.CypherToSparkTypeConverter\nimport org.neo4j.spark.util.DriverCache\nimport org.neo4j.spark.util.Neo4jOptions\nimport org.neo4j.spark.util.Neo4jUtil\nimport org.neo4j.spark.util.QueryType\n\nimport java.util\nimport java.util.UUID\n\n@FixMethodOrder(MethodSorters.JVM)\nclass SchemaServiceWithApocTSE extends SparkConnectorScalaBaseWithApocTSE {\n\n  @Before\n  def beforeEach(): Unit = {\n    use(SparkConnectorScalaSuiteWithApocIT.session(\"system\")) {\n      session =>\n        session.run(\"CREATE OR REPLACE DATABASE neo4j WAIT 30 seconds\")\n          .consume()\n    }\n  }\n\n  @Test\n  def testGetSchemaFromNodeBoolean(): Unit = {\n    initTest(\"CREATE (p:Person {is_hero: true})\")\n    val options: java.util.Map[String, String] = new util.HashMap[String, String]()\n    options.put(QueryType.LABELS.toString.toLowerCase, \"Person\")\n\n    val schema = getSchema(options)\n\n    assertEquals(getExpectedStructType(Seq(StructField(\"is_hero\", DataTypes.BooleanType))), schema)\n  }\n\n  @Test\n  def testGetSchemaFromNodeString(): Unit = {\n    initTest(\"CREATE (p:Person {name: 'John'})\")\n    val options: java.util.Map[String, String] = new util.HashMap[String, String]()\n    options.put(QueryType.LABELS.toString.toLowerCase, \"Person\")\n\n    val schema = getSchema(options)\n\n    assertEquals(getExpectedStructType(Seq(StructField(\"name\", DataTypes.StringType))), schema)\n  }\n\n  @Test\n  def testGetSchemaFromNodeLong(): Unit = {\n    initTest(\"CREATE (p:Person {age: 93})\")\n    val options: java.util.Map[String, String] = new util.HashMap[String, String]()\n    options.put(QueryType.LABELS.toString.toLowerCase, \"Person\")\n\n    val schema = getSchema(options)\n\n    assertEquals(getExpectedStructType(Seq(StructField(\"age\", DataTypes.LongType))), schema)\n  }\n\n  @Test\n  def testGetSchemaFromNodeDouble(): Unit = {\n    initTest(\"CREATE (p:Person {ratio: 43.120})\")\n    val options: java.util.Map[String, String] = new util.HashMap[String, String]()\n    options.put(QueryType.LABELS.toString.toLowerCase, \"Person\")\n\n    val schema = getSchema(options)\n\n    assertEquals(getExpectedStructType(Seq(StructField(\"ratio\", DataTypes.DoubleType))), schema)\n  }\n\n  @Test\n  def testGetSchemaFromNodePoint2D(): Unit = {\n    initTest(\"CREATE (p:Person {location: point({x: 12.32, y: 49.32})})\")\n    val options: java.util.Map[String, String] = new util.HashMap[String, String]()\n    options.put(QueryType.LABELS.toString.toLowerCase, \"Person\")\n\n    val schema = getSchema(options)\n\n    assertEquals(getExpectedStructType(Seq(StructField(\"location\", CypherToSparkTypeConverter.pointType))), schema)\n  }\n\n  @Test\n  def testGetSchemaFromDate(): Unit = {\n    initTest(\"CREATE (p:Person {born_on: date('1998-01-05')})\")\n    val options: java.util.Map[String, String] = new util.HashMap[String, String]()\n    options.put(QueryType.LABELS.toString.toLowerCase, \"Person\")\n\n    val schema = getSchema(options)\n\n    assertEquals(getExpectedStructType(Seq(StructField(\"born_on\", DataTypes.DateType))), schema)\n  }\n\n  @Test\n  def testGetSchemaFromDateTime(): Unit = {\n    initTest(\"CREATE (p:Person {arrived_at: datetime('1998-01-05')})\")\n    val options: java.util.Map[String, String] = new util.HashMap[String, String]()\n    options.put(QueryType.LABELS.toString.toLowerCase, \"Person\")\n\n    val schema = getSchema(options)\n\n    assertEquals(getExpectedStructType(Seq(StructField(\"arrived_at\", DataTypes.TimestampType))), schema)\n  }\n\n  @Test\n  def testGetSchemaFromTime(): Unit = {\n    initTest(\"CREATE (p:Person {arrived_at: time('125035.556+0100')})\")\n    val options: java.util.Map[String, String] = new util.HashMap[String, String]()\n    options.put(QueryType.LABELS.toString.toLowerCase, \"Person\")\n\n    val schema = getSchema(options)\n\n    assertEquals(getExpectedStructType(Seq(StructField(\"arrived_at\", CypherToSparkTypeConverter.timeType))), schema)\n  }\n\n  @Test\n  def testGetSchemaFromStringArray(): Unit = {\n    initTest(\"CREATE (p:Person {names: ['John', 'Doe']})\")\n    val options: java.util.Map[String, String] = new util.HashMap[String, String]()\n    options.put(QueryType.LABELS.toString.toLowerCase, \"Person\")\n\n    val schema = getSchema(options)\n\n    assertEquals(\n      getExpectedStructType(Seq(StructField(\"names\", DataTypes.createArrayType(DataTypes.StringType)))),\n      schema\n    )\n  }\n\n  @Test\n  def testGetSchemaFromDateArray(): Unit = {\n    initTest(\"CREATE (p:Person {names: [date('2019-11-19'), date('2019-11-20')]})\")\n    val options: java.util.Map[String, String] = new util.HashMap[String, String]()\n    options.put(QueryType.LABELS.toString.toLowerCase, \"Person\")\n\n    val schema = getSchema(options)\n\n    assertEquals(\n      getExpectedStructType(Seq(StructField(\"names\", DataTypes.createArrayType(DataTypes.DateType)))),\n      schema\n    )\n  }\n\n  @Test\n  def testGetSchemaFromTimestampArray(): Unit = {\n    initTest(\"CREATE (p:Person {dates: [datetime('2019-11-19'), datetime('2019-11-20')]})\")\n    val options: java.util.Map[String, String] = new util.HashMap[String, String]()\n    options.put(QueryType.LABELS.toString.toLowerCase, \"Person\")\n\n    val schema = getSchema(options)\n\n    assertEquals(\n      getExpectedStructType(Seq(StructField(\"dates\", DataTypes.createArrayType(DataTypes.TimestampType)))),\n      schema\n    )\n  }\n\n  @Test\n  def testGetSchemaFromTimeArray(): Unit = {\n    initTest(\"CREATE (p:Person {dates: [time('125035.556+0100'), time('125125.556+0100')]})\")\n    val options: java.util.Map[String, String] = new util.HashMap[String, String]()\n    options.put(QueryType.LABELS.toString.toLowerCase, \"Person\")\n\n    val schema = getSchema(options)\n\n    assertEquals(\n      getExpectedStructType(Seq(StructField(\"dates\", DataTypes.createArrayType(CypherToSparkTypeConverter.timeType)))),\n      schema\n    )\n  }\n\n  @Test\n  def testGetSchemaFromIntegerArray(): Unit = {\n    initTest(\"CREATE (p:Person {ages: [42, 101]})\")\n    val options: java.util.Map[String, String] = new util.HashMap[String, String]()\n    options.put(QueryType.LABELS.toString.toLowerCase, \"Person\")\n\n    val schema = getSchema(options)\n\n    assertEquals(getExpectedStructType(Seq(StructField(\"ages\", DataTypes.createArrayType(DataTypes.LongType)))), schema)\n  }\n\n  @Test\n  def testGetSchemaFromMultipleNodes(): Unit = {\n    initTest(\n      \"\"\"\n      CREATE (p1:Person {age: 31, name: 'Jane Doe'}),\n        (p2:Person {name: 'John Doe', age: 33, location: null}),\n        (p3:Person {age: 25, location: point({latitude: 12.12, longitude: 31.13})})\n    \"\"\"\n    )\n\n    val options: java.util.Map[String, String] = new util.HashMap[String, String]()\n    options.put(QueryType.LABELS.toString.toLowerCase, \"Person\")\n\n    val schema = getSchema(options)\n\n    assertEquals(\n      getExpectedStructType(Seq(\n        StructField(\"age\", DataTypes.LongType),\n        StructField(\"location\", CypherToSparkTypeConverter.pointType),\n        StructField(\"name\", DataTypes.StringType)\n      )),\n      schema\n    )\n  }\n\n  private def getExpectedStructType(structFields: Seq[StructField]): StructType = {\n    val additionalFields: Seq[StructField] = Seq(\n      StructField(Neo4jUtil.INTERNAL_LABELS_FIELD, DataTypes.createArrayType(DataTypes.StringType), nullable = true),\n      StructField(Neo4jUtil.INTERNAL_ID_FIELD, DataTypes.LongType, nullable = false)\n    )\n    StructType(structFields.union(additionalFields).reverse)\n  }\n\n  private def initTest(query: String): Unit = {\n    SparkConnectorScalaSuiteWithApocIT.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(query).consume()\n        }\n      )\n  }\n\n  private def getSchema(options: java.util.Map[String, String]): StructType = {\n    options.put(Neo4jOptions.URL, SparkConnectorScalaSuiteWithApocIT.server.getBoltUrl)\n    val neo4jOptions: Neo4jOptions = new Neo4jOptions(options)\n\n    val driverCache = new DriverCache(neo4jOptions.connection)\n    val neo4j = new Neo4j(new Neo4jVersion(4, 4, 0), Neo4jEdition.ENTERPRISE, Neo4jDeploymentType.SELF_MANAGED)\n    val schemaService: SchemaService = new SchemaService(neo4j, neo4jOptions, driverCache)\n\n    val schema: StructType = schemaService.struct()\n    schemaService.close()\n    driverCache.close()\n\n    schema\n  }\n}\n"
  },
  {
    "path": "common/src/test/scala/org/neo4j/spark/util/DummyNamedReference.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark.util\n\nimport org.apache.spark.sql.connector.expressions.NamedReference\n\nclass DummyNamedReference(private val fields: String*) extends NamedReference {\n  override def fieldNames(): Array[String] = fields.toArray\n\n  override def describe(): String = fields.mkString(\", \")\n  override def toString: String = describe()\n}\n"
  },
  {
    "path": "common/src/test/scala/org/neo4j/spark/util/Neo4jImplicitsTest.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark.util\n\nimport org.apache.spark.sql.connector.expressions.NamedReference\nimport org.apache.spark.sql.connector.expressions.aggregate.Aggregation\nimport org.apache.spark.sql.connector.expressions.aggregate.Sum\nimport org.apache.spark.sql.sources.And\nimport org.apache.spark.sql.sources.EqualTo\nimport org.apache.spark.sql.types.DataTypes\nimport org.apache.spark.sql.types.StructField\nimport org.apache.spark.sql.types.StructType\nimport org.junit.Assert\nimport org.junit.Assert._\nimport org.junit.Test\nimport org.neo4j.spark.util.Neo4jImplicits._\n\nimport scala.collection.JavaConverters.mapAsJavaMapConverter\nimport scala.collection.JavaConverters.mapAsScalaMapConverter\nimport scala.collection.JavaConverters.seqAsJavaListConverter\nimport scala.collection.immutable.ListMap\n\nclass Neo4jImplicitsTest {\n\n  @Test\n  def `should quote the string` {\n    // given\n    val value = \"Test with space\"\n\n    // when\n    val actual = value.quote\n\n    // then\n    assertEquals(s\"`$value`\", actual)\n  }\n\n  @Test\n  def `should quote text that starts with $` {\n    // given\n    val value = \"$tring\"\n\n    // when\n    val actual = value.quote\n\n    // then\n    assertEquals(s\"`$value`\", actual)\n  }\n\n  @Test\n  def `should not re-quote the string` {\n    // given\n    val value = \"`Test with space`\"\n\n    // when\n    val actual = value.quote\n\n    // then\n    assertEquals(value, actual)\n  }\n\n  @Test\n  def `should not quote the string` {\n    // given\n    val value = \"Test\"\n\n    // when\n    val actual = value.quote\n\n    // then\n    assertEquals(value, actual)\n  }\n\n  @Test\n  def `should return attribute if filter has it` {\n    // given\n    val filter = EqualTo(\"name\", \"John\")\n\n    // when\n    val attribute = filter.getAttribute\n\n    // then\n    assertTrue(attribute.isDefined)\n  }\n\n  @Test\n  def `should return an empty option if the filter doesn't have an attribute` {\n    // given\n    val filter = And(EqualTo(\"name\", \"John\"), EqualTo(\"age\", 32))\n\n    // when\n    val attribute = filter.getAttribute\n\n    // then\n    assertFalse(attribute.isDefined)\n  }\n\n  @Test\n  def `should return the attribute without the entity identifier` {\n    // given\n    val filter = EqualTo(\"person.address.coords\", 32)\n\n    // when\n    val attribute = filter.getAttributeWithoutEntityName\n\n    // then\n    assertEquals(\"address.coords\", attribute.get)\n  }\n\n  @Test\n  def `struct should return true if contains fields`: Unit = {\n    val struct = StructType(Seq(\n      StructField(\"is_hero\", DataTypes.BooleanType),\n      StructField(\"name\", DataTypes.StringType),\n      StructField(\"fi``(╯°□°)╯︵ ┻━┻eld\", DataTypes.StringType)\n    ))\n\n    assertEquals(0, struct.getMissingFields(Set(\"is_hero\", \"name\", \"fi``(╯°□°)╯︵ ┻━┻eld\")).size)\n  }\n\n  @Test\n  def `struct should return false if not contains fields`: Unit = {\n    val struct =\n      StructType(Seq(StructField(\"is_hero\", DataTypes.BooleanType), StructField(\"name\", DataTypes.StringType)))\n\n    assertEquals(Set[String](\"hero_name\"), struct.getMissingFields(Set(\"is_hero\", \"hero_name\")))\n  }\n\n  @Test\n  def `getMissingFields should handle maps`: Unit = {\n    val struct = StructType(Seq(\n      StructField(\"im\", DataTypes.StringType),\n      StructField(\"im.a\", DataTypes.createMapType(DataTypes.StringType, DataTypes.StringType)),\n      StructField(\"im.also.a\", DataTypes.createMapType(DataTypes.StringType, DataTypes.StringType)),\n      StructField(\"im.not.a.map\", DataTypes.StringType),\n      StructField(\"fi``(╯°□°)╯︵ ┻━┻eld\", DataTypes.StringType)\n    ))\n\n    val result = struct.getMissingFields(Set(\n      \"im.aMap\",\n      \"`im.also.a`.field\",\n      \"`im.a`.map\",\n      \"`im.not.a.map`\",\n      \"fi``(╯°□°)╯︵ ┻━┻eld\"\n    ))\n\n    assertEquals(Set(\"im.aMap\"), result)\n  }\n\n  @Test\n  def `groupByCols aggregation should work`: Unit = {\n    val aggField = new NamedReference {\n      override def fieldNames(): Array[String] = Array(\"foo\")\n\n      override def describe(): String = \"foo\"\n    }\n    val gbyField = new NamedReference {\n      override def fieldNames(): Array[String] = Array(\"bar\")\n\n      override def describe(): String = \"bar\"\n    }\n    val agg = new Aggregation(Array(new Sum(aggField, false)), Array(gbyField))\n    assertEquals(1, agg.groupByCols().length)\n    assertEquals(\"bar\", agg.groupByCols()(0).describe())\n  }\n\n  @Test\n  def `should flatten the map`(): Unit = {\n    val input = Map(\n      \"foo\" -> \"bar\",\n      \"key\" -> Map(\n        \"innerKey\" -> Map(\"innerKey2\" -> \"value\")\n      )\n    )\n    val expected = Map(\n      \"foo\" -> \"bar\",\n      \"key.innerKey.innerKey2\" -> \"value\"\n    )\n    val actual = input.flattenMap()\n    Assert.assertEquals(expected, actual)\n  }\n\n  @Test\n  def `should not handle collision`(): Unit = {\n    val input = ListMap(\n      \"my\" -> Map(\n        \"inner\" -> Map(\"key\" -> 42424242),\n        \"inner.key\" -> 424242\n      ),\n      \"my.inner\" -> Map(\"key\" -> 4242).asJava,\n      \"my.inner.key\" -> 42\n    )\n    val expected = Map(\n      \"my.inner.key\" -> 42\n    )\n    val actual = input.flattenMap()\n    Assert.assertEquals(expected, actual)\n  }\n\n  @Test\n  def `should handle collision by aggregating values`(): Unit = {\n    val input = ListMap(\n      \"my\" -> Map(\n        \"inner\" -> Map(\"key\" -> 42424242),\n        \"inner.key\" -> 424242\n      ),\n      \"my.inner\" -> Map(\"key\" -> 4242).asJava,\n      \"my.inner.key\" -> 42\n    )\n    val expected = Map(\n      \"my.inner.key\" -> Seq(42424242, 424242, 4242, 42).asJava\n    )\n    val actual = input.flattenMap(groupDuplicateKeys = true)\n    Assert.assertEquals(expected, actual)\n  }\n\n  @Test\n  def `should show duplicate keys`(): Unit = {\n    val input = Map(\n      \"my\" -> Map(\n        \"inner\" -> Map(\"key\" -> 42424242),\n        \"inner.key\" -> 424242\n      ),\n      \"my.inner\" -> Map(\"key\" -> 4242).asJava,\n      \"my.inner.key\" -> 42\n    )\n    val expected = Seq(\"my.inner.key\", \"my.inner.key\", \"my.inner.key\", \"my.inner.key\")\n    val actual = input.flattenKeys()\n    Assert.assertEquals(expected, actual)\n  }\n\n  @Test\n  def `should deserialized dotted/stringified map into a nested Java map`(): Unit = {\n    val actual = Map(\n      \"graphName\" -> \"foo\",\n      \"configuration.number\" -> \"1\",\n      \"configuration.string\" -> \"foo\",\n      \"configuration.list\" -> \"['a', 1]\",\n      \"configuration.map.key\" -> \"value\",\n      \"relationshipProjection.LINK.properties.foobar.defaultValue\" -> \"42.0\"\n    ).toNestedJavaMap\n    val expected: java.util.Map[String, Object] = Map(\n      \"graphName\" -> \"foo\",\n      \"configuration\" -> Map(\n        \"number\" -> 1,\n        \"string\" -> \"foo\",\n        \"list\" -> Seq(\"a\", 1).toList.asJava,\n        \"map\" -> Map(\n          \"key\" -> \"value\"\n        ).asJava\n      ).asJava,\n      \"relationshipProjection\" -> Map(\n        \"LINK\" -> Map(\n          \"properties\" -> Map(\n            \"foobar\" -> Map(\"defaultValue\" -> 42.0).asJava\n          ).asJava\n        ).asJava\n      ).asJava\n    ).asJava\n    Assert.assertEquals(expected, actual)\n\n    val ucActual = Map(\n      \"graphName\" -> \"myGraph\",\n      \"nodeProjection\" -> \"Website\",\n      \"relationshipProjection.LINK.indexInverse\" -> \"true\"\n    ).toNestedJavaMap\n    val ucExpected: java.util.Map[String, Object] = Map(\n      \"graphName\" -> \"myGraph\",\n      \"nodeProjection\" -> \"Website\",\n      \"relationshipProjection\" -> Map(\n        \"LINK\" -> Map(\n          \"indexInverse\" -> true\n        ).asJava\n      ).asJava\n    ).asJava\n    Assert.assertEquals(ucExpected, ucActual)\n  }\n}\n"
  },
  {
    "path": "common/src/test/scala/org/neo4j/spark/util/Neo4jOptionsIT.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark.util\n\nimport org.junit.Assert.assertEquals\nimport org.junit.Assert.assertNotNull\nimport org.junit.Ignore\nimport org.junit.Test\nimport org.neo4j.Closeables.use\nimport org.neo4j.spark.SparkConnectorScalaSuiteIT\nimport org.neo4j.spark.SparkConnectorScalaSuiteIT.server\n\nclass Neo4jOptionsIT extends SparkConnectorScalaSuiteIT {\n\n  @Test\n  def shouldConstructDriver(): Unit = {\n    val options: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    options.put(Neo4jOptions.URL, server.getBoltUrl)\n    options.put(Neo4jOptions.AUTH_TYPE, \"none\")\n\n    val neo4jOptions = new Neo4jOptions(options)\n\n    use(neo4jOptions.connection.createDriver()) { driver =>\n      assertNotNull(driver)\n\n      use(driver.session()) { session =>\n        assertEquals(1, session.run(\"RETURN 1\").single().get(0).asInt())\n      }\n    }\n  }\n\n  @Test\n  def shouldConstructDriverWithResolver(): Unit = {\n    val options: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    options.put(\n      Neo4jOptions.URL,\n      s\"neo4j://localhost.localdomain:8888, bolt://localhost.localdomain:9999, ${server.getBoltUrl}\"\n    )\n    options.put(Neo4jOptions.AUTH_TYPE, \"none\")\n\n    val neo4jOptions = new Neo4jOptions(options)\n\n    use(neo4jOptions.connection.createDriver()) { driver =>\n      assertNotNull(driver)\n\n      use(driver.session()) { session =>\n        assertEquals(1, session.run(\"RETURN 1\").single().get(0).asInt())\n      }\n    }\n  }\n\n}\n"
  },
  {
    "path": "common/src/test/scala/org/neo4j/spark/util/Neo4jOptionsTest.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark.util\n\nimport org.junit.Assert._\nimport org.junit.Test\nimport org.neo4j.driver.AccessMode\nimport org.neo4j.driver.net.ServerAddress\n\nimport java.net.URI\nimport java.time.Duration\n\nimport scala.annotation.meta.getter\nimport scala.collection.JavaConverters._\n\nclass Neo4jOptionsTest {\n\n  import org.junit.Rule\n  import org.junit.rules.ExpectedException\n\n  @(Rule @getter)\n  val _expectedException: ExpectedException = ExpectedException.none\n\n  @Test\n  def testUrlIsRequired(): Unit = {\n    val options: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    options.put(QueryType.QUERY.toString.toLowerCase, \"Person\")\n\n    _expectedException.expect(classOf[IllegalArgumentException])\n    _expectedException.expectMessage(\"Parameter 'url' is required\")\n\n    new Neo4jOptions(options)\n  }\n\n  @Test\n  def testRelationshipTableName(): Unit = {\n    val options: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    options.put(Neo4jOptions.URL, \"bolt://localhost\")\n    options.put(QueryType.RELATIONSHIP.toString.toLowerCase, \"KNOWS\")\n    options.put(Neo4jOptions.RELATIONSHIP_SOURCE_LABELS, \"Person\")\n    options.put(Neo4jOptions.RELATIONSHIP_TARGET_LABELS, \"Answer\")\n\n    val neo4jOptions = new Neo4jOptions(options)\n\n    assertEquals(\"table_Person_KNOWS_Answer\", neo4jOptions.getTableName)\n  }\n\n  @Test\n  def testLabelsTableName(): Unit = {\n    val options: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    options.put(Neo4jOptions.URL, \"bolt://localhost\")\n    options.put(\"labels\", \"Person:Admin\")\n\n    val neo4jOptions = new Neo4jOptions(options)\n\n    assertEquals(\"table_Person-Admin\", neo4jOptions.getTableName)\n  }\n\n  @Test\n  def testRelationshipNodeModesAreCaseInsensitive(): Unit = {\n    val options: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    options.put(Neo4jOptions.URL, \"bolt://localhost\")\n    options.put(QueryType.RELATIONSHIP.toString.toLowerCase, \"KNOWS\")\n    options.put(Neo4jOptions.RELATIONSHIP_SAVE_STRATEGY, \"nAtIve\")\n    options.put(Neo4jOptions.RELATIONSHIP_SOURCE_SAVE_MODE, \"Errorifexists\")\n    options.put(Neo4jOptions.RELATIONSHIP_TARGET_SAVE_MODE, \"overwrite\")\n\n    val neo4jOptions = new Neo4jOptions(options)\n\n    assertEquals(RelationshipSaveStrategy.NATIVE, neo4jOptions.relationshipMetadata.saveStrategy)\n    assertEquals(NodeSaveMode.ErrorIfExists, neo4jOptions.relationshipMetadata.sourceSaveMode)\n    assertEquals(NodeSaveMode.Overwrite, neo4jOptions.relationshipMetadata.targetSaveMode)\n  }\n\n  @Test\n  def testRelationshipWriteStrategyIsNotPresentShouldThrowException(): Unit = {\n    val options: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    options.put(Neo4jOptions.URL, \"bolt://localhost\")\n    options.put(QueryType.LABELS.toString.toLowerCase, \"PERSON\")\n    options.put(\"relationship.save.strategy\", \"nope\")\n\n    _expectedException.expect(classOf[NoSuchElementException])\n    _expectedException.expectMessage(\"No value found for 'NOPE'\")\n\n    new Neo4jOptions(options)\n  }\n\n  @Test\n  def testQueryShouldHaveQueryType(): Unit = {\n    val query: String = \"MATCH n RETURN n\"\n    val options: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    options.put(Neo4jOptions.URL, \"bolt://localhost\")\n    options.put(QueryType.QUERY.toString.toLowerCase, query)\n\n    val neo4jOptions: Neo4jOptions = new Neo4jOptions(options)\n\n    assertEquals(QueryType.QUERY, neo4jOptions.query.queryType)\n    assertEquals(query, neo4jOptions.query.value)\n  }\n\n  @Test\n  def testNodeShouldHaveLabelType(): Unit = {\n    val label: String = \"Person\"\n    val options: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    options.put(Neo4jOptions.URL, \"bolt://localhost\")\n    options.put(QueryType.LABELS.toString.toLowerCase, label)\n\n    val neo4jOptions: Neo4jOptions = new Neo4jOptions(options)\n\n    assertEquals(QueryType.LABELS, neo4jOptions.query.queryType)\n    assertEquals(label, neo4jOptions.query.value)\n  }\n\n  @Test\n  def testRelationshipShouldHaveRelationshipType(): Unit = {\n    val relationship: String = \"KNOWS\"\n    val options: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    options.put(Neo4jOptions.URL, \"bolt://localhost\")\n    options.put(QueryType.LABELS.toString.toLowerCase, relationship)\n\n    val neo4jOptions: Neo4jOptions = new Neo4jOptions(options)\n\n    assertEquals(QueryType.LABELS, neo4jOptions.query.queryType)\n    assertEquals(relationship, neo4jOptions.query.value)\n  }\n\n  @Test\n  def testPushDownColumnIsDisabled(): Unit = {\n    val options: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    options.put(Neo4jOptions.URL, \"bolt://localhost\")\n    options.put(\"pushdown.columns.enabled\", \"false\")\n\n    val neo4jOptions: Neo4jOptions = new Neo4jOptions(options)\n\n    assertFalse(neo4jOptions.pushdownColumnsEnabled)\n  }\n\n  @Test\n  def testDriverDefaults(): Unit = {\n    val options: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    options.put(Neo4jOptions.URL, \"bolt://localhost\")\n    options.put(QueryType.QUERY.toString.toLowerCase, \"MATCH n RETURN n\")\n\n    val neo4jOptions: Neo4jOptions = new Neo4jOptions(options)\n\n    assertEquals(\"\", neo4jOptions.session.database)\n    assertEquals(AccessMode.READ, neo4jOptions.session.accessMode)\n\n    assertEquals(\"basic\", neo4jOptions.connection.auth)\n    assertEquals(Neo4jOptions.DEFAULT_AUTH_PARAMETERS, neo4jOptions.connection.authParameters)\n    assertEquals(false, neo4jOptions.connection.encryption)\n\n    assertEquals(None, neo4jOptions.connection.trustStrategy)\n\n    assertEquals(\"\", neo4jOptions.connection.certificatePath)\n\n    assertEquals(Neo4jOptions.DEFAULT_CONNECTION_MAX_LIFETIME_MSECS, neo4jOptions.connection.lifetime)\n    assertEquals(-1, neo4jOptions.connection.acquisitionTimeout)\n    assertEquals(-1, neo4jOptions.connection.connectionTimeout)\n    assertEquals(\n      Neo4jOptions.DEFAULT_CONNECTION_LIVENESS_CHECK_TIMEOUT_MSECS,\n      neo4jOptions.connection.livenessCheckTimeout\n    )\n    assertEquals(RelationshipSaveStrategy.NATIVE, neo4jOptions.relationshipMetadata.saveStrategy)\n\n    assertTrue(neo4jOptions.pushdownFiltersEnabled)\n  }\n\n  @Test\n  def testApocConfiguration(): Unit = {\n    val options: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    options.put(\"apoc.meta.nodeTypeProperties\", \"\"\"{\"nodeLabels\": [\"Label\"], \"mandatory\": false}\"\"\")\n    options.put(Neo4jOptions.URL, \"bolt://localhost\")\n\n    val neo4jOptions: Neo4jOptions = new Neo4jOptions(options)\n\n    val expected = Map(\"apoc.meta.nodeTypeProperties\" -> Map(\n      \"nodeLabels\" -> Seq(\"Label\").asJava,\n      \"mandatory\" -> false\n    ))\n\n    assertEquals(neo4jOptions.apocConfig.procedureConfigMap, expected)\n  }\n\n  @Test\n  def testUnexistingProperty(): Unit = {\n    val options: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    options.put(\"relationship.properties\", null)\n    options.put(Neo4jOptions.URL, \"bolt://localhost\")\n\n    val neo4jOptions: Neo4jOptions = new Neo4jOptions(options)\n\n    assertEquals(neo4jOptions.relationshipMetadata.properties, None)\n  }\n\n  @Test\n  def testUrls(): Unit = {\n    val options: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    options.put(Neo4jOptions.URL, \"neo4j://localhost, neo4j://foo.bar:7687, neo4j://foo.bar.baz:7783\")\n\n    val neo4jOptions: Neo4jOptions = new Neo4jOptions(options)\n    val (baseUrl, resolvers) = neo4jOptions.connection.connectionUrls\n\n    assertEquals(URI.create(\"neo4j://localhost\"), baseUrl)\n    assertEquals(Set(ServerAddress.of(\"foo.bar\", 7687), ServerAddress.of(\"foo.bar.baz\", 7783)), resolvers)\n  }\n\n  @Test\n  def testGdsProperties(): Unit = {\n    val options: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    options.put(Neo4jOptions.URL, \"neo4j://localhost,neo4j://foo.bar,neo4j://foo.bar.baz:7783\")\n    options.put(\"gds\", \"gds.pageRank.stream\")\n    options.put(\"gds.graphName\", \"myGraph\")\n    options.put(\"gds.configuration.concurrency\", \"2\")\n    val neo4jOptions: Neo4jOptions = new Neo4jOptions(options)\n    assertEquals(QueryType.GDS, neo4jOptions.query.queryType)\n    assertEquals(\"gds.pageRank.stream\", neo4jOptions.query.value)\n    assertEquals(\n      Map(\n        \"graphName\" -> \"myGraph\",\n        \"configuration\" -> Map(\"concurrency\" -> 2).asJava\n      ).asJava,\n      neo4jOptions.gdsMetadata.parameters\n    )\n  }\n\n  @Test\n  def testTransactionTimeout(): Unit = {\n    // Given a Neo4j options with transaction timeout set\n    val rawOptions = new java.util.HashMap[String, String]()\n    rawOptions.put(Neo4jOptions.URL, \"neo4j://localhost,neo4j://foo.bar,neo4j://foo.bar.baz:7783\")\n    rawOptions.put(\"db.transaction.timeout\", \"1000\")\n\n    val neo4jOptions = new Neo4jOptions(rawOptions)\n\n    // When it converts to TransactionConfig\n    val transactionConfig = neo4jOptions.toNeo4jTransactionConfig\n\n    // Then it has the correct duration\n    assertEquals(Duration.ofMillis(1000), transactionConfig.timeout())\n  }\n\n  @Test\n  def testDefaultTransactionTimeout(): Unit = {\n    // Given a Neo4j options with no explicit transaction timeout set\n    val rawOptions = new java.util.HashMap[String, String]()\n    rawOptions.put(Neo4jOptions.URL, \"neo4j://localhost,neo4j://foo.bar,neo4j://foo.bar.baz:7783\")\n\n    val neo4jOptions = new Neo4jOptions(rawOptions)\n\n    // When it converts to TransactionConfig\n    val transactionConfig = neo4jOptions.toNeo4jTransactionConfig\n\n    // Then it is not set\n    assertNull(transactionConfig.timeout())\n  }\n}\n"
  },
  {
    "path": "common/src/test/scala/org/neo4j/spark/util/Neo4jUtilTest.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark.util\n\nimport org.apache.commons.lang3.StringUtils\nimport org.junit.Assert\nimport org.junit.Test\n\nclass Neo4jUtilTest {\n\n  @Test\n  def testSafetyCloseShouldNotFailWithNull(): Unit = {\n    Neo4jUtil.closeSafely(null)\n  }\n\n  @Test\n  def testConnectorEnv(): Unit = {\n    val expected = if (StringUtils.isNotBlank(System.getenv(\"DATABRICKS_RUNTIME_VERSION\"))) {\n      \"databricks\"\n    } else {\n      \"spark\"\n    }\n    val actual = Neo4jUtil.connectorEnv\n    Assert.assertEquals(expected, actual)\n  }\n\n  @Test\n  def testConnectorEnvForCustom(): Unit = {\n    System.setProperty(\"neo4j.spark.platform\", \"abc\")\n    val actual = Neo4jUtil.connectorEnv\n    Assert.assertEquals(\"abc\", actual)\n  }\n\n}\n"
  },
  {
    "path": "common/src/test/scala/org/neo4j/spark/util/ValidationsIT.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark.util\n\nimport org.hamcrest.CoreMatchers\nimport org.junit.Rule\nimport org.junit.Test\nimport org.junit.rules.ExpectedException\nimport org.neo4j.driver.AccessMode\nimport org.neo4j.spark.SparkConnectorScalaSuiteIT\nimport org.neo4j.spark.SparkConnectorScalaSuiteIT.neo4j\nimport org.neo4j.spark.TestUtil\n\nimport java.util.regex.Pattern\n\nimport scala.annotation.meta.getter\n\nclass ValidationsIT extends SparkConnectorScalaSuiteIT {\n\n  @(Rule @getter)\n  val expectedException: ExpectedException = ExpectedException.none\n\n  @Test\n  def testReadQueryShouldBeSyntacticallyInvalid(): Unit = {\n    // then\n    expectedException.expect(classOf[IllegalArgumentException])\n    expectedException.expectMessage(\n      CoreMatchers.containsString(\"Query not compiled for the following exception: ClientException: Invalid input \")\n    )\n    val query = \"MATCH (f{) RETURN f\"\n    expectedException.expectMessage(CoreMatchers.containsString(query))\n\n    // given\n    val readOpts: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    readOpts.put(Neo4jOptions.URL, SparkConnectorScalaSuiteIT.server.getBoltUrl)\n    readOpts.put(\"query\", query)\n\n    // when\n    Validations.validate(ValidateRead(neo4j, new Neo4jOptions(readOpts), \"1\"))\n  }\n\n  @Test\n  def testReadQueryShouldBeSemanticallyInvalid(): Unit = {\n    // then\n    val query = \"MERGE (n:TestNode{id: 1}) RETURN n\"\n    expectedException.expect(classOf[IllegalArgumentException])\n    expectedException.expectMessage(\n      s\"Invalid query `$query` because the accepted types are [READ_ONLY], but the actual type is READ_WRITE\"\n    )\n\n    // given\n    val readOpts: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    readOpts.put(Neo4jOptions.URL, SparkConnectorScalaSuiteIT.server.getBoltUrl)\n    readOpts.put(\"query\", query)\n\n    // when\n    Validations.validate(ValidateRead(neo4j, new Neo4jOptions(readOpts), \"1\"))\n  }\n\n  @Test\n  def testReadQueryCountBeSyntacticallyInvalid(): Unit = {\n    // then\n    val query = \"MATCH (f{) RETURN f\"\n    expectedException.expect(classOf[IllegalArgumentException])\n    expectedException.expectMessage(CoreMatchers.containsString(\n      \"Query count not compiled for the following exception: ClientException: Invalid input \"\n    ))\n    expectedException.expectMessage(CoreMatchers.containsString(s\"EXPLAIN $query\"))\n\n    // given\n    val readOpts: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    readOpts.put(Neo4jOptions.URL, SparkConnectorScalaSuiteIT.server.getBoltUrl)\n    readOpts.put(\"query\", \"MATCH (f) RETURN f\")\n    readOpts.put(\"query.count\", query)\n\n    // when\n    Validations.validate(ValidateRead(neo4j, new Neo4jOptions(readOpts), \"1\"))\n  }\n\n  @Test\n  def testScriptQueryCountShouldContainAnInvalidQuery(): Unit = {\n    // then\n    expectedException.expect(classOf[IllegalArgumentException])\n    expectedException.expectMessage(\n      CoreMatchers.containsString(\"The following queries inside the `script` are not valid,\")\n    )\n    expectedException.expectMessage(\n      CoreMatchers.containsString(\"Query not compiled for the following exception: ClientException: Invalid input \")\n    )\n    expectedException.expectMessage(CoreMatchers.containsString(\"EXPLAIN RETUR 2 AS two\"))\n\n    // given\n    val readOpts: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    readOpts.put(Neo4jOptions.URL, SparkConnectorScalaSuiteIT.server.getBoltUrl)\n    readOpts.put(\"query\", \"MATCH (f) RETURN f\")\n    readOpts.put(\"script\", \"RETURN 1 AS one; RETUR 2 AS two; RETURN 3 AS three\")\n\n    // when\n    Validations.validate(ValidateRead(neo4j, new Neo4jOptions(readOpts), \"1\"))\n  }\n\n  @Test\n  def testWriteQueryShouldBeSyntacticallyInvalid(): Unit = {\n    // then\n    val query = \"MERGE (f{) RETURN f\"\n    expectedException.expect(classOf[IllegalArgumentException])\n    expectedException.expectMessage(\n      CoreMatchers.containsString(\"Query not compiled for the following exception: ClientException: Invalid input \")\n    )\n    expectedException.expectMessage(CoreMatchers.containsString(query))\n\n    // given\n    val writeOpts: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    writeOpts.put(Neo4jOptions.URL, SparkConnectorScalaSuiteIT.server.getBoltUrl)\n    writeOpts.put(Neo4jOptions.ACCESS_MODE, AccessMode.WRITE.toString)\n    writeOpts.put(\"query\", query)\n\n    // when\n    Validations.validate(ValidateWrite(neo4j, new Neo4jOptions(writeOpts), \"1\", null))\n  }\n\n  @Test\n  def testWriteQueryShouldBeSemanticallyInvalid(): Unit = {\n    // then\n    val query = \"MATCH (n:TestNode{id: 1}) RETURN n\"\n    expectedException.expect(classOf[IllegalArgumentException])\n    expectedException.expectMessage(\n      s\"Invalid query `$query` because the accepted types are [WRITE_ONLY, READ_WRITE], but the actual type is READ_ONLY\"\n    )\n\n    // given\n    val writeOpts: java.util.Map[String, String] = new java.util.HashMap[String, String]()\n    writeOpts.put(Neo4jOptions.URL, SparkConnectorScalaSuiteIT.server.getBoltUrl)\n    writeOpts.put(Neo4jOptions.ACCESS_MODE, AccessMode.WRITE.toString)\n    writeOpts.put(\"query\", query)\n\n    // when\n    Validations.validate(ValidateWrite(neo4j, new Neo4jOptions(writeOpts), \"1\", null))\n  }\n\n}\n"
  },
  {
    "path": "common/src/test/scala/org/neo4j/spark/util/ValidationsTest.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark.util\n\nimport org.apache.spark.sql.SparkSession\nimport org.junit\nimport org.junit.Assert.assertEquals\nimport org.junit.Test\nimport org.neo4j.spark.SparkConnectorScalaBaseTSE\n\nclass ValidationsTest extends SparkConnectorScalaBaseTSE {\n\n  @Test\n  def testVersionThrowsExceptionSparkVersionIsNotSupported(): Unit = {\n    val sparkVersion = SparkSession.getActiveSession\n      .map { _.version }\n      .getOrElse(\"UNKNOWN\")\n    try {\n      Validations.validate(ValidateSparkMinVersion(\"3.10000\"))\n      fail(s\"should be thrown a ${classOf[IllegalArgumentException].getName}\")\n    } catch {\n      case e: IllegalArgumentException =>\n        assertEquals(\n          s\"\"\"Your current Spark version $sparkVersion is not supported by the current connector.\n             |Please visit https://neo4j.com/developer/spark/overview/#_spark_compatibility to know which connector version you need.\n             |\"\"\".stripMargin,\n          e.getMessage\n        )\n      case e: Throwable =>\n        fail(s\"should be thrown a ${classOf[IllegalArgumentException].getName}, got ${e.getClass} instead\")\n    }\n  }\n\n  @Test\n  def testVersionShouldBeValid(): Unit = {\n    val fullVersion = SparkSession\n      .getDefaultSession\n      .map(_.version)\n      .getOrElse(\"3.2\")\n    val baseVersion = fullVersion\n      .split(\"\\\\.\")\n      .take(2)\n      .mkString(\".\")\n    Validations.validate(ValidateSparkMinVersion(s\"$baseVersion.*\"))\n    Validations.validate(ValidateSparkMinVersion(fullVersion))\n    Validations.validate(ValidateSparkMinVersion(s\"$fullVersion-amzn-0\"))\n  }\n\n  @Test\n  def testVersionShouldValidateTheVersion(): Unit = {\n    val version = ValidateSparkMinVersion(\"2.3.0\")\n    junit.Assert.assertTrue(version.isSupported(\"2.3.0-amzn-1\"))\n    junit.Assert.assertTrue(version.isSupported(\"2.3.1-amzn-1\"))\n    junit.Assert.assertTrue(version.isSupported(\"3.3.0-amzn-1\"))\n    junit.Assert.assertTrue(version.isSupported(\"3.3.0\"))\n    junit.Assert.assertTrue(version.isSupported(\"3.1.0\"))\n    junit.Assert.assertTrue(version.isSupported(\"3.2.0\"))\n    junit.Assert.assertFalse(version.isSupported(\"2.2.10\"))\n  }\n\n}\n"
  },
  {
    "path": "dangerfile.mjs",
    "content": "import load from '@commitlint/load';\nimport lint from '@commitlint/lint';\n\nconst minPRDescriptionLength = 10;\n\n// Utility functions\nconst processReport = (type, report, warnOnly = false) => {\n    if (report.warnings.length > 0) {\n        warn(\n            `${type} '${report.input}': ${report.warnings\n                .map((w) => w.message)\n                .join(', ')}`,\n        );\n    }\n\n    if (report.errors.length > 0) {\n        const reportFn = warnOnly ? warn : fail;\n\n        reportFn(\n            `${type} '${report.input}': ${report.errors\n                .map((e) => e.message)\n                .join(', ')}`,\n        );\n    }\n\n    return report.valid || warnOnly ? Promise.resolve() : Promise.reject();\n};\n\nconst reportCommitMessage = (report) => processReport('Commit Message', report, true);\n\nconst reportPRTitle = (report) => processReport('PR Title', report, false);\n\nconst lintMessage = (message, opts, reporter) =>\n    lint(\n        message,\n        opts.rules,\n        opts.parserPreset ? {parserOpts: opts.parserPreset.parserOpts} : {},\n    ).then(reporter);\n\nconst pr = danger.github.pr;\n\n// check commit messages and PR name\nschedule(\n    Promise.all([\n        load({}, {file: './.commitlintrc.json', cwd: process.cwd()}).then(\n            (opts) =>\n                Promise.all(\n                    danger.git.commits\n                        .map((c) => c.message)\n                        .map((m) => lintMessage(m, opts, reportCommitMessage)),\n                )\n                    .catch(() =>\n                        markdown(\n                            '> All commits should follow ' +\n                            '[Conventional commits](https://cheatography.com/albelop/cheat-sheets/conventional-commits). ' +\n                            'It seems some of the commit messages are not following those rules, please fix them.',\n                        ),\n                    )\n                    .then(() => lintMessage(pr.title, opts, reportPRTitle))\n                    .catch(() =>\n                        markdown(\n                            '> Pull request title should follow ' +\n                            '[Conventional commits](https://cheatography.com/albelop/cheat-sheets/conventional-commits).',\n                        ),\n                    ),\n        ),\n        new Promise((resolve, reject) => {\n            // No PR is too small to include a description of why you made a change\n            if (pr.body.length < minPRDescriptionLength) {\n                warn(`:exclamation: Please include a description of your PR changes.`);\n\n                markdown(\n                    '> Pull request should have a description of the underlying changes.',\n                );\n            }\n        }),\n    ]),\n);\n"
  },
  {
    "path": "examples/neo4j_data_engineering.ipynb",
    "content": "{\n  \"cells\": [\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"Open this notebook in Google Colab <a target=\\\"_blank\\\" href=\\\"https://colab.research.google.com/github/neo4j/neo4j-spark-connector/blob/5.0/examples/neo4j_data_engineering.ipynb\\\">\\n\",\n        \"  <img src=\\\"https://colab.research.google.com/assets/colab-badge.svg\\\" alt=\\\"Open In Colab\\\"/>\\n\",\n        \"</a>\"\n      ],\n      \"metadata\": {\n        \"id\": \"EhTThKJMxDCy\"\n      }\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"7Nvb-_bYx359\"\n      },\n      \"source\": [\n        \"# Example of a Simple data engineering workflow with Neo4j and Spark\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"This notebook contains a set of examples that explains how to extract insights from data using the Neo4j Connector for Apache Spark in a Data Engineering workflow with [AuraDB](https://neo4j.com/docs/aura/auradb/) our fully managed version of Neo4j database.\\n\",\n        \"\\n\",\n        \"The notebooks will enable you to test your knowledge with a set of exercises after each section.\\n\",\n        \"\\n\",\n        \"If you have any questions or problems feel free to write a post in the [Neo4j community forum](https://community.neo4j.com/) or in [Discord](https://discord.com/invite/neo4j).\\n\",\n        \"\\n\",\n        \"If you want more exercises feel free to open an issue in the [GitHub repository](https://github.com/neo4j/neo4j-spark-connector).\\n\",\n        \"\\n\",\n        \"Enjoy!\"\n      ],\n      \"metadata\": {\n        \"id\": \"e0bo6ido8tL7\"\n      }\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"hXwkjQMnMXED\"\n      },\n      \"source\": [\n        \"### Configure the Spark Environment\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"BhZwh-RAz6Bo\"\n      },\n      \"outputs\": [],\n      \"source\": [\n        \"!apt-get install openjdk-17-jdk-headless -qq > /dev/null\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"spark_version = '3.3.4'\"\n      ],\n      \"metadata\": {\n        \"id\": \"gmEzhrux7Jek\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"!wget -q https://dlcdn.apache.org/spark/spark-$spark_version/spark-$spark_version-bin-hadoop3.tgz\"\n      ],\n      \"metadata\": {\n        \"id\": \"Ya6Nj_u3vdTL\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"A3gsnSHl0F99\"\n      },\n      \"outputs\": [],\n      \"source\": [\n        \"!tar xf spark-$spark_version-bin-hadoop3.tgz\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"hSBQWKs90vSx\"\n      },\n      \"outputs\": [],\n      \"source\": [\n        \"!pip install -q findspark\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"tnW0a1Gj080k\"\n      },\n      \"outputs\": [],\n      \"source\": [\n        \"import os\\n\",\n        \"os.environ[\\\"JAVA_HOME\\\"] = \\\"/usr/lib/jvm/java-17-openjdk-amd64\\\"\\n\",\n        \"os.environ[\\\"SPARK_HOME\\\"] = f\\\"/content/spark-{spark_version}-bin-hadoop3\\\"\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"dlUBSezK1DpZ\"\n      },\n      \"outputs\": [],\n      \"source\": [\n        \"import findspark\\n\",\n        \"findspark.init()\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"rd5KWGQiOVDV\"\n      },\n      \"outputs\": [],\n      \"source\": [\n        \"neo4j_url = \\\"\\\" # put your neo4j url here\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"uXbi_82KOTzU\"\n      },\n      \"outputs\": [],\n      \"source\": [\n        \"neo4j_user = \\\"neo4j\\\" # put your neo4j user here\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"Sw50wjxxOUqt\"\n      },\n      \"outputs\": [],\n      \"source\": [\n        \"neo4j_password = \\\"\\\" # put your neo4j password here\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"dOUJ-W871Tur\"\n      },\n      \"outputs\": [],\n      \"source\": [\n        \"from pyspark.sql import SparkSession\\n\",\n        \"spark = (SparkSession.builder\\n\",\n        \"        .master('local[*]')\\n\",\n        \"        .appName('Data engineering workflow with Neo4j and Spark')\\n\",\n        \"        .config('spark.ui.port', '4050')\\n\",\n        \"        # Just to show dataframes as tables\\n\",\n        \"        .config('spark.sql.repl.eagerEval.enabled', True)\\n\",\n        \"        .config('spark.jars.packages', 'org.neo4j:neo4j-connector-apache-spark_2.12:5.1.0_for_spark_3')\\n\",\n        \"        # As we're using always the same database instance we'll\\n\",\n        \"        # define them as global variables\\n\",\n        \"        # so we don't need to repeat them each time\\n\",\n        \"        .config(\\\"neo4j.url\\\", neo4j_url)\\n\",\n        \"        .config(\\\"neo4j.authentication.type\\\", \\\"basic\\\")\\n\",\n        \"        .config(\\\"neo4j.authentication.basic.username\\\", neo4j_user)\\n\",\n        \"        .config(\\\"neo4j.authentication.basic.password\\\", neo4j_password)\\n\",\n        \"        .getOrCreate())\\n\",\n        \"spark\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"\\n\",\n        \"## Exercises prerequisite\\n\",\n        \"\\n\",\n        \"In this notebook we and going to test your knowledge. Some of the exercises require the Neo4j Python driver to check if the exercises are being solved correctly.\\n\",\n        \"\\n\",\n        \"*Neo4j Python Driver is required only for verifying the exercises when you persist data from Spark to Neo4j*\\n\",\n        \"\\n\",\n        \"**It's not required by the Spark connector!!!**\\n\",\n        \"\\n\",\n        \"We'll use [Cy2Py](https://github.com/conker84/cy2py), a Jupyter extension that easily allows you to connect to Neo4j and visualize data from Jupyter notebooks.\\n\",\n        \"For a detailed instruction about how to use it please dive into [this example](https://github.com/conker84/cy2py/blob/main/examples/Neo4j_Crime_Investigation_Dataset.ipynb)\"\n      ],\n      \"metadata\": {\n        \"id\": \"b6_YNZnZ5GdT\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"!pip install -q cy2py\"\n      ],\n      \"metadata\": {\n        \"id\": \"f5ZZJylo5Bbz\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"CsnO4C9X7vK0\"\n      },\n      \"source\": [\n        \"### Configure an Aura instance\\n\",\n        \"\\n\",\n        \"<center>\\n\",\n        \"<h3>Neo4j Aura DB is a fully managed cloud service: The zero-admin, always-on graph database for cloud developers.</h3>\\n\",\n        \"\\n\",\n        \"Create a [free instance](https://console.neo4j.io/?ref=aura-lp&mpp=4bfb2414ab973c741b6f067bf06d5575&mpid=17f40ce03ac883-0f09bb214466c1-37677109-1ea000-17f40ce03ad975&_gl=1*ql4f6s*_ga*MTc2OTMwNjEwMy4xNjQ5NDI3MDE0*_ga_DL38Q8KGQC*MTY1MzQxMDQzMC43OS4xLjE2NTM0MTA3MjQuMA..&_ga=2.136543024.1659283742.1653295079-1769306103.1649427014&_gac=1.216269284.1653306922.CjwKCAjw4ayUBhA4EiwATWyBrl6dN0oaH9_btCfvzdhi77ieNP07GAkOYuz7wx9QEewBnG_FUIMg8xoCgLsQAvD_BwE)\\n\",\n        \"\\n\",\n        \"</center>\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"let's load the extension\"\n      ],\n      \"metadata\": {\n        \"id\": \"uKYEPEgOcG2b\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"%load_ext cy2py\"\n      ],\n      \"metadata\": {\n        \"id\": \"38EeXF6icKOK\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"#### Populate the database\\n\",\n        \"\\n\",\n        \"To perform this section go in the Neo4j Brower of your aura instance and paste the following query:\\n\",\n        \"\\n\",\n        \"<details>\\n\",\n        \"<summary>\\n\",\n        \"Show the Cypher query\\n\",\n        \"</summary>\\n\",\n        \"\\n\",\n        \"```cypher\\n\",\n        \"CREATE (TheMatrix:Movie {title:'The Matrix', released:1999, tagline:'Welcome to the Real World'})\\n\",\n        \"CREATE (Keanu:Person {name:'Keanu Reeves', born:1964})\\n\",\n        \"CREATE (Carrie:Person {name:'Carrie-Anne Moss', born:1967})\\n\",\n        \"CREATE (Laurence:Person {name:'Laurence Fishburne', born:1961})\\n\",\n        \"CREATE (Hugo:Person {name:'Hugo Weaving', born:1960})\\n\",\n        \"CREATE (LillyW:Person {name:'Lilly Wachowski', born:1967})\\n\",\n        \"CREATE (LanaW:Person {name:'Lana Wachowski', born:1965})\\n\",\n        \"CREATE (JoelS:Person {name:'Joel Silver', born:1952})\\n\",\n        \"CREATE\\n\",\n        \"(Keanu)-[:ACTED_IN {roles:['Neo']}]->(TheMatrix),\\n\",\n        \"(Carrie)-[:ACTED_IN {roles:['Trinity']}]->(TheMatrix),\\n\",\n        \"(Laurence)-[:ACTED_IN {roles:['Morpheus']}]->(TheMatrix),\\n\",\n        \"(Hugo)-[:ACTED_IN {roles:['Agent Smith']}]->(TheMatrix),\\n\",\n        \"(LillyW)-[:DIRECTED]->(TheMatrix),\\n\",\n        \"(LanaW)-[:DIRECTED]->(TheMatrix),\\n\",\n        \"(JoelS)-[:PRODUCED]->(TheMatrix)\\n\",\n        \"\\n\",\n        \"CREATE (Emil:Person {name:\\\"Emil Eifrem\\\", born:1978})\\n\",\n        \"CREATE (Emil)-[:ACTED_IN {roles:[\\\"Emil\\\"]}]->(TheMatrix)\\n\",\n        \"\\n\",\n        \"CREATE (TheMatrixReloaded:Movie {title:'The Matrix Reloaded', released:2003, tagline:'Free your mind'})\\n\",\n        \"CREATE\\n\",\n        \"(Keanu)-[:ACTED_IN {roles:['Neo']}]->(TheMatrixReloaded),\\n\",\n        \"(Carrie)-[:ACTED_IN {roles:['Trinity']}]->(TheMatrixReloaded),\\n\",\n        \"(Laurence)-[:ACTED_IN {roles:['Morpheus']}]->(TheMatrixReloaded),\\n\",\n        \"(Hugo)-[:ACTED_IN {roles:['Agent Smith']}]->(TheMatrixReloaded),\\n\",\n        \"(LillyW)-[:DIRECTED]->(TheMatrixReloaded),\\n\",\n        \"(LanaW)-[:DIRECTED]->(TheMatrixReloaded),\\n\",\n        \"(JoelS)-[:PRODUCED]->(TheMatrixReloaded)\\n\",\n        \"\\n\",\n        \"CREATE (TheMatrixRevolutions:Movie {title:'The Matrix Revolutions', released:2003, tagline:'Everything that has a beginning has an end'})\\n\",\n        \"CREATE\\n\",\n        \"(Keanu)-[:ACTED_IN {roles:['Neo']}]->(TheMatrixRevolutions),\\n\",\n        \"(Carrie)-[:ACTED_IN {roles:['Trinity']}]->(TheMatrixRevolutions),\\n\",\n        \"(Laurence)-[:ACTED_IN {roles:['Morpheus']}]->(TheMatrixRevolutions),\\n\",\n        \"(Hugo)-[:ACTED_IN {roles:['Agent Smith']}]->(TheMatrixRevolutions),\\n\",\n        \"(LillyW)-[:DIRECTED]->(TheMatrixRevolutions),\\n\",\n        \"(LanaW)-[:DIRECTED]->(TheMatrixRevolutions),\\n\",\n        \"(JoelS)-[:PRODUCED]->(TheMatrixRevolutions)\\n\",\n        \"\\n\",\n        \"CREATE (TheDevilsAdvocate:Movie {title:\\\"The Devil's Advocate\\\", released:1997, tagline:'Evil has its winning ways'})\\n\",\n        \"CREATE (Charlize:Person {name:'Charlize Theron', born:1975})\\n\",\n        \"CREATE (Al:Person {name:'Al Pacino', born:1940})\\n\",\n        \"CREATE (Taylor:Person {name:'Taylor Hackford', born:1944})\\n\",\n        \"CREATE\\n\",\n        \"(Keanu)-[:ACTED_IN {roles:['Kevin Lomax']}]->(TheDevilsAdvocate),\\n\",\n        \"(Charlize)-[:ACTED_IN {roles:['Mary Ann Lomax']}]->(TheDevilsAdvocate),\\n\",\n        \"(Al)-[:ACTED_IN {roles:['John Milton']}]->(TheDevilsAdvocate),\\n\",\n        \"(Taylor)-[:DIRECTED]->(TheDevilsAdvocate)\\n\",\n        \"\\n\",\n        \"CREATE (AFewGoodMen:Movie {title:\\\"A Few Good Men\\\", released:1992, tagline:\\\"In the heart of the nation's capital, in a courthouse of the U.S. government, one man will stop at nothing to keep his honor, and one will stop at nothing to find the truth.\\\"})\\n\",\n        \"CREATE (TomC:Person {name:'Tom Cruise', born:1962})\\n\",\n        \"CREATE (JackN:Person {name:'Jack Nicholson', born:1937})\\n\",\n        \"CREATE (DemiM:Person {name:'Demi Moore', born:1962})\\n\",\n        \"CREATE (KevinB:Person {name:'Kevin Bacon', born:1958})\\n\",\n        \"CREATE (KieferS:Person {name:'Kiefer Sutherland', born:1966})\\n\",\n        \"CREATE (NoahW:Person {name:'Noah Wyle', born:1971})\\n\",\n        \"CREATE (CubaG:Person {name:'Cuba Gooding Jr.', born:1968})\\n\",\n        \"CREATE (KevinP:Person {name:'Kevin Pollak', born:1957})\\n\",\n        \"CREATE (JTW:Person {name:'J.T. Walsh', born:1943})\\n\",\n        \"CREATE (JamesM:Person {name:'James Marshall', born:1967})\\n\",\n        \"CREATE (ChristopherG:Person {name:'Christopher Guest', born:1948})\\n\",\n        \"CREATE (RobR:Person {name:'Rob Reiner', born:1947})\\n\",\n        \"CREATE (AaronS:Person {name:'Aaron Sorkin', born:1961})\\n\",\n        \"CREATE\\n\",\n        \"(TomC)-[:ACTED_IN {roles:['Lt. Daniel Kaffee']}]->(AFewGoodMen),\\n\",\n        \"(JackN)-[:ACTED_IN {roles:['Col. Nathan R. Jessup']}]->(AFewGoodMen),\\n\",\n        \"(DemiM)-[:ACTED_IN {roles:['Lt. Cdr. JoAnne Galloway']}]->(AFewGoodMen),\\n\",\n        \"(KevinB)-[:ACTED_IN {roles:['Capt. Jack Ross']}]->(AFewGoodMen),\\n\",\n        \"(KieferS)-[:ACTED_IN {roles:['Lt. Jonathan Kendrick']}]->(AFewGoodMen),\\n\",\n        \"(NoahW)-[:ACTED_IN {roles:['Cpl. Jeffrey Barnes']}]->(AFewGoodMen),\\n\",\n        \"(CubaG)-[:ACTED_IN {roles:['Cpl. Carl Hammaker']}]->(AFewGoodMen),\\n\",\n        \"(KevinP)-[:ACTED_IN {roles:['Lt. Sam Weinberg']}]->(AFewGoodMen),\\n\",\n        \"(JTW)-[:ACTED_IN {roles:['Lt. Col. Matthew Andrew Markinson']}]->(AFewGoodMen),\\n\",\n        \"(JamesM)-[:ACTED_IN {roles:['Pfc. Louden Downey']}]->(AFewGoodMen),\\n\",\n        \"(ChristopherG)-[:ACTED_IN {roles:['Dr. Stone']}]->(AFewGoodMen),\\n\",\n        \"(AaronS)-[:ACTED_IN {roles:['Man in Bar']}]->(AFewGoodMen),\\n\",\n        \"(RobR)-[:DIRECTED]->(AFewGoodMen),\\n\",\n        \"(AaronS)-[:WROTE]->(AFewGoodMen)\\n\",\n        \"\\n\",\n        \"CREATE (TopGun:Movie {title:\\\"Top Gun\\\", released:1986, tagline:'I feel the need, the need for speed.'})\\n\",\n        \"CREATE (KellyM:Person {name:'Kelly McGillis', born:1957})\\n\",\n        \"CREATE (ValK:Person {name:'Val Kilmer', born:1959})\\n\",\n        \"CREATE (AnthonyE:Person {name:'Anthony Edwards', born:1962})\\n\",\n        \"CREATE (TomS:Person {name:'Tom Skerritt', born:1933})\\n\",\n        \"CREATE (MegR:Person {name:'Meg Ryan', born:1961})\\n\",\n        \"CREATE (TonyS:Person {name:'Tony Scott', born:1944})\\n\",\n        \"CREATE (JimC:Person {name:'Jim Cash', born:1941})\\n\",\n        \"CREATE\\n\",\n        \"(TomC)-[:ACTED_IN {roles:['Maverick']}]->(TopGun),\\n\",\n        \"(KellyM)-[:ACTED_IN {roles:['Charlie']}]->(TopGun),\\n\",\n        \"(ValK)-[:ACTED_IN {roles:['Iceman']}]->(TopGun),\\n\",\n        \"(AnthonyE)-[:ACTED_IN {roles:['Goose']}]->(TopGun),\\n\",\n        \"(TomS)-[:ACTED_IN {roles:['Viper']}]->(TopGun),\\n\",\n        \"(MegR)-[:ACTED_IN {roles:['Carole']}]->(TopGun),\\n\",\n        \"(TonyS)-[:DIRECTED]->(TopGun),\\n\",\n        \"(JimC)-[:WROTE]->(TopGun)\\n\",\n        \"\\n\",\n        \"CREATE (JerryMaguire:Movie {title:'Jerry Maguire', released:2000, tagline:'The rest of his life begins now.'})\\n\",\n        \"CREATE (ReneeZ:Person {name:'Renee Zellweger', born:1969})\\n\",\n        \"CREATE (KellyP:Person {name:'Kelly Preston', born:1962})\\n\",\n        \"CREATE (JerryO:Person {name:\\\"Jerry O'Connell\\\", born:1974})\\n\",\n        \"CREATE (JayM:Person {name:'Jay Mohr', born:1970})\\n\",\n        \"CREATE (BonnieH:Person {name:'Bonnie Hunt', born:1961})\\n\",\n        \"CREATE (ReginaK:Person {name:'Regina King', born:1971})\\n\",\n        \"CREATE (JonathanL:Person {name:'Jonathan Lipnicki', born:1996})\\n\",\n        \"CREATE (CameronC:Person {name:'Cameron Crowe', born:1957})\\n\",\n        \"CREATE\\n\",\n        \"(TomC)-[:ACTED_IN {roles:['Jerry Maguire']}]->(JerryMaguire),\\n\",\n        \"(CubaG)-[:ACTED_IN {roles:['Rod Tidwell']}]->(JerryMaguire),\\n\",\n        \"(ReneeZ)-[:ACTED_IN {roles:['Dorothy Boyd']}]->(JerryMaguire),\\n\",\n        \"(KellyP)-[:ACTED_IN {roles:['Avery Bishop']}]->(JerryMaguire),\\n\",\n        \"(JerryO)-[:ACTED_IN {roles:['Frank Cushman']}]->(JerryMaguire),\\n\",\n        \"(JayM)-[:ACTED_IN {roles:['Bob Sugar']}]->(JerryMaguire),\\n\",\n        \"(BonnieH)-[:ACTED_IN {roles:['Laurel Boyd']}]->(JerryMaguire),\\n\",\n        \"(ReginaK)-[:ACTED_IN {roles:['Marcee Tidwell']}]->(JerryMaguire),\\n\",\n        \"(JonathanL)-[:ACTED_IN {roles:['Ray Boyd']}]->(JerryMaguire),\\n\",\n        \"(CameronC)-[:DIRECTED]->(JerryMaguire),\\n\",\n        \"(CameronC)-[:PRODUCED]->(JerryMaguire),\\n\",\n        \"(CameronC)-[:WROTE]->(JerryMaguire)\\n\",\n        \"\\n\",\n        \"CREATE (StandByMe:Movie {title:\\\"Stand By Me\\\", released:1986, tagline:\\\"For some, it's the last real taste of innocence, and the first real taste of life. But for everyone, it's the time that memories are made of.\\\"})\\n\",\n        \"CREATE (RiverP:Person {name:'River Phoenix', born:1970})\\n\",\n        \"CREATE (CoreyF:Person {name:'Corey Feldman', born:1971})\\n\",\n        \"CREATE (WilW:Person {name:'Wil Wheaton', born:1972})\\n\",\n        \"CREATE (JohnC:Person {name:'John Cusack', born:1966})\\n\",\n        \"CREATE (MarshallB:Person {name:'Marshall Bell', born:1942})\\n\",\n        \"CREATE\\n\",\n        \"(WilW)-[:ACTED_IN {roles:['Gordie Lachance']}]->(StandByMe),\\n\",\n        \"(RiverP)-[:ACTED_IN {roles:['Chris Chambers']}]->(StandByMe),\\n\",\n        \"(JerryO)-[:ACTED_IN {roles:['Vern Tessio']}]->(StandByMe),\\n\",\n        \"(CoreyF)-[:ACTED_IN {roles:['Teddy Duchamp']}]->(StandByMe),\\n\",\n        \"(JohnC)-[:ACTED_IN {roles:['Denny Lachance']}]->(StandByMe),\\n\",\n        \"(KieferS)-[:ACTED_IN {roles:['Ace Merrill']}]->(StandByMe),\\n\",\n        \"(MarshallB)-[:ACTED_IN {roles:['Mr. Lachance']}]->(StandByMe),\\n\",\n        \"(RobR)-[:DIRECTED]->(StandByMe)\\n\",\n        \"\\n\",\n        \"CREATE (AsGoodAsItGets:Movie {title:'As Good as It Gets', released:1997, tagline:'A comedy from the heart that goes for the throat.'})\\n\",\n        \"CREATE (HelenH:Person {name:'Helen Hunt', born:1963})\\n\",\n        \"CREATE (GregK:Person {name:'Greg Kinnear', born:1963})\\n\",\n        \"CREATE (JamesB:Person {name:'James L. Brooks', born:1940})\\n\",\n        \"CREATE\\n\",\n        \"(JackN)-[:ACTED_IN {roles:['Melvin Udall']}]->(AsGoodAsItGets),\\n\",\n        \"(HelenH)-[:ACTED_IN {roles:['Carol Connelly']}]->(AsGoodAsItGets),\\n\",\n        \"(GregK)-[:ACTED_IN {roles:['Simon Bishop']}]->(AsGoodAsItGets),\\n\",\n        \"(CubaG)-[:ACTED_IN {roles:['Frank Sachs']}]->(AsGoodAsItGets),\\n\",\n        \"(JamesB)-[:DIRECTED]->(AsGoodAsItGets)\\n\",\n        \"\\n\",\n        \"CREATE (WhatDreamsMayCome:Movie {title:'What Dreams May Come', released:1998, tagline:'After life there is more. The end is just the beginning.'})\\n\",\n        \"CREATE (AnnabellaS:Person {name:'Annabella Sciorra', born:1960})\\n\",\n        \"CREATE (MaxS:Person {name:'Max von Sydow', born:1929})\\n\",\n        \"CREATE (WernerH:Person {name:'Werner Herzog', born:1942})\\n\",\n        \"CREATE (Robin:Person {name:'Robin Williams', born:1951})\\n\",\n        \"CREATE (VincentW:Person {name:'Vincent Ward', born:1956})\\n\",\n        \"CREATE\\n\",\n        \"(Robin)-[:ACTED_IN {roles:['Chris Nielsen']}]->(WhatDreamsMayCome),\\n\",\n        \"(CubaG)-[:ACTED_IN {roles:['Albert Lewis']}]->(WhatDreamsMayCome),\\n\",\n        \"(AnnabellaS)-[:ACTED_IN {roles:['Annie Collins-Nielsen']}]->(WhatDreamsMayCome),\\n\",\n        \"(MaxS)-[:ACTED_IN {roles:['The Tracker']}]->(WhatDreamsMayCome),\\n\",\n        \"(WernerH)-[:ACTED_IN {roles:['The Face']}]->(WhatDreamsMayCome),\\n\",\n        \"(VincentW)-[:DIRECTED]->(WhatDreamsMayCome)\\n\",\n        \"\\n\",\n        \"CREATE (SnowFallingonCedars:Movie {title:'Snow Falling on Cedars', released:1999, tagline:'First loves last. Forever.'})\\n\",\n        \"CREATE (EthanH:Person {name:'Ethan Hawke', born:1970})\\n\",\n        \"CREATE (RickY:Person {name:'Rick Yune', born:1971})\\n\",\n        \"CREATE (JamesC:Person {name:'James Cromwell', born:1940})\\n\",\n        \"CREATE (ScottH:Person {name:'Scott Hicks', born:1953})\\n\",\n        \"CREATE\\n\",\n        \"(EthanH)-[:ACTED_IN {roles:['Ishmael Chambers']}]->(SnowFallingonCedars),\\n\",\n        \"(RickY)-[:ACTED_IN {roles:['Kazuo Miyamoto']}]->(SnowFallingonCedars),\\n\",\n        \"(MaxS)-[:ACTED_IN {roles:['Nels Gudmundsson']}]->(SnowFallingonCedars),\\n\",\n        \"(JamesC)-[:ACTED_IN {roles:['Judge Fielding']}]->(SnowFallingonCedars),\\n\",\n        \"(ScottH)-[:DIRECTED]->(SnowFallingonCedars)\\n\",\n        \"\\n\",\n        \"CREATE (YouveGotMail:Movie {title:\\\"You've Got Mail\\\", released:1998, tagline:'At odds in life... in love on-line.'})\\n\",\n        \"CREATE (ParkerP:Person {name:'Parker Posey', born:1968})\\n\",\n        \"CREATE (DaveC:Person {name:'Dave Chappelle', born:1973})\\n\",\n        \"CREATE (SteveZ:Person {name:'Steve Zahn', born:1967})\\n\",\n        \"CREATE (TomH:Person {name:'Tom Hanks', born:1956})\\n\",\n        \"CREATE (NoraE:Person {name:'Nora Ephron', born:1941})\\n\",\n        \"CREATE\\n\",\n        \"(TomH)-[:ACTED_IN {roles:['Joe Fox']}]->(YouveGotMail),\\n\",\n        \"(MegR)-[:ACTED_IN {roles:['Kathleen Kelly']}]->(YouveGotMail),\\n\",\n        \"(GregK)-[:ACTED_IN {roles:['Frank Navasky']}]->(YouveGotMail),\\n\",\n        \"(ParkerP)-[:ACTED_IN {roles:['Patricia Eden']}]->(YouveGotMail),\\n\",\n        \"(DaveC)-[:ACTED_IN {roles:['Kevin Jackson']}]->(YouveGotMail),\\n\",\n        \"(SteveZ)-[:ACTED_IN {roles:['George Pappas']}]->(YouveGotMail),\\n\",\n        \"(NoraE)-[:DIRECTED]->(YouveGotMail)\\n\",\n        \"\\n\",\n        \"CREATE (SleeplessInSeattle:Movie {title:'Sleepless in Seattle', released:1993, tagline:'What if someone you never met, someone you never saw, someone you never knew was the only someone for you?'})\\n\",\n        \"CREATE (RitaW:Person {name:'Rita Wilson', born:1956})\\n\",\n        \"CREATE (BillPull:Person {name:'Bill Pullman', born:1953})\\n\",\n        \"CREATE (VictorG:Person {name:'Victor Garber', born:1949})\\n\",\n        \"CREATE (RosieO:Person {name:\\\"Rosie O'Donnell\\\", born:1962})\\n\",\n        \"CREATE\\n\",\n        \"(TomH)-[:ACTED_IN {roles:['Sam Baldwin']}]->(SleeplessInSeattle),\\n\",\n        \"(MegR)-[:ACTED_IN {roles:['Annie Reed']}]->(SleeplessInSeattle),\\n\",\n        \"(RitaW)-[:ACTED_IN {roles:['Suzy']}]->(SleeplessInSeattle),\\n\",\n        \"(BillPull)-[:ACTED_IN {roles:['Walter']}]->(SleeplessInSeattle),\\n\",\n        \"(VictorG)-[:ACTED_IN {roles:['Greg']}]->(SleeplessInSeattle),\\n\",\n        \"(RosieO)-[:ACTED_IN {roles:['Becky']}]->(SleeplessInSeattle),\\n\",\n        \"(NoraE)-[:DIRECTED]->(SleeplessInSeattle)\\n\",\n        \"\\n\",\n        \"CREATE (JoeVersustheVolcano:Movie {title:'Joe Versus the Volcano', released:1990, tagline:'A story of love, lava and burning desire.'})\\n\",\n        \"CREATE (JohnS:Person {name:'John Patrick Stanley', born:1950})\\n\",\n        \"CREATE (Nathan:Person {name:'Nathan Lane', born:1956})\\n\",\n        \"CREATE\\n\",\n        \"(TomH)-[:ACTED_IN {roles:['Joe Banks']}]->(JoeVersustheVolcano),\\n\",\n        \"(MegR)-[:ACTED_IN {roles:['DeDe', 'Angelica Graynamore', 'Patricia Graynamore']}]->(JoeVersustheVolcano),\\n\",\n        \"(Nathan)-[:ACTED_IN {roles:['Baw']}]->(JoeVersustheVolcano),\\n\",\n        \"(JohnS)-[:DIRECTED]->(JoeVersustheVolcano)\\n\",\n        \"\\n\",\n        \"CREATE (WhenHarryMetSally:Movie {title:'When Harry Met Sally', released:1998, tagline:'Can two friends sleep together and still love each other in the morning?'})\\n\",\n        \"CREATE (BillyC:Person {name:'Billy Crystal', born:1948})\\n\",\n        \"CREATE (CarrieF:Person {name:'Carrie Fisher', born:1956})\\n\",\n        \"CREATE (BrunoK:Person {name:'Bruno Kirby', born:1949})\\n\",\n        \"CREATE\\n\",\n        \"(BillyC)-[:ACTED_IN {roles:['Harry Burns']}]->(WhenHarryMetSally),\\n\",\n        \"(MegR)-[:ACTED_IN {roles:['Sally Albright']}]->(WhenHarryMetSally),\\n\",\n        \"(CarrieF)-[:ACTED_IN {roles:['Marie']}]->(WhenHarryMetSally),\\n\",\n        \"(BrunoK)-[:ACTED_IN {roles:['Jess']}]->(WhenHarryMetSally),\\n\",\n        \"(RobR)-[:DIRECTED]->(WhenHarryMetSally),\\n\",\n        \"(RobR)-[:PRODUCED]->(WhenHarryMetSally),\\n\",\n        \"(NoraE)-[:PRODUCED]->(WhenHarryMetSally),\\n\",\n        \"(NoraE)-[:WROTE]->(WhenHarryMetSally)\\n\",\n        \"\\n\",\n        \"CREATE (ThatThingYouDo:Movie {title:'That Thing You Do', released:1996, tagline:'In every life there comes a time when that thing you dream becomes that thing you do'})\\n\",\n        \"CREATE (LivT:Person {name:'Liv Tyler', born:1977})\\n\",\n        \"CREATE\\n\",\n        \"(TomH)-[:ACTED_IN {roles:['Mr. White']}]->(ThatThingYouDo),\\n\",\n        \"(LivT)-[:ACTED_IN {roles:['Faye Dolan']}]->(ThatThingYouDo),\\n\",\n        \"(Charlize)-[:ACTED_IN {roles:['Tina']}]->(ThatThingYouDo),\\n\",\n        \"(TomH)-[:DIRECTED]->(ThatThingYouDo)\\n\",\n        \"\\n\",\n        \"CREATE (TheReplacements:Movie {title:'The Replacements', released:2000, tagline:'Pain heals, Chicks dig scars... Glory lasts forever'})\\n\",\n        \"CREATE (Brooke:Person {name:'Brooke Langton', born:1970})\\n\",\n        \"CREATE (Gene:Person {name:'Gene Hackman', born:1930})\\n\",\n        \"CREATE (Orlando:Person {name:'Orlando Jones', born:1968})\\n\",\n        \"CREATE (Howard:Person {name:'Howard Deutch', born:1950})\\n\",\n        \"CREATE\\n\",\n        \"(Keanu)-[:ACTED_IN {roles:['Shane Falco']}]->(TheReplacements),\\n\",\n        \"(Brooke)-[:ACTED_IN {roles:['Annabelle Farrell']}]->(TheReplacements),\\n\",\n        \"(Gene)-[:ACTED_IN {roles:['Jimmy McGinty']}]->(TheReplacements),\\n\",\n        \"(Orlando)-[:ACTED_IN {roles:['Clifford Franklin']}]->(TheReplacements),\\n\",\n        \"(Howard)-[:DIRECTED]->(TheReplacements)\\n\",\n        \"\\n\",\n        \"CREATE (RescueDawn:Movie {title:'RescueDawn', released:2006, tagline:\\\"Based on the extraordinary true story of one man's fight for freedom\\\"})\\n\",\n        \"CREATE (ChristianB:Person {name:'Christian Bale', born:1974})\\n\",\n        \"CREATE (ZachG:Person {name:'Zach Grenier', born:1954})\\n\",\n        \"CREATE\\n\",\n        \"(MarshallB)-[:ACTED_IN {roles:['Admiral']}]->(RescueDawn),\\n\",\n        \"(ChristianB)-[:ACTED_IN {roles:['Dieter Dengler']}]->(RescueDawn),\\n\",\n        \"(ZachG)-[:ACTED_IN {roles:['Squad Leader']}]->(RescueDawn),\\n\",\n        \"(SteveZ)-[:ACTED_IN {roles:['Duane']}]->(RescueDawn),\\n\",\n        \"(WernerH)-[:DIRECTED]->(RescueDawn)\\n\",\n        \"\\n\",\n        \"CREATE (TheBirdcage:Movie {title:'The Birdcage', released:1996, tagline:'Come as you are'})\\n\",\n        \"CREATE (MikeN:Person {name:'Mike Nichols', born:1931})\\n\",\n        \"CREATE\\n\",\n        \"(Robin)-[:ACTED_IN {roles:['Armand Goldman']}]->(TheBirdcage),\\n\",\n        \"(Nathan)-[:ACTED_IN {roles:['Albert Goldman']}]->(TheBirdcage),\\n\",\n        \"(Gene)-[:ACTED_IN {roles:['Sen. Kevin Keeley']}]->(TheBirdcage),\\n\",\n        \"(MikeN)-[:DIRECTED]->(TheBirdcage)\\n\",\n        \"\\n\",\n        \"CREATE (Unforgiven:Movie {title:'Unforgiven', released:1992, tagline:\\\"It's a hell of a thing, killing a man\\\"})\\n\",\n        \"CREATE (RichardH:Person {name:'Richard Harris', born:1930})\\n\",\n        \"CREATE (ClintE:Person {name:'Clint Eastwood', born:1930})\\n\",\n        \"CREATE\\n\",\n        \"(RichardH)-[:ACTED_IN {roles:['English Bob']}]->(Unforgiven),\\n\",\n        \"(ClintE)-[:ACTED_IN {roles:['Bill Munny']}]->(Unforgiven),\\n\",\n        \"(Gene)-[:ACTED_IN {roles:['Little Bill Daggett']}]->(Unforgiven),\\n\",\n        \"(ClintE)-[:DIRECTED]->(Unforgiven)\\n\",\n        \"\\n\",\n        \"CREATE (JohnnyMnemonic:Movie {title:'Johnny Mnemonic', released:1995, tagline:'The hottest data on earth. In the coolest head in town'})\\n\",\n        \"CREATE (Takeshi:Person {name:'Takeshi Kitano', born:1947})\\n\",\n        \"CREATE (Dina:Person {name:'Dina Meyer', born:1968})\\n\",\n        \"CREATE (IceT:Person {name:'Ice-T', born:1958})\\n\",\n        \"CREATE (RobertL:Person {name:'Robert Longo', born:1953})\\n\",\n        \"CREATE\\n\",\n        \"(Keanu)-[:ACTED_IN {roles:['Johnny Mnemonic']}]->(JohnnyMnemonic),\\n\",\n        \"(Takeshi)-[:ACTED_IN {roles:['Takahashi']}]->(JohnnyMnemonic),\\n\",\n        \"(Dina)-[:ACTED_IN {roles:['Jane']}]->(JohnnyMnemonic),\\n\",\n        \"(IceT)-[:ACTED_IN {roles:['J-Bone']}]->(JohnnyMnemonic),\\n\",\n        \"(RobertL)-[:DIRECTED]->(JohnnyMnemonic)\\n\",\n        \"\\n\",\n        \"CREATE (CloudAtlas:Movie {title:'Cloud Atlas', released:2012, tagline:'Everything is connected'})\\n\",\n        \"CREATE (HalleB:Person {name:'Halle Berry', born:1966})\\n\",\n        \"CREATE (JimB:Person {name:'Jim Broadbent', born:1949})\\n\",\n        \"CREATE (TomT:Person {name:'Tom Tykwer', born:1965})\\n\",\n        \"CREATE (DavidMitchell:Person {name:'David Mitchell', born:1969})\\n\",\n        \"CREATE (StefanArndt:Person {name:'Stefan Arndt', born:1961})\\n\",\n        \"CREATE\\n\",\n        \"(TomH)-[:ACTED_IN {roles:['Zachry', 'Dr. Henry Goose', 'Isaac Sachs', 'Dermot Hoggins']}]->(CloudAtlas),\\n\",\n        \"(Hugo)-[:ACTED_IN {roles:['Bill Smoke', 'Haskell Moore', 'Tadeusz Kesselring', 'Nurse Noakes', 'Boardman Mephi', 'Old Georgie']}]->(CloudAtlas),\\n\",\n        \"(HalleB)-[:ACTED_IN {roles:['Luisa Rey', 'Jocasta Ayrs', 'Ovid', 'Meronym']}]->(CloudAtlas),\\n\",\n        \"(JimB)-[:ACTED_IN {roles:['Vyvyan Ayrs', 'Captain Molyneux', 'Timothy Cavendish']}]->(CloudAtlas),\\n\",\n        \"(TomT)-[:DIRECTED]->(CloudAtlas),\\n\",\n        \"(LillyW)-[:DIRECTED]->(CloudAtlas),\\n\",\n        \"(LanaW)-[:DIRECTED]->(CloudAtlas),\\n\",\n        \"(DavidMitchell)-[:WROTE]->(CloudAtlas),\\n\",\n        \"(StefanArndt)-[:PRODUCED]->(CloudAtlas)\\n\",\n        \"\\n\",\n        \"CREATE (TheDaVinciCode:Movie {title:'The Da Vinci Code', released:2006, tagline:'Break The Codes'})\\n\",\n        \"CREATE (IanM:Person {name:'Ian McKellen', born:1939})\\n\",\n        \"CREATE (AudreyT:Person {name:'Audrey Tautou', born:1976})\\n\",\n        \"CREATE (PaulB:Person {name:'Paul Bettany', born:1971})\\n\",\n        \"CREATE (RonH:Person {name:'Ron Howard', born:1954})\\n\",\n        \"CREATE\\n\",\n        \"(TomH)-[:ACTED_IN {roles:['Dr. Robert Langdon']}]->(TheDaVinciCode),\\n\",\n        \"(IanM)-[:ACTED_IN {roles:['Sir Leight Teabing']}]->(TheDaVinciCode),\\n\",\n        \"(AudreyT)-[:ACTED_IN {roles:['Sophie Neveu']}]->(TheDaVinciCode),\\n\",\n        \"(PaulB)-[:ACTED_IN {roles:['Silas']}]->(TheDaVinciCode),\\n\",\n        \"(RonH)-[:DIRECTED]->(TheDaVinciCode)\\n\",\n        \"\\n\",\n        \"CREATE (VforVendetta:Movie {title:'V for Vendetta', released:2006, tagline:'Freedom! Forever!'})\\n\",\n        \"CREATE (NatalieP:Person {name:'Natalie Portman', born:1981})\\n\",\n        \"CREATE (StephenR:Person {name:'Stephen Rea', born:1946})\\n\",\n        \"CREATE (JohnH:Person {name:'John Hurt', born:1940})\\n\",\n        \"CREATE (BenM:Person {name: 'Ben Miles', born:1967})\\n\",\n        \"CREATE\\n\",\n        \"(Hugo)-[:ACTED_IN {roles:['V']}]->(VforVendetta),\\n\",\n        \"(NatalieP)-[:ACTED_IN {roles:['Evey Hammond']}]->(VforVendetta),\\n\",\n        \"(StephenR)-[:ACTED_IN {roles:['Eric Finch']}]->(VforVendetta),\\n\",\n        \"(JohnH)-[:ACTED_IN {roles:['High Chancellor Adam Sutler']}]->(VforVendetta),\\n\",\n        \"(BenM)-[:ACTED_IN {roles:['Dascomb']}]->(VforVendetta),\\n\",\n        \"(JamesM)-[:DIRECTED]->(VforVendetta),\\n\",\n        \"(LillyW)-[:PRODUCED]->(VforVendetta),\\n\",\n        \"(LanaW)-[:PRODUCED]->(VforVendetta),\\n\",\n        \"(JoelS)-[:PRODUCED]->(VforVendetta),\\n\",\n        \"(LillyW)-[:WROTE]->(VforVendetta),\\n\",\n        \"(LanaW)-[:WROTE]->(VforVendetta)\\n\",\n        \"\\n\",\n        \"CREATE (SpeedRacer:Movie {title:'Speed Racer', released:2008, tagline:'Speed has no limits'})\\n\",\n        \"CREATE (EmileH:Person {name:'Emile Hirsch', born:1985})\\n\",\n        \"CREATE (JohnG:Person {name:'John Goodman', born:1960})\\n\",\n        \"CREATE (SusanS:Person {name:'Susan Sarandon', born:1946})\\n\",\n        \"CREATE (MatthewF:Person {name:'Matthew Fox', born:1966})\\n\",\n        \"CREATE (ChristinaR:Person {name:'Christina Ricci', born:1980})\\n\",\n        \"CREATE (Rain:Person {name:'Rain', born:1982})\\n\",\n        \"CREATE\\n\",\n        \"(EmileH)-[:ACTED_IN {roles:['Speed Racer']}]->(SpeedRacer),\\n\",\n        \"(JohnG)-[:ACTED_IN {roles:['Pops']}]->(SpeedRacer),\\n\",\n        \"(SusanS)-[:ACTED_IN {roles:['Mom']}]->(SpeedRacer),\\n\",\n        \"(MatthewF)-[:ACTED_IN {roles:['Racer X']}]->(SpeedRacer),\\n\",\n        \"(ChristinaR)-[:ACTED_IN {roles:['Trixie']}]->(SpeedRacer),\\n\",\n        \"(Rain)-[:ACTED_IN {roles:['Taejo Togokahn']}]->(SpeedRacer),\\n\",\n        \"(BenM)-[:ACTED_IN {roles:['Cass Jones']}]->(SpeedRacer),\\n\",\n        \"(LillyW)-[:DIRECTED]->(SpeedRacer),\\n\",\n        \"(LanaW)-[:DIRECTED]->(SpeedRacer),\\n\",\n        \"(LillyW)-[:WROTE]->(SpeedRacer),\\n\",\n        \"(LanaW)-[:WROTE]->(SpeedRacer),\\n\",\n        \"(JoelS)-[:PRODUCED]->(SpeedRacer)\\n\",\n        \"\\n\",\n        \"CREATE (NinjaAssassin:Movie {title:'Ninja Assassin', released:2009, tagline:'Prepare to enter a secret world of assassins'})\\n\",\n        \"CREATE (NaomieH:Person {name:'Naomie Harris'})\\n\",\n        \"CREATE\\n\",\n        \"(Rain)-[:ACTED_IN {roles:['Raizo']}]->(NinjaAssassin),\\n\",\n        \"(NaomieH)-[:ACTED_IN {roles:['Mika Coretti']}]->(NinjaAssassin),\\n\",\n        \"(RickY)-[:ACTED_IN {roles:['Takeshi']}]->(NinjaAssassin),\\n\",\n        \"(BenM)-[:ACTED_IN {roles:['Ryan Maslow']}]->(NinjaAssassin),\\n\",\n        \"(JamesM)-[:DIRECTED]->(NinjaAssassin),\\n\",\n        \"(LillyW)-[:PRODUCED]->(NinjaAssassin),\\n\",\n        \"(LanaW)-[:PRODUCED]->(NinjaAssassin),\\n\",\n        \"(JoelS)-[:PRODUCED]->(NinjaAssassin)\\n\",\n        \"\\n\",\n        \"CREATE (TheGreenMile:Movie {title:'The Green Mile', released:1999, tagline:\\\"Walk a mile you'll never forget.\\\"})\\n\",\n        \"CREATE (MichaelD:Person {name:'Michael Clarke Duncan', born:1957})\\n\",\n        \"CREATE (DavidM:Person {name:'David Morse', born:1953})\\n\",\n        \"CREATE (SamR:Person {name:'Sam Rockwell', born:1968})\\n\",\n        \"CREATE (GaryS:Person {name:'Gary Sinise', born:1955})\\n\",\n        \"CREATE (PatriciaC:Person {name:'Patricia Clarkson', born:1959})\\n\",\n        \"CREATE (FrankD:Person {name:'Frank Darabont', born:1959})\\n\",\n        \"CREATE\\n\",\n        \"(TomH)-[:ACTED_IN {roles:['Paul Edgecomb']}]->(TheGreenMile),\\n\",\n        \"(MichaelD)-[:ACTED_IN {roles:['John Coffey']}]->(TheGreenMile),\\n\",\n        \"(DavidM)-[:ACTED_IN {roles:['Brutus \\\"Brutal\\\" Howell']}]->(TheGreenMile),\\n\",\n        \"(BonnieH)-[:ACTED_IN {roles:['Jan Edgecomb']}]->(TheGreenMile),\\n\",\n        \"(JamesC)-[:ACTED_IN {roles:['Warden Hal Moores']}]->(TheGreenMile),\\n\",\n        \"(SamR)-[:ACTED_IN {roles:['\\\"Wild Bill\\\" Wharton']}]->(TheGreenMile),\\n\",\n        \"(GaryS)-[:ACTED_IN {roles:['Burt Hammersmith']}]->(TheGreenMile),\\n\",\n        \"(PatriciaC)-[:ACTED_IN {roles:['Melinda Moores']}]->(TheGreenMile),\\n\",\n        \"(FrankD)-[:DIRECTED]->(TheGreenMile)\\n\",\n        \"\\n\",\n        \"CREATE (FrostNixon:Movie {title:'Frost/Nixon', released:2008, tagline:'400 million people were waiting for the truth.'})\\n\",\n        \"CREATE (FrankL:Person {name:'Frank Langella', born:1938})\\n\",\n        \"CREATE (MichaelS:Person {name:'Michael Sheen', born:1969})\\n\",\n        \"CREATE (OliverP:Person {name:'Oliver Platt', born:1960})\\n\",\n        \"CREATE\\n\",\n        \"(FrankL)-[:ACTED_IN {roles:['Richard Nixon']}]->(FrostNixon),\\n\",\n        \"(MichaelS)-[:ACTED_IN {roles:['David Frost']}]->(FrostNixon),\\n\",\n        \"(KevinB)-[:ACTED_IN {roles:['Jack Brennan']}]->(FrostNixon),\\n\",\n        \"(OliverP)-[:ACTED_IN {roles:['Bob Zelnick']}]->(FrostNixon),\\n\",\n        \"(SamR)-[:ACTED_IN {roles:['James Reston, Jr.']}]->(FrostNixon),\\n\",\n        \"(RonH)-[:DIRECTED]->(FrostNixon)\\n\",\n        \"\\n\",\n        \"CREATE (Hoffa:Movie {title:'Hoffa', released:1992, tagline:\\\"He didn't want law. He wanted justice.\\\"})\\n\",\n        \"CREATE (DannyD:Person {name:'Danny DeVito', born:1944})\\n\",\n        \"CREATE (JohnR:Person {name:'John C. Reilly', born:1965})\\n\",\n        \"CREATE\\n\",\n        \"(JackN)-[:ACTED_IN {roles:['Hoffa']}]->(Hoffa),\\n\",\n        \"(DannyD)-[:ACTED_IN {roles:['Robert \\\"Bobby\\\" Ciaro']}]->(Hoffa),\\n\",\n        \"(JTW)-[:ACTED_IN {roles:['Frank Fitzsimmons']}]->(Hoffa),\\n\",\n        \"(JohnR)-[:ACTED_IN {roles:['Peter \\\"Pete\\\" Connelly']}]->(Hoffa),\\n\",\n        \"(DannyD)-[:DIRECTED]->(Hoffa)\\n\",\n        \"\\n\",\n        \"CREATE (Apollo13:Movie {title:'Apollo 13', released:1995, tagline:'Houston, we have a problem.'})\\n\",\n        \"CREATE (EdH:Person {name:'Ed Harris', born:1950})\\n\",\n        \"CREATE (BillPax:Person {name:'Bill Paxton', born:1955})\\n\",\n        \"CREATE\\n\",\n        \"(TomH)-[:ACTED_IN {roles:['Jim Lovell']}]->(Apollo13),\\n\",\n        \"(KevinB)-[:ACTED_IN {roles:['Jack Swigert']}]->(Apollo13),\\n\",\n        \"(EdH)-[:ACTED_IN {roles:['Gene Kranz']}]->(Apollo13),\\n\",\n        \"(BillPax)-[:ACTED_IN {roles:['Fred Haise']}]->(Apollo13),\\n\",\n        \"(GaryS)-[:ACTED_IN {roles:['Ken Mattingly']}]->(Apollo13),\\n\",\n        \"(RonH)-[:DIRECTED]->(Apollo13)\\n\",\n        \"\\n\",\n        \"CREATE (Twister:Movie {title:'Twister', released:1996, tagline:\\\"Don't Breathe. Don't Look Back.\\\"})\\n\",\n        \"CREATE (PhilipH:Person {name:'Philip Seymour Hoffman', born:1967})\\n\",\n        \"CREATE (JanB:Person {name:'Jan de Bont', born:1943})\\n\",\n        \"CREATE\\n\",\n        \"(BillPax)-[:ACTED_IN {roles:['Bill Harding']}]->(Twister),\\n\",\n        \"(HelenH)-[:ACTED_IN {roles:['Dr. Jo Harding']}]->(Twister),\\n\",\n        \"(ZachG)-[:ACTED_IN {roles:['Eddie']}]->(Twister),\\n\",\n        \"(PhilipH)-[:ACTED_IN {roles:['Dustin \\\"Dusty\\\" Davis']}]->(Twister),\\n\",\n        \"(JanB)-[:DIRECTED]->(Twister)\\n\",\n        \"\\n\",\n        \"CREATE (CastAway:Movie {title:'Cast Away', released:2000, tagline:'At the edge of the world, his journey begins.'})\\n\",\n        \"CREATE (RobertZ:Person {name:'Robert Zemeckis', born:1951})\\n\",\n        \"CREATE\\n\",\n        \"(TomH)-[:ACTED_IN {roles:['Chuck Noland']}]->(CastAway),\\n\",\n        \"(HelenH)-[:ACTED_IN {roles:['Kelly Frears']}]->(CastAway),\\n\",\n        \"(RobertZ)-[:DIRECTED]->(CastAway)\\n\",\n        \"\\n\",\n        \"CREATE (OneFlewOvertheCuckoosNest:Movie {title:\\\"One Flew Over the Cuckoo's Nest\\\", released:1975, tagline:\\\"If he's crazy, what does that make you?\\\"})\\n\",\n        \"CREATE (MilosF:Person {name:'Milos Forman', born:1932})\\n\",\n        \"CREATE\\n\",\n        \"(JackN)-[:ACTED_IN {roles:['Randle McMurphy']}]->(OneFlewOvertheCuckoosNest),\\n\",\n        \"(DannyD)-[:ACTED_IN {roles:['Martini']}]->(OneFlewOvertheCuckoosNest),\\n\",\n        \"(MilosF)-[:DIRECTED]->(OneFlewOvertheCuckoosNest)\\n\",\n        \"\\n\",\n        \"CREATE (SomethingsGottaGive:Movie {title:\\\"Something's Gotta Give\\\", released:2003})\\n\",\n        \"CREATE (DianeK:Person {name:'Diane Keaton', born:1946})\\n\",\n        \"CREATE (NancyM:Person {name:'Nancy Meyers', born:1949})\\n\",\n        \"CREATE\\n\",\n        \"(JackN)-[:ACTED_IN {roles:['Harry Sanborn']}]->(SomethingsGottaGive),\\n\",\n        \"(DianeK)-[:ACTED_IN {roles:['Erica Barry']}]->(SomethingsGottaGive),\\n\",\n        \"(Keanu)-[:ACTED_IN {roles:['Julian Mercer']}]->(SomethingsGottaGive),\\n\",\n        \"(NancyM)-[:DIRECTED]->(SomethingsGottaGive),\\n\",\n        \"(NancyM)-[:PRODUCED]->(SomethingsGottaGive),\\n\",\n        \"(NancyM)-[:WROTE]->(SomethingsGottaGive)\\n\",\n        \"\\n\",\n        \"CREATE (BicentennialMan:Movie {title:'Bicentennial Man', released:1999, tagline:\\\"One robot's 200 year journey to become an ordinary man.\\\"})\\n\",\n        \"CREATE (ChrisC:Person {name:'Chris Columbus', born:1958})\\n\",\n        \"CREATE\\n\",\n        \"(Robin)-[:ACTED_IN {roles:['Andrew Marin']}]->(BicentennialMan),\\n\",\n        \"(OliverP)-[:ACTED_IN {roles:['Rupert Burns']}]->(BicentennialMan),\\n\",\n        \"(ChrisC)-[:DIRECTED]->(BicentennialMan)\\n\",\n        \"\\n\",\n        \"CREATE (CharlieWilsonsWar:Movie {title:\\\"Charlie Wilson's War\\\", released:2007, tagline:\\\"A stiff drink. A little mascara. A lot of nerve. Who said they couldn't bring down the Soviet empire.\\\"})\\n\",\n        \"CREATE (JuliaR:Person {name:'Julia Roberts', born:1967})\\n\",\n        \"CREATE\\n\",\n        \"(TomH)-[:ACTED_IN {roles:['Rep. Charlie Wilson']}]->(CharlieWilsonsWar),\\n\",\n        \"(JuliaR)-[:ACTED_IN {roles:['Joanne Herring']}]->(CharlieWilsonsWar),\\n\",\n        \"(PhilipH)-[:ACTED_IN {roles:['Gust Avrakotos']}]->(CharlieWilsonsWar),\\n\",\n        \"(MikeN)-[:DIRECTED]->(CharlieWilsonsWar)\\n\",\n        \"\\n\",\n        \"CREATE (ThePolarExpress:Movie {title:'The Polar Express', released:2004, tagline:'This Holiday Season... Believe'})\\n\",\n        \"CREATE\\n\",\n        \"(TomH)-[:ACTED_IN {roles:['Hero Boy', 'Father', 'Conductor', 'Hobo', 'Scrooge', 'Santa Claus']}]->(ThePolarExpress),\\n\",\n        \"(RobertZ)-[:DIRECTED]->(ThePolarExpress)\\n\",\n        \"\\n\",\n        \"CREATE (ALeagueofTheirOwn:Movie {title:'A League of Their Own', released:1992, tagline:'Once in a lifetime you get a chance to do something different.'})\\n\",\n        \"CREATE (Madonna:Person {name:'Madonna', born:1954})\\n\",\n        \"CREATE (GeenaD:Person {name:'Geena Davis', born:1956})\\n\",\n        \"CREATE (LoriP:Person {name:'Lori Petty', born:1963})\\n\",\n        \"CREATE (PennyM:Person {name:'Penny Marshall', born:1943})\\n\",\n        \"CREATE\\n\",\n        \"(TomH)-[:ACTED_IN {roles:['Jimmy Dugan']}]->(ALeagueofTheirOwn),\\n\",\n        \"(GeenaD)-[:ACTED_IN {roles:['Dottie Hinson']}]->(ALeagueofTheirOwn),\\n\",\n        \"(LoriP)-[:ACTED_IN {roles:['Kit Keller']}]->(ALeagueofTheirOwn),\\n\",\n        \"(RosieO)-[:ACTED_IN {roles:['Doris Murphy']}]->(ALeagueofTheirOwn),\\n\",\n        \"(Madonna)-[:ACTED_IN {roles:['\\\"All the Way\\\" Mae Mordabito']}]->(ALeagueofTheirOwn),\\n\",\n        \"(BillPax)-[:ACTED_IN {roles:['Bob Hinson']}]->(ALeagueofTheirOwn),\\n\",\n        \"(PennyM)-[:DIRECTED]->(ALeagueofTheirOwn)\\n\",\n        \"\\n\",\n        \"CREATE (PaulBlythe:Person {name:'Paul Blythe'})\\n\",\n        \"CREATE (AngelaScope:Person {name:'Angela Scope'})\\n\",\n        \"CREATE (JessicaThompson:Person {name:'Jessica Thompson'})\\n\",\n        \"CREATE (JamesThompson:Person {name:'James Thompson'})\\n\",\n        \"\\n\",\n        \"CREATE\\n\",\n        \"(JamesThompson)-[:FOLLOWS]->(JessicaThompson),\\n\",\n        \"(AngelaScope)-[:FOLLOWS]->(JessicaThompson),\\n\",\n        \"(PaulBlythe)-[:FOLLOWS]->(AngelaScope)\\n\",\n        \"\\n\",\n        \"CREATE\\n\",\n        \"(JessicaThompson)-[:REVIEWED {summary:'An amazing journey', rating:95}]->(CloudAtlas),\\n\",\n        \"(JessicaThompson)-[:REVIEWED {summary:'Silly, but fun', rating:65}]->(TheReplacements),\\n\",\n        \"(JamesThompson)-[:REVIEWED {summary:'The coolest football movie ever', rating:100}]->(TheReplacements),\\n\",\n        \"(AngelaScope)-[:REVIEWED {summary:'Pretty funny at times', rating:62}]->(TheReplacements),\\n\",\n        \"(JessicaThompson)-[:REVIEWED {summary:'Dark, but compelling', rating:85}]->(Unforgiven),\\n\",\n        \"(JessicaThompson)-[:REVIEWED {summary:\\\"Slapstick redeemed only by the Robin Williams and Gene Hackman's stellar performances\\\", rating:45}]->(TheBirdcage),\\n\",\n        \"(JessicaThompson)-[:REVIEWED {summary:'A solid romp', rating:68}]->(TheDaVinciCode),\\n\",\n        \"(JamesThompson)-[:REVIEWED {summary:'Fun, but a little far fetched', rating:65}]->(TheDaVinciCode),\\n\",\n        \"(JessicaThompson)-[:REVIEWED {summary:'You had me at Jerry', rating:92}]->(JerryMaguire)\\n\",\n        \"\\n\",\n        \"WITH TomH as a\\n\",\n        \"MATCH (a)-[:ACTED_IN]->(m)<-[:DIRECTED]-(d) RETURN a,m,d LIMIT 10;\\n\",\n        \"```\\n\",\n        \"\\n\",\n        \"</details>\\n\",\n        \"\\n\",\n        \"This will create the following graph model\\n\",\n        \"\\n\",\n        \"<img src=\\\"data:image/png;base64,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\\\" >\"\n      ],\n      \"metadata\": {\n        \"id\": \"AQhqv93Mj0Ss\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"%%cypher -u $neo4j_url -us $neo4j_user -pw $neo4j_password\\n\",\n        \"// the following Cypher query is the same as above\\n\",\n        \"// and is required for running the notebook\\n\",\n        \"CREATE (TheMatrix:Movie {title:'The Matrix', released:1999, tagline:'Welcome to the Real World'})\\n\",\n        \"CREATE (Keanu:Person {name:'Keanu Reeves', born:1964})\\n\",\n        \"CREATE (Carrie:Person {name:'Carrie-Anne Moss', born:1967})\\n\",\n        \"CREATE (Laurence:Person {name:'Laurence Fishburne', born:1961})\\n\",\n        \"CREATE (Hugo:Person {name:'Hugo Weaving', born:1960})\\n\",\n        \"CREATE (LillyW:Person {name:'Lilly Wachowski', born:1967})\\n\",\n        \"CREATE (LanaW:Person {name:'Lana Wachowski', born:1965})\\n\",\n        \"CREATE (JoelS:Person {name:'Joel Silver', born:1952})\\n\",\n        \"CREATE\\n\",\n        \"(Keanu)-[:ACTED_IN {roles:['Neo']}]->(TheMatrix),\\n\",\n        \"(Carrie)-[:ACTED_IN {roles:['Trinity']}]->(TheMatrix),\\n\",\n        \"(Laurence)-[:ACTED_IN {roles:['Morpheus']}]->(TheMatrix),\\n\",\n        \"(Hugo)-[:ACTED_IN {roles:['Agent Smith']}]->(TheMatrix),\\n\",\n        \"(LillyW)-[:DIRECTED]->(TheMatrix),\\n\",\n        \"(LanaW)-[:DIRECTED]->(TheMatrix),\\n\",\n        \"(JoelS)-[:PRODUCED]->(TheMatrix)\\n\",\n        \"\\n\",\n        \"CREATE (Emil:Person {name:\\\"Emil Eifrem\\\", born:1978})\\n\",\n        \"CREATE (Emil)-[:ACTED_IN {roles:[\\\"Emil\\\"]}]->(TheMatrix)\\n\",\n        \"\\n\",\n        \"CREATE (TheMatrixReloaded:Movie {title:'The Matrix Reloaded', released:2003, tagline:'Free your mind'})\\n\",\n        \"CREATE\\n\",\n        \"(Keanu)-[:ACTED_IN {roles:['Neo']}]->(TheMatrixReloaded),\\n\",\n        \"(Carrie)-[:ACTED_IN {roles:['Trinity']}]->(TheMatrixReloaded),\\n\",\n        \"(Laurence)-[:ACTED_IN {roles:['Morpheus']}]->(TheMatrixReloaded),\\n\",\n        \"(Hugo)-[:ACTED_IN {roles:['Agent Smith']}]->(TheMatrixReloaded),\\n\",\n        \"(LillyW)-[:DIRECTED]->(TheMatrixReloaded),\\n\",\n        \"(LanaW)-[:DIRECTED]->(TheMatrixReloaded),\\n\",\n        \"(JoelS)-[:PRODUCED]->(TheMatrixReloaded)\\n\",\n        \"\\n\",\n        \"CREATE (TheMatrixRevolutions:Movie {title:'The Matrix Revolutions', released:2003, tagline:'Everything that has a beginning has an end'})\\n\",\n        \"CREATE\\n\",\n        \"(Keanu)-[:ACTED_IN {roles:['Neo']}]->(TheMatrixRevolutions),\\n\",\n        \"(Carrie)-[:ACTED_IN {roles:['Trinity']}]->(TheMatrixRevolutions),\\n\",\n        \"(Laurence)-[:ACTED_IN {roles:['Morpheus']}]->(TheMatrixRevolutions),\\n\",\n        \"(Hugo)-[:ACTED_IN {roles:['Agent Smith']}]->(TheMatrixRevolutions),\\n\",\n        \"(LillyW)-[:DIRECTED]->(TheMatrixRevolutions),\\n\",\n        \"(LanaW)-[:DIRECTED]->(TheMatrixRevolutions),\\n\",\n        \"(JoelS)-[:PRODUCED]->(TheMatrixRevolutions)\\n\",\n        \"\\n\",\n        \"CREATE (TheDevilsAdvocate:Movie {title:\\\"The Devil's Advocate\\\", released:1997, tagline:'Evil has its winning ways'})\\n\",\n        \"CREATE (Charlize:Person {name:'Charlize Theron', born:1975})\\n\",\n        \"CREATE (Al:Person {name:'Al Pacino', born:1940})\\n\",\n        \"CREATE (Taylor:Person {name:'Taylor Hackford', born:1944})\\n\",\n        \"CREATE\\n\",\n        \"(Keanu)-[:ACTED_IN {roles:['Kevin Lomax']}]->(TheDevilsAdvocate),\\n\",\n        \"(Charlize)-[:ACTED_IN {roles:['Mary Ann Lomax']}]->(TheDevilsAdvocate),\\n\",\n        \"(Al)-[:ACTED_IN {roles:['John Milton']}]->(TheDevilsAdvocate),\\n\",\n        \"(Taylor)-[:DIRECTED]->(TheDevilsAdvocate)\\n\",\n        \"\\n\",\n        \"CREATE (AFewGoodMen:Movie {title:\\\"A Few Good Men\\\", released:1992, tagline:\\\"In the heart of the nation's capital, in a courthouse of the U.S. government, one man will stop at nothing to keep his honor, and one will stop at nothing to find the truth.\\\"})\\n\",\n        \"CREATE (TomC:Person {name:'Tom Cruise', born:1962})\\n\",\n        \"CREATE (JackN:Person {name:'Jack Nicholson', born:1937})\\n\",\n        \"CREATE (DemiM:Person {name:'Demi Moore', born:1962})\\n\",\n        \"CREATE (KevinB:Person {name:'Kevin Bacon', born:1958})\\n\",\n        \"CREATE (KieferS:Person {name:'Kiefer Sutherland', born:1966})\\n\",\n        \"CREATE (NoahW:Person {name:'Noah Wyle', born:1971})\\n\",\n        \"CREATE (CubaG:Person {name:'Cuba Gooding Jr.', born:1968})\\n\",\n        \"CREATE (KevinP:Person {name:'Kevin Pollak', born:1957})\\n\",\n        \"CREATE (JTW:Person {name:'J.T. Walsh', born:1943})\\n\",\n        \"CREATE (JamesM:Person {name:'James Marshall', born:1967})\\n\",\n        \"CREATE (ChristopherG:Person {name:'Christopher Guest', born:1948})\\n\",\n        \"CREATE (RobR:Person {name:'Rob Reiner', born:1947})\\n\",\n        \"CREATE (AaronS:Person {name:'Aaron Sorkin', born:1961})\\n\",\n        \"CREATE\\n\",\n        \"(TomC)-[:ACTED_IN {roles:['Lt. Daniel Kaffee']}]->(AFewGoodMen),\\n\",\n        \"(JackN)-[:ACTED_IN {roles:['Col. Nathan R. Jessup']}]->(AFewGoodMen),\\n\",\n        \"(DemiM)-[:ACTED_IN {roles:['Lt. Cdr. JoAnne Galloway']}]->(AFewGoodMen),\\n\",\n        \"(KevinB)-[:ACTED_IN {roles:['Capt. Jack Ross']}]->(AFewGoodMen),\\n\",\n        \"(KieferS)-[:ACTED_IN {roles:['Lt. Jonathan Kendrick']}]->(AFewGoodMen),\\n\",\n        \"(NoahW)-[:ACTED_IN {roles:['Cpl. Jeffrey Barnes']}]->(AFewGoodMen),\\n\",\n        \"(CubaG)-[:ACTED_IN {roles:['Cpl. Carl Hammaker']}]->(AFewGoodMen),\\n\",\n        \"(KevinP)-[:ACTED_IN {roles:['Lt. Sam Weinberg']}]->(AFewGoodMen),\\n\",\n        \"(JTW)-[:ACTED_IN {roles:['Lt. Col. Matthew Andrew Markinson']}]->(AFewGoodMen),\\n\",\n        \"(JamesM)-[:ACTED_IN {roles:['Pfc. Louden Downey']}]->(AFewGoodMen),\\n\",\n        \"(ChristopherG)-[:ACTED_IN {roles:['Dr. Stone']}]->(AFewGoodMen),\\n\",\n        \"(AaronS)-[:ACTED_IN {roles:['Man in Bar']}]->(AFewGoodMen),\\n\",\n        \"(RobR)-[:DIRECTED]->(AFewGoodMen),\\n\",\n        \"(AaronS)-[:WROTE]->(AFewGoodMen)\\n\",\n        \"\\n\",\n        \"CREATE (TopGun:Movie {title:\\\"Top Gun\\\", released:1986, tagline:'I feel the need, the need for speed.'})\\n\",\n        \"CREATE (KellyM:Person {name:'Kelly McGillis', born:1957})\\n\",\n        \"CREATE (ValK:Person {name:'Val Kilmer', born:1959})\\n\",\n        \"CREATE (AnthonyE:Person {name:'Anthony Edwards', born:1962})\\n\",\n        \"CREATE (TomS:Person {name:'Tom Skerritt', born:1933})\\n\",\n        \"CREATE (MegR:Person {name:'Meg Ryan', born:1961})\\n\",\n        \"CREATE (TonyS:Person {name:'Tony Scott', born:1944})\\n\",\n        \"CREATE (JimC:Person {name:'Jim Cash', born:1941})\\n\",\n        \"CREATE\\n\",\n        \"(TomC)-[:ACTED_IN {roles:['Maverick']}]->(TopGun),\\n\",\n        \"(KellyM)-[:ACTED_IN {roles:['Charlie']}]->(TopGun),\\n\",\n        \"(ValK)-[:ACTED_IN {roles:['Iceman']}]->(TopGun),\\n\",\n        \"(AnthonyE)-[:ACTED_IN {roles:['Goose']}]->(TopGun),\\n\",\n        \"(TomS)-[:ACTED_IN {roles:['Viper']}]->(TopGun),\\n\",\n        \"(MegR)-[:ACTED_IN {roles:['Carole']}]->(TopGun),\\n\",\n        \"(TonyS)-[:DIRECTED]->(TopGun),\\n\",\n        \"(JimC)-[:WROTE]->(TopGun)\\n\",\n        \"\\n\",\n        \"CREATE (JerryMaguire:Movie {title:'Jerry Maguire', released:2000, tagline:'The rest of his life begins now.'})\\n\",\n        \"CREATE (ReneeZ:Person {name:'Renee Zellweger', born:1969})\\n\",\n        \"CREATE (KellyP:Person {name:'Kelly Preston', born:1962})\\n\",\n        \"CREATE (JerryO:Person {name:\\\"Jerry O'Connell\\\", born:1974})\\n\",\n        \"CREATE (JayM:Person {name:'Jay Mohr', born:1970})\\n\",\n        \"CREATE (BonnieH:Person {name:'Bonnie Hunt', born:1961})\\n\",\n        \"CREATE (ReginaK:Person {name:'Regina King', born:1971})\\n\",\n        \"CREATE (JonathanL:Person {name:'Jonathan Lipnicki', born:1996})\\n\",\n        \"CREATE (CameronC:Person {name:'Cameron Crowe', born:1957})\\n\",\n        \"CREATE\\n\",\n        \"(TomC)-[:ACTED_IN {roles:['Jerry Maguire']}]->(JerryMaguire),\\n\",\n        \"(CubaG)-[:ACTED_IN {roles:['Rod Tidwell']}]->(JerryMaguire),\\n\",\n        \"(ReneeZ)-[:ACTED_IN {roles:['Dorothy Boyd']}]->(JerryMaguire),\\n\",\n        \"(KellyP)-[:ACTED_IN {roles:['Avery Bishop']}]->(JerryMaguire),\\n\",\n        \"(JerryO)-[:ACTED_IN {roles:['Frank Cushman']}]->(JerryMaguire),\\n\",\n        \"(JayM)-[:ACTED_IN {roles:['Bob Sugar']}]->(JerryMaguire),\\n\",\n        \"(BonnieH)-[:ACTED_IN {roles:['Laurel Boyd']}]->(JerryMaguire),\\n\",\n        \"(ReginaK)-[:ACTED_IN {roles:['Marcee Tidwell']}]->(JerryMaguire),\\n\",\n        \"(JonathanL)-[:ACTED_IN {roles:['Ray Boyd']}]->(JerryMaguire),\\n\",\n        \"(CameronC)-[:DIRECTED]->(JerryMaguire),\\n\",\n        \"(CameronC)-[:PRODUCED]->(JerryMaguire),\\n\",\n        \"(CameronC)-[:WROTE]->(JerryMaguire)\\n\",\n        \"\\n\",\n        \"CREATE (StandByMe:Movie {title:\\\"Stand By Me\\\", released:1986, tagline:\\\"For some, it's the last real taste of innocence, and the first real taste of life. But for everyone, it's the time that memories are made of.\\\"})\\n\",\n        \"CREATE (RiverP:Person {name:'River Phoenix', born:1970})\\n\",\n        \"CREATE (CoreyF:Person {name:'Corey Feldman', born:1971})\\n\",\n        \"CREATE (WilW:Person {name:'Wil Wheaton', born:1972})\\n\",\n        \"CREATE (JohnC:Person {name:'John Cusack', born:1966})\\n\",\n        \"CREATE (MarshallB:Person {name:'Marshall Bell', born:1942})\\n\",\n        \"CREATE\\n\",\n        \"(WilW)-[:ACTED_IN {roles:['Gordie Lachance']}]->(StandByMe),\\n\",\n        \"(RiverP)-[:ACTED_IN {roles:['Chris Chambers']}]->(StandByMe),\\n\",\n        \"(JerryO)-[:ACTED_IN {roles:['Vern Tessio']}]->(StandByMe),\\n\",\n        \"(CoreyF)-[:ACTED_IN {roles:['Teddy Duchamp']}]->(StandByMe),\\n\",\n        \"(JohnC)-[:ACTED_IN {roles:['Denny Lachance']}]->(StandByMe),\\n\",\n        \"(KieferS)-[:ACTED_IN {roles:['Ace Merrill']}]->(StandByMe),\\n\",\n        \"(MarshallB)-[:ACTED_IN {roles:['Mr. Lachance']}]->(StandByMe),\\n\",\n        \"(RobR)-[:DIRECTED]->(StandByMe)\\n\",\n        \"\\n\",\n        \"CREATE (AsGoodAsItGets:Movie {title:'As Good as It Gets', released:1997, tagline:'A comedy from the heart that goes for the throat.'})\\n\",\n        \"CREATE (HelenH:Person {name:'Helen Hunt', born:1963})\\n\",\n        \"CREATE (GregK:Person {name:'Greg Kinnear', born:1963})\\n\",\n        \"CREATE (JamesB:Person {name:'James L. Brooks', born:1940})\\n\",\n        \"CREATE\\n\",\n        \"(JackN)-[:ACTED_IN {roles:['Melvin Udall']}]->(AsGoodAsItGets),\\n\",\n        \"(HelenH)-[:ACTED_IN {roles:['Carol Connelly']}]->(AsGoodAsItGets),\\n\",\n        \"(GregK)-[:ACTED_IN {roles:['Simon Bishop']}]->(AsGoodAsItGets),\\n\",\n        \"(CubaG)-[:ACTED_IN {roles:['Frank Sachs']}]->(AsGoodAsItGets),\\n\",\n        \"(JamesB)-[:DIRECTED]->(AsGoodAsItGets)\\n\",\n        \"\\n\",\n        \"CREATE (WhatDreamsMayCome:Movie {title:'What Dreams May Come', released:1998, tagline:'After life there is more. The end is just the beginning.'})\\n\",\n        \"CREATE (AnnabellaS:Person {name:'Annabella Sciorra', born:1960})\\n\",\n        \"CREATE (MaxS:Person {name:'Max von Sydow', born:1929})\\n\",\n        \"CREATE (WernerH:Person {name:'Werner Herzog', born:1942})\\n\",\n        \"CREATE (Robin:Person {name:'Robin Williams', born:1951})\\n\",\n        \"CREATE (VincentW:Person {name:'Vincent Ward', born:1956})\\n\",\n        \"CREATE\\n\",\n        \"(Robin)-[:ACTED_IN {roles:['Chris Nielsen']}]->(WhatDreamsMayCome),\\n\",\n        \"(CubaG)-[:ACTED_IN {roles:['Albert Lewis']}]->(WhatDreamsMayCome),\\n\",\n        \"(AnnabellaS)-[:ACTED_IN {roles:['Annie Collins-Nielsen']}]->(WhatDreamsMayCome),\\n\",\n        \"(MaxS)-[:ACTED_IN {roles:['The Tracker']}]->(WhatDreamsMayCome),\\n\",\n        \"(WernerH)-[:ACTED_IN {roles:['The Face']}]->(WhatDreamsMayCome),\\n\",\n        \"(VincentW)-[:DIRECTED]->(WhatDreamsMayCome)\\n\",\n        \"\\n\",\n        \"CREATE (SnowFallingonCedars:Movie {title:'Snow Falling on Cedars', released:1999, tagline:'First loves last. Forever.'})\\n\",\n        \"CREATE (EthanH:Person {name:'Ethan Hawke', born:1970})\\n\",\n        \"CREATE (RickY:Person {name:'Rick Yune', born:1971})\\n\",\n        \"CREATE (JamesC:Person {name:'James Cromwell', born:1940})\\n\",\n        \"CREATE (ScottH:Person {name:'Scott Hicks', born:1953})\\n\",\n        \"CREATE\\n\",\n        \"(EthanH)-[:ACTED_IN {roles:['Ishmael Chambers']}]->(SnowFallingonCedars),\\n\",\n        \"(RickY)-[:ACTED_IN {roles:['Kazuo Miyamoto']}]->(SnowFallingonCedars),\\n\",\n        \"(MaxS)-[:ACTED_IN {roles:['Nels Gudmundsson']}]->(SnowFallingonCedars),\\n\",\n        \"(JamesC)-[:ACTED_IN {roles:['Judge Fielding']}]->(SnowFallingonCedars),\\n\",\n        \"(ScottH)-[:DIRECTED]->(SnowFallingonCedars)\\n\",\n        \"\\n\",\n        \"CREATE (YouveGotMail:Movie {title:\\\"You've Got Mail\\\", released:1998, tagline:'At odds in life... in love on-line.'})\\n\",\n        \"CREATE (ParkerP:Person {name:'Parker Posey', born:1968})\\n\",\n        \"CREATE (DaveC:Person {name:'Dave Chappelle', born:1973})\\n\",\n        \"CREATE (SteveZ:Person {name:'Steve Zahn', born:1967})\\n\",\n        \"CREATE (TomH:Person {name:'Tom Hanks', born:1956})\\n\",\n        \"CREATE (NoraE:Person {name:'Nora Ephron', born:1941})\\n\",\n        \"CREATE\\n\",\n        \"(TomH)-[:ACTED_IN {roles:['Joe Fox']}]->(YouveGotMail),\\n\",\n        \"(MegR)-[:ACTED_IN {roles:['Kathleen Kelly']}]->(YouveGotMail),\\n\",\n        \"(GregK)-[:ACTED_IN {roles:['Frank Navasky']}]->(YouveGotMail),\\n\",\n        \"(ParkerP)-[:ACTED_IN {roles:['Patricia Eden']}]->(YouveGotMail),\\n\",\n        \"(DaveC)-[:ACTED_IN {roles:['Kevin Jackson']}]->(YouveGotMail),\\n\",\n        \"(SteveZ)-[:ACTED_IN {roles:['George Pappas']}]->(YouveGotMail),\\n\",\n        \"(NoraE)-[:DIRECTED]->(YouveGotMail)\\n\",\n        \"\\n\",\n        \"CREATE (SleeplessInSeattle:Movie {title:'Sleepless in Seattle', released:1993, tagline:'What if someone you never met, someone you never saw, someone you never knew was the only someone for you?'})\\n\",\n        \"CREATE (RitaW:Person {name:'Rita Wilson', born:1956})\\n\",\n        \"CREATE (BillPull:Person {name:'Bill Pullman', born:1953})\\n\",\n        \"CREATE (VictorG:Person {name:'Victor Garber', born:1949})\\n\",\n        \"CREATE (RosieO:Person {name:\\\"Rosie O'Donnell\\\", born:1962})\\n\",\n        \"CREATE\\n\",\n        \"(TomH)-[:ACTED_IN {roles:['Sam Baldwin']}]->(SleeplessInSeattle),\\n\",\n        \"(MegR)-[:ACTED_IN {roles:['Annie Reed']}]->(SleeplessInSeattle),\\n\",\n        \"(RitaW)-[:ACTED_IN {roles:['Suzy']}]->(SleeplessInSeattle),\\n\",\n        \"(BillPull)-[:ACTED_IN {roles:['Walter']}]->(SleeplessInSeattle),\\n\",\n        \"(VictorG)-[:ACTED_IN {roles:['Greg']}]->(SleeplessInSeattle),\\n\",\n        \"(RosieO)-[:ACTED_IN {roles:['Becky']}]->(SleeplessInSeattle),\\n\",\n        \"(NoraE)-[:DIRECTED]->(SleeplessInSeattle)\\n\",\n        \"\\n\",\n        \"CREATE (JoeVersustheVolcano:Movie {title:'Joe Versus the Volcano', released:1990, tagline:'A story of love, lava and burning desire.'})\\n\",\n        \"CREATE (JohnS:Person {name:'John Patrick Stanley', born:1950})\\n\",\n        \"CREATE (Nathan:Person {name:'Nathan Lane', born:1956})\\n\",\n        \"CREATE\\n\",\n        \"(TomH)-[:ACTED_IN {roles:['Joe Banks']}]->(JoeVersustheVolcano),\\n\",\n        \"(MegR)-[:ACTED_IN {roles:['DeDe', 'Angelica Graynamore', 'Patricia Graynamore']}]->(JoeVersustheVolcano),\\n\",\n        \"(Nathan)-[:ACTED_IN {roles:['Baw']}]->(JoeVersustheVolcano),\\n\",\n        \"(JohnS)-[:DIRECTED]->(JoeVersustheVolcano)\\n\",\n        \"\\n\",\n        \"CREATE (WhenHarryMetSally:Movie {title:'When Harry Met Sally', released:1998, tagline:'Can two friends sleep together and still love each other in the morning?'})\\n\",\n        \"CREATE (BillyC:Person {name:'Billy Crystal', born:1948})\\n\",\n        \"CREATE (CarrieF:Person {name:'Carrie Fisher', born:1956})\\n\",\n        \"CREATE (BrunoK:Person {name:'Bruno Kirby', born:1949})\\n\",\n        \"CREATE\\n\",\n        \"(BillyC)-[:ACTED_IN {roles:['Harry Burns']}]->(WhenHarryMetSally),\\n\",\n        \"(MegR)-[:ACTED_IN {roles:['Sally Albright']}]->(WhenHarryMetSally),\\n\",\n        \"(CarrieF)-[:ACTED_IN {roles:['Marie']}]->(WhenHarryMetSally),\\n\",\n        \"(BrunoK)-[:ACTED_IN {roles:['Jess']}]->(WhenHarryMetSally),\\n\",\n        \"(RobR)-[:DIRECTED]->(WhenHarryMetSally),\\n\",\n        \"(RobR)-[:PRODUCED]->(WhenHarryMetSally),\\n\",\n        \"(NoraE)-[:PRODUCED]->(WhenHarryMetSally),\\n\",\n        \"(NoraE)-[:WROTE]->(WhenHarryMetSally)\\n\",\n        \"\\n\",\n        \"CREATE (ThatThingYouDo:Movie {title:'That Thing You Do', released:1996, tagline:'In every life there comes a time when that thing you dream becomes that thing you do'})\\n\",\n        \"CREATE (LivT:Person {name:'Liv Tyler', born:1977})\\n\",\n        \"CREATE\\n\",\n        \"(TomH)-[:ACTED_IN {roles:['Mr. White']}]->(ThatThingYouDo),\\n\",\n        \"(LivT)-[:ACTED_IN {roles:['Faye Dolan']}]->(ThatThingYouDo),\\n\",\n        \"(Charlize)-[:ACTED_IN {roles:['Tina']}]->(ThatThingYouDo),\\n\",\n        \"(TomH)-[:DIRECTED]->(ThatThingYouDo)\\n\",\n        \"\\n\",\n        \"CREATE (TheReplacements:Movie {title:'The Replacements', released:2000, tagline:'Pain heals, Chicks dig scars... Glory lasts forever'})\\n\",\n        \"CREATE (Brooke:Person {name:'Brooke Langton', born:1970})\\n\",\n        \"CREATE (Gene:Person {name:'Gene Hackman', born:1930})\\n\",\n        \"CREATE (Orlando:Person {name:'Orlando Jones', born:1968})\\n\",\n        \"CREATE (Howard:Person {name:'Howard Deutch', born:1950})\\n\",\n        \"CREATE\\n\",\n        \"(Keanu)-[:ACTED_IN {roles:['Shane Falco']}]->(TheReplacements),\\n\",\n        \"(Brooke)-[:ACTED_IN {roles:['Annabelle Farrell']}]->(TheReplacements),\\n\",\n        \"(Gene)-[:ACTED_IN {roles:['Jimmy McGinty']}]->(TheReplacements),\\n\",\n        \"(Orlando)-[:ACTED_IN {roles:['Clifford Franklin']}]->(TheReplacements),\\n\",\n        \"(Howard)-[:DIRECTED]->(TheReplacements)\\n\",\n        \"\\n\",\n        \"CREATE (RescueDawn:Movie {title:'RescueDawn', released:2006, tagline:\\\"Based on the extraordinary true story of one man's fight for freedom\\\"})\\n\",\n        \"CREATE (ChristianB:Person {name:'Christian Bale', born:1974})\\n\",\n        \"CREATE (ZachG:Person {name:'Zach Grenier', born:1954})\\n\",\n        \"CREATE\\n\",\n        \"(MarshallB)-[:ACTED_IN {roles:['Admiral']}]->(RescueDawn),\\n\",\n        \"(ChristianB)-[:ACTED_IN {roles:['Dieter Dengler']}]->(RescueDawn),\\n\",\n        \"(ZachG)-[:ACTED_IN {roles:['Squad Leader']}]->(RescueDawn),\\n\",\n        \"(SteveZ)-[:ACTED_IN {roles:['Duane']}]->(RescueDawn),\\n\",\n        \"(WernerH)-[:DIRECTED]->(RescueDawn)\\n\",\n        \"\\n\",\n        \"CREATE (TheBirdcage:Movie {title:'The Birdcage', released:1996, tagline:'Come as you are'})\\n\",\n        \"CREATE (MikeN:Person {name:'Mike Nichols', born:1931})\\n\",\n        \"CREATE\\n\",\n        \"(Robin)-[:ACTED_IN {roles:['Armand Goldman']}]->(TheBirdcage),\\n\",\n        \"(Nathan)-[:ACTED_IN {roles:['Albert Goldman']}]->(TheBirdcage),\\n\",\n        \"(Gene)-[:ACTED_IN {roles:['Sen. Kevin Keeley']}]->(TheBirdcage),\\n\",\n        \"(MikeN)-[:DIRECTED]->(TheBirdcage)\\n\",\n        \"\\n\",\n        \"CREATE (Unforgiven:Movie {title:'Unforgiven', released:1992, tagline:\\\"It's a hell of a thing, killing a man\\\"})\\n\",\n        \"CREATE (RichardH:Person {name:'Richard Harris', born:1930})\\n\",\n        \"CREATE (ClintE:Person {name:'Clint Eastwood', born:1930})\\n\",\n        \"CREATE\\n\",\n        \"(RichardH)-[:ACTED_IN {roles:['English Bob']}]->(Unforgiven),\\n\",\n        \"(ClintE)-[:ACTED_IN {roles:['Bill Munny']}]->(Unforgiven),\\n\",\n        \"(Gene)-[:ACTED_IN {roles:['Little Bill Daggett']}]->(Unforgiven),\\n\",\n        \"(ClintE)-[:DIRECTED]->(Unforgiven)\\n\",\n        \"\\n\",\n        \"CREATE (JohnnyMnemonic:Movie {title:'Johnny Mnemonic', released:1995, tagline:'The hottest data on earth. In the coolest head in town'})\\n\",\n        \"CREATE (Takeshi:Person {name:'Takeshi Kitano', born:1947})\\n\",\n        \"CREATE (Dina:Person {name:'Dina Meyer', born:1968})\\n\",\n        \"CREATE (IceT:Person {name:'Ice-T', born:1958})\\n\",\n        \"CREATE (RobertL:Person {name:'Robert Longo', born:1953})\\n\",\n        \"CREATE\\n\",\n        \"(Keanu)-[:ACTED_IN {roles:['Johnny Mnemonic']}]->(JohnnyMnemonic),\\n\",\n        \"(Takeshi)-[:ACTED_IN {roles:['Takahashi']}]->(JohnnyMnemonic),\\n\",\n        \"(Dina)-[:ACTED_IN {roles:['Jane']}]->(JohnnyMnemonic),\\n\",\n        \"(IceT)-[:ACTED_IN {roles:['J-Bone']}]->(JohnnyMnemonic),\\n\",\n        \"(RobertL)-[:DIRECTED]->(JohnnyMnemonic)\\n\",\n        \"\\n\",\n        \"CREATE (CloudAtlas:Movie {title:'Cloud Atlas', released:2012, tagline:'Everything is connected'})\\n\",\n        \"CREATE (HalleB:Person {name:'Halle Berry', born:1966})\\n\",\n        \"CREATE (JimB:Person {name:'Jim Broadbent', born:1949})\\n\",\n        \"CREATE (TomT:Person {name:'Tom Tykwer', born:1965})\\n\",\n        \"CREATE (DavidMitchell:Person {name:'David Mitchell', born:1969})\\n\",\n        \"CREATE (StefanArndt:Person {name:'Stefan Arndt', born:1961})\\n\",\n        \"CREATE\\n\",\n        \"(TomH)-[:ACTED_IN {roles:['Zachry', 'Dr. Henry Goose', 'Isaac Sachs', 'Dermot Hoggins']}]->(CloudAtlas),\\n\",\n        \"(Hugo)-[:ACTED_IN {roles:['Bill Smoke', 'Haskell Moore', 'Tadeusz Kesselring', 'Nurse Noakes', 'Boardman Mephi', 'Old Georgie']}]->(CloudAtlas),\\n\",\n        \"(HalleB)-[:ACTED_IN {roles:['Luisa Rey', 'Jocasta Ayrs', 'Ovid', 'Meronym']}]->(CloudAtlas),\\n\",\n        \"(JimB)-[:ACTED_IN {roles:['Vyvyan Ayrs', 'Captain Molyneux', 'Timothy Cavendish']}]->(CloudAtlas),\\n\",\n        \"(TomT)-[:DIRECTED]->(CloudAtlas),\\n\",\n        \"(LillyW)-[:DIRECTED]->(CloudAtlas),\\n\",\n        \"(LanaW)-[:DIRECTED]->(CloudAtlas),\\n\",\n        \"(DavidMitchell)-[:WROTE]->(CloudAtlas),\\n\",\n        \"(StefanArndt)-[:PRODUCED]->(CloudAtlas)\\n\",\n        \"\\n\",\n        \"CREATE (TheDaVinciCode:Movie {title:'The Da Vinci Code', released:2006, tagline:'Break The Codes'})\\n\",\n        \"CREATE (IanM:Person {name:'Ian McKellen', born:1939})\\n\",\n        \"CREATE (AudreyT:Person {name:'Audrey Tautou', born:1976})\\n\",\n        \"CREATE (PaulB:Person {name:'Paul Bettany', born:1971})\\n\",\n        \"CREATE (RonH:Person {name:'Ron Howard', born:1954})\\n\",\n        \"CREATE\\n\",\n        \"(TomH)-[:ACTED_IN {roles:['Dr. Robert Langdon']}]->(TheDaVinciCode),\\n\",\n        \"(IanM)-[:ACTED_IN {roles:['Sir Leight Teabing']}]->(TheDaVinciCode),\\n\",\n        \"(AudreyT)-[:ACTED_IN {roles:['Sophie Neveu']}]->(TheDaVinciCode),\\n\",\n        \"(PaulB)-[:ACTED_IN {roles:['Silas']}]->(TheDaVinciCode),\\n\",\n        \"(RonH)-[:DIRECTED]->(TheDaVinciCode)\\n\",\n        \"\\n\",\n        \"CREATE (VforVendetta:Movie {title:'V for Vendetta', released:2006, tagline:'Freedom! Forever!'})\\n\",\n        \"CREATE (NatalieP:Person {name:'Natalie Portman', born:1981})\\n\",\n        \"CREATE (StephenR:Person {name:'Stephen Rea', born:1946})\\n\",\n        \"CREATE (JohnH:Person {name:'John Hurt', born:1940})\\n\",\n        \"CREATE (BenM:Person {name: 'Ben Miles', born:1967})\\n\",\n        \"CREATE\\n\",\n        \"(Hugo)-[:ACTED_IN {roles:['V']}]->(VforVendetta),\\n\",\n        \"(NatalieP)-[:ACTED_IN {roles:['Evey Hammond']}]->(VforVendetta),\\n\",\n        \"(StephenR)-[:ACTED_IN {roles:['Eric Finch']}]->(VforVendetta),\\n\",\n        \"(JohnH)-[:ACTED_IN {roles:['High Chancellor Adam Sutler']}]->(VforVendetta),\\n\",\n        \"(BenM)-[:ACTED_IN {roles:['Dascomb']}]->(VforVendetta),\\n\",\n        \"(JamesM)-[:DIRECTED]->(VforVendetta),\\n\",\n        \"(LillyW)-[:PRODUCED]->(VforVendetta),\\n\",\n        \"(LanaW)-[:PRODUCED]->(VforVendetta),\\n\",\n        \"(JoelS)-[:PRODUCED]->(VforVendetta),\\n\",\n        \"(LillyW)-[:WROTE]->(VforVendetta),\\n\",\n        \"(LanaW)-[:WROTE]->(VforVendetta)\\n\",\n        \"\\n\",\n        \"CREATE (SpeedRacer:Movie {title:'Speed Racer', released:2008, tagline:'Speed has no limits'})\\n\",\n        \"CREATE (EmileH:Person {name:'Emile Hirsch', born:1985})\\n\",\n        \"CREATE (JohnG:Person {name:'John Goodman', born:1960})\\n\",\n        \"CREATE (SusanS:Person {name:'Susan Sarandon', born:1946})\\n\",\n        \"CREATE (MatthewF:Person {name:'Matthew Fox', born:1966})\\n\",\n        \"CREATE (ChristinaR:Person {name:'Christina Ricci', born:1980})\\n\",\n        \"CREATE (Rain:Person {name:'Rain', born:1982})\\n\",\n        \"CREATE\\n\",\n        \"(EmileH)-[:ACTED_IN {roles:['Speed Racer']}]->(SpeedRacer),\\n\",\n        \"(JohnG)-[:ACTED_IN {roles:['Pops']}]->(SpeedRacer),\\n\",\n        \"(SusanS)-[:ACTED_IN {roles:['Mom']}]->(SpeedRacer),\\n\",\n        \"(MatthewF)-[:ACTED_IN {roles:['Racer X']}]->(SpeedRacer),\\n\",\n        \"(ChristinaR)-[:ACTED_IN {roles:['Trixie']}]->(SpeedRacer),\\n\",\n        \"(Rain)-[:ACTED_IN {roles:['Taejo Togokahn']}]->(SpeedRacer),\\n\",\n        \"(BenM)-[:ACTED_IN {roles:['Cass Jones']}]->(SpeedRacer),\\n\",\n        \"(LillyW)-[:DIRECTED]->(SpeedRacer),\\n\",\n        \"(LanaW)-[:DIRECTED]->(SpeedRacer),\\n\",\n        \"(LillyW)-[:WROTE]->(SpeedRacer),\\n\",\n        \"(LanaW)-[:WROTE]->(SpeedRacer),\\n\",\n        \"(JoelS)-[:PRODUCED]->(SpeedRacer)\\n\",\n        \"\\n\",\n        \"CREATE (NinjaAssassin:Movie {title:'Ninja Assassin', released:2009, tagline:'Prepare to enter a secret world of assassins'})\\n\",\n        \"CREATE (NaomieH:Person {name:'Naomie Harris'})\\n\",\n        \"CREATE\\n\",\n        \"(Rain)-[:ACTED_IN {roles:['Raizo']}]->(NinjaAssassin),\\n\",\n        \"(NaomieH)-[:ACTED_IN {roles:['Mika Coretti']}]->(NinjaAssassin),\\n\",\n        \"(RickY)-[:ACTED_IN {roles:['Takeshi']}]->(NinjaAssassin),\\n\",\n        \"(BenM)-[:ACTED_IN {roles:['Ryan Maslow']}]->(NinjaAssassin),\\n\",\n        \"(JamesM)-[:DIRECTED]->(NinjaAssassin),\\n\",\n        \"(LillyW)-[:PRODUCED]->(NinjaAssassin),\\n\",\n        \"(LanaW)-[:PRODUCED]->(NinjaAssassin),\\n\",\n        \"(JoelS)-[:PRODUCED]->(NinjaAssassin)\\n\",\n        \"\\n\",\n        \"CREATE (TheGreenMile:Movie {title:'The Green Mile', released:1999, tagline:\\\"Walk a mile you'll never forget.\\\"})\\n\",\n        \"CREATE (MichaelD:Person {name:'Michael Clarke Duncan', born:1957})\\n\",\n        \"CREATE (DavidM:Person {name:'David Morse', born:1953})\\n\",\n        \"CREATE (SamR:Person {name:'Sam Rockwell', born:1968})\\n\",\n        \"CREATE (GaryS:Person {name:'Gary Sinise', born:1955})\\n\",\n        \"CREATE (PatriciaC:Person {name:'Patricia Clarkson', born:1959})\\n\",\n        \"CREATE (FrankD:Person {name:'Frank Darabont', born:1959})\\n\",\n        \"CREATE\\n\",\n        \"(TomH)-[:ACTED_IN {roles:['Paul Edgecomb']}]->(TheGreenMile),\\n\",\n        \"(MichaelD)-[:ACTED_IN {roles:['John Coffey']}]->(TheGreenMile),\\n\",\n        \"(DavidM)-[:ACTED_IN {roles:['Brutus \\\"Brutal\\\" Howell']}]->(TheGreenMile),\\n\",\n        \"(BonnieH)-[:ACTED_IN {roles:['Jan Edgecomb']}]->(TheGreenMile),\\n\",\n        \"(JamesC)-[:ACTED_IN {roles:['Warden Hal Moores']}]->(TheGreenMile),\\n\",\n        \"(SamR)-[:ACTED_IN {roles:['\\\"Wild Bill\\\" Wharton']}]->(TheGreenMile),\\n\",\n        \"(GaryS)-[:ACTED_IN {roles:['Burt Hammersmith']}]->(TheGreenMile),\\n\",\n        \"(PatriciaC)-[:ACTED_IN {roles:['Melinda Moores']}]->(TheGreenMile),\\n\",\n        \"(FrankD)-[:DIRECTED]->(TheGreenMile)\\n\",\n        \"\\n\",\n        \"CREATE (FrostNixon:Movie {title:'Frost/Nixon', released:2008, tagline:'400 million people were waiting for the truth.'})\\n\",\n        \"CREATE (FrankL:Person {name:'Frank Langella', born:1938})\\n\",\n        \"CREATE (MichaelS:Person {name:'Michael Sheen', born:1969})\\n\",\n        \"CREATE (OliverP:Person {name:'Oliver Platt', born:1960})\\n\",\n        \"CREATE\\n\",\n        \"(FrankL)-[:ACTED_IN {roles:['Richard Nixon']}]->(FrostNixon),\\n\",\n        \"(MichaelS)-[:ACTED_IN {roles:['David Frost']}]->(FrostNixon),\\n\",\n        \"(KevinB)-[:ACTED_IN {roles:['Jack Brennan']}]->(FrostNixon),\\n\",\n        \"(OliverP)-[:ACTED_IN {roles:['Bob Zelnick']}]->(FrostNixon),\\n\",\n        \"(SamR)-[:ACTED_IN {roles:['James Reston, Jr.']}]->(FrostNixon),\\n\",\n        \"(RonH)-[:DIRECTED]->(FrostNixon)\\n\",\n        \"\\n\",\n        \"CREATE (Hoffa:Movie {title:'Hoffa', released:1992, tagline:\\\"He didn't want law. He wanted justice.\\\"})\\n\",\n        \"CREATE (DannyD:Person {name:'Danny DeVito', born:1944})\\n\",\n        \"CREATE (JohnR:Person {name:'John C. Reilly', born:1965})\\n\",\n        \"CREATE\\n\",\n        \"(JackN)-[:ACTED_IN {roles:['Hoffa']}]->(Hoffa),\\n\",\n        \"(DannyD)-[:ACTED_IN {roles:['Robert \\\"Bobby\\\" Ciaro']}]->(Hoffa),\\n\",\n        \"(JTW)-[:ACTED_IN {roles:['Frank Fitzsimmons']}]->(Hoffa),\\n\",\n        \"(JohnR)-[:ACTED_IN {roles:['Peter \\\"Pete\\\" Connelly']}]->(Hoffa),\\n\",\n        \"(DannyD)-[:DIRECTED]->(Hoffa)\\n\",\n        \"\\n\",\n        \"CREATE (Apollo13:Movie {title:'Apollo 13', released:1995, tagline:'Houston, we have a problem.'})\\n\",\n        \"CREATE (EdH:Person {name:'Ed Harris', born:1950})\\n\",\n        \"CREATE (BillPax:Person {name:'Bill Paxton', born:1955})\\n\",\n        \"CREATE\\n\",\n        \"(TomH)-[:ACTED_IN {roles:['Jim Lovell']}]->(Apollo13),\\n\",\n        \"(KevinB)-[:ACTED_IN {roles:['Jack Swigert']}]->(Apollo13),\\n\",\n        \"(EdH)-[:ACTED_IN {roles:['Gene Kranz']}]->(Apollo13),\\n\",\n        \"(BillPax)-[:ACTED_IN {roles:['Fred Haise']}]->(Apollo13),\\n\",\n        \"(GaryS)-[:ACTED_IN {roles:['Ken Mattingly']}]->(Apollo13),\\n\",\n        \"(RonH)-[:DIRECTED]->(Apollo13)\\n\",\n        \"\\n\",\n        \"CREATE (Twister:Movie {title:'Twister', released:1996, tagline:\\\"Don't Breathe. Don't Look Back.\\\"})\\n\",\n        \"CREATE (PhilipH:Person {name:'Philip Seymour Hoffman', born:1967})\\n\",\n        \"CREATE (JanB:Person {name:'Jan de Bont', born:1943})\\n\",\n        \"CREATE\\n\",\n        \"(BillPax)-[:ACTED_IN {roles:['Bill Harding']}]->(Twister),\\n\",\n        \"(HelenH)-[:ACTED_IN {roles:['Dr. Jo Harding']}]->(Twister),\\n\",\n        \"(ZachG)-[:ACTED_IN {roles:['Eddie']}]->(Twister),\\n\",\n        \"(PhilipH)-[:ACTED_IN {roles:['Dustin \\\"Dusty\\\" Davis']}]->(Twister),\\n\",\n        \"(JanB)-[:DIRECTED]->(Twister)\\n\",\n        \"\\n\",\n        \"CREATE (CastAway:Movie {title:'Cast Away', released:2000, tagline:'At the edge of the world, his journey begins.'})\\n\",\n        \"CREATE (RobertZ:Person {name:'Robert Zemeckis', born:1951})\\n\",\n        \"CREATE\\n\",\n        \"(TomH)-[:ACTED_IN {roles:['Chuck Noland']}]->(CastAway),\\n\",\n        \"(HelenH)-[:ACTED_IN {roles:['Kelly Frears']}]->(CastAway),\\n\",\n        \"(RobertZ)-[:DIRECTED]->(CastAway)\\n\",\n        \"\\n\",\n        \"CREATE (OneFlewOvertheCuckoosNest:Movie {title:\\\"One Flew Over the Cuckoo's Nest\\\", released:1975, tagline:\\\"If he's crazy, what does that make you?\\\"})\\n\",\n        \"CREATE (MilosF:Person {name:'Milos Forman', born:1932})\\n\",\n        \"CREATE\\n\",\n        \"(JackN)-[:ACTED_IN {roles:['Randle McMurphy']}]->(OneFlewOvertheCuckoosNest),\\n\",\n        \"(DannyD)-[:ACTED_IN {roles:['Martini']}]->(OneFlewOvertheCuckoosNest),\\n\",\n        \"(MilosF)-[:DIRECTED]->(OneFlewOvertheCuckoosNest)\\n\",\n        \"\\n\",\n        \"CREATE (SomethingsGottaGive:Movie {title:\\\"Something's Gotta Give\\\", released:2003})\\n\",\n        \"CREATE (DianeK:Person {name:'Diane Keaton', born:1946})\\n\",\n        \"CREATE (NancyM:Person {name:'Nancy Meyers', born:1949})\\n\",\n        \"CREATE\\n\",\n        \"(JackN)-[:ACTED_IN {roles:['Harry Sanborn']}]->(SomethingsGottaGive),\\n\",\n        \"(DianeK)-[:ACTED_IN {roles:['Erica Barry']}]->(SomethingsGottaGive),\\n\",\n        \"(Keanu)-[:ACTED_IN {roles:['Julian Mercer']}]->(SomethingsGottaGive),\\n\",\n        \"(NancyM)-[:DIRECTED]->(SomethingsGottaGive),\\n\",\n        \"(NancyM)-[:PRODUCED]->(SomethingsGottaGive),\\n\",\n        \"(NancyM)-[:WROTE]->(SomethingsGottaGive)\\n\",\n        \"\\n\",\n        \"CREATE (BicentennialMan:Movie {title:'Bicentennial Man', released:1999, tagline:\\\"One robot's 200 year journey to become an ordinary man.\\\"})\\n\",\n        \"CREATE (ChrisC:Person {name:'Chris Columbus', born:1958})\\n\",\n        \"CREATE\\n\",\n        \"(Robin)-[:ACTED_IN {roles:['Andrew Marin']}]->(BicentennialMan),\\n\",\n        \"(OliverP)-[:ACTED_IN {roles:['Rupert Burns']}]->(BicentennialMan),\\n\",\n        \"(ChrisC)-[:DIRECTED]->(BicentennialMan)\\n\",\n        \"\\n\",\n        \"CREATE (CharlieWilsonsWar:Movie {title:\\\"Charlie Wilson's War\\\", released:2007, tagline:\\\"A stiff drink. A little mascara. A lot of nerve. Who said they couldn't bring down the Soviet empire.\\\"})\\n\",\n        \"CREATE (JuliaR:Person {name:'Julia Roberts', born:1967})\\n\",\n        \"CREATE\\n\",\n        \"(TomH)-[:ACTED_IN {roles:['Rep. Charlie Wilson']}]->(CharlieWilsonsWar),\\n\",\n        \"(JuliaR)-[:ACTED_IN {roles:['Joanne Herring']}]->(CharlieWilsonsWar),\\n\",\n        \"(PhilipH)-[:ACTED_IN {roles:['Gust Avrakotos']}]->(CharlieWilsonsWar),\\n\",\n        \"(MikeN)-[:DIRECTED]->(CharlieWilsonsWar)\\n\",\n        \"\\n\",\n        \"CREATE (ThePolarExpress:Movie {title:'The Polar Express', released:2004, tagline:'This Holiday Season... Believe'})\\n\",\n        \"CREATE\\n\",\n        \"(TomH)-[:ACTED_IN {roles:['Hero Boy', 'Father', 'Conductor', 'Hobo', 'Scrooge', 'Santa Claus']}]->(ThePolarExpress),\\n\",\n        \"(RobertZ)-[:DIRECTED]->(ThePolarExpress)\\n\",\n        \"\\n\",\n        \"CREATE (ALeagueofTheirOwn:Movie {title:'A League of Their Own', released:1992, tagline:'Once in a lifetime you get a chance to do something different.'})\\n\",\n        \"CREATE (Madonna:Person {name:'Madonna', born:1954})\\n\",\n        \"CREATE (GeenaD:Person {name:'Geena Davis', born:1956})\\n\",\n        \"CREATE (LoriP:Person {name:'Lori Petty', born:1963})\\n\",\n        \"CREATE (PennyM:Person {name:'Penny Marshall', born:1943})\\n\",\n        \"CREATE\\n\",\n        \"(TomH)-[:ACTED_IN {roles:['Jimmy Dugan']}]->(ALeagueofTheirOwn),\\n\",\n        \"(GeenaD)-[:ACTED_IN {roles:['Dottie Hinson']}]->(ALeagueofTheirOwn),\\n\",\n        \"(LoriP)-[:ACTED_IN {roles:['Kit Keller']}]->(ALeagueofTheirOwn),\\n\",\n        \"(RosieO)-[:ACTED_IN {roles:['Doris Murphy']}]->(ALeagueofTheirOwn),\\n\",\n        \"(Madonna)-[:ACTED_IN {roles:['\\\"All the Way\\\" Mae Mordabito']}]->(ALeagueofTheirOwn),\\n\",\n        \"(BillPax)-[:ACTED_IN {roles:['Bob Hinson']}]->(ALeagueofTheirOwn),\\n\",\n        \"(PennyM)-[:DIRECTED]->(ALeagueofTheirOwn)\\n\",\n        \"\\n\",\n        \"CREATE (PaulBlythe:Person {name:'Paul Blythe'})\\n\",\n        \"CREATE (AngelaScope:Person {name:'Angela Scope'})\\n\",\n        \"CREATE (JessicaThompson:Person {name:'Jessica Thompson'})\\n\",\n        \"CREATE (JamesThompson:Person {name:'James Thompson'})\\n\",\n        \"\\n\",\n        \"CREATE\\n\",\n        \"(JamesThompson)-[:FOLLOWS]->(JessicaThompson),\\n\",\n        \"(AngelaScope)-[:FOLLOWS]->(JessicaThompson),\\n\",\n        \"(PaulBlythe)-[:FOLLOWS]->(AngelaScope)\\n\",\n        \"\\n\",\n        \"CREATE\\n\",\n        \"(JessicaThompson)-[:REVIEWED {summary:'An amazing journey', rating:95}]->(CloudAtlas),\\n\",\n        \"(JessicaThompson)-[:REVIEWED {summary:'Silly, but fun', rating:65}]->(TheReplacements),\\n\",\n        \"(JamesThompson)-[:REVIEWED {summary:'The coolest football movie ever', rating:100}]->(TheReplacements),\\n\",\n        \"(AngelaScope)-[:REVIEWED {summary:'Pretty funny at times', rating:62}]->(TheReplacements),\\n\",\n        \"(JessicaThompson)-[:REVIEWED {summary:'Dark, but compelling', rating:85}]->(Unforgiven),\\n\",\n        \"(JessicaThompson)-[:REVIEWED {summary:\\\"Slapstick redeemed only by the Robin Williams and Gene Hackman's stellar performances\\\", rating:45}]->(TheBirdcage),\\n\",\n        \"(JessicaThompson)-[:REVIEWED {summary:'A solid romp', rating:68}]->(TheDaVinciCode),\\n\",\n        \"(JamesThompson)-[:REVIEWED {summary:'Fun, but a little far fetched', rating:65}]->(TheDaVinciCode),\\n\",\n        \"(JessicaThompson)-[:REVIEWED {summary:'You had me at Jerry', rating:92}]->(JerryMaguire)\\n\",\n        \"\\n\",\n        \"WITH TomH as a\\n\",\n        \"MATCH (a)-[:ACTED_IN]->(m)<-[:DIRECTED]-(d) RETURN a,m,d LIMIT 10;\"\n      ],\n      \"metadata\": {\n        \"id\": \"QFbjo1k24YEY\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"You can query the database via **cy2py** in this simple way\"\n      ],\n      \"metadata\": {\n        \"id\": \"peqcEHj0b35T\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"%%cypher\\n\",\n        \"CALL apoc.meta.graph()\"\n      ],\n      \"metadata\": {\n        \"id\": \"BfFOTNkncMqp\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"As you can see the model is exactely how we expect!\"\n      ],\n      \"metadata\": {\n        \"id\": \"sGu-zpk8nY5r\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"# this step is MANDATORY for the exercises\\n\",\n        \"from neo4j import GraphDatabase\\n\",\n        \"neo4j_driver = GraphDatabase.driver(neo4j_url, auth=(neo4j_user, neo4j_password))\"\n      ],\n      \"metadata\": {\n        \"id\": \"_zZF1guo58cc\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"c8bQe1b-7RY-\"\n      },\n      \"source\": [\n        \"# Read data from Neo4j into Spark\\n\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"The query above generates the following graph model:\\n\",\n        \"\\n\"\n      ],\n      \"metadata\": {\n        \"id\": \"ovoUnDmocaxK\"\n      }\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"B1LLHYf1CsPh\"\n      },\n      \"source\": [\n        \"## Read nodes via `labels` option\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"omdSk6ShCqfA\"\n      },\n      \"outputs\": [],\n      \"source\": [\n        \"movies_df = (spark.read\\n\",\n        \"            .format('org.neo4j.spark.DataSource')\\n\",\n        \"            .option('labels', ':Movie')\\n\",\n        \"            .load())\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"RyglSgXnQcar\"\n      },\n      \"source\": [\n        \"### Schema description\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"f9AaUINjPH4n\"\n      },\n      \"outputs\": [],\n      \"source\": [\n        \"movies_df.printSchema()\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"The `movies_df` contains a set of fields, the first two (generally) are always:\\n\",\n        \"\\n\",\n        \"* `<id>` which represents the internal Neo4j id\\n\",\n        \"* `<labels>` which represents the list of labels attached to the node\\n\",\n        \"\\n\",\n        \"All other properties are taken from the node via schema resolution by using APOC or Cypher queries\"\n      ],\n      \"metadata\": {\n        \"id\": \"jxLcYSkgZ1xf\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"omGjaw5QDgS-\"\n      },\n      \"outputs\": [],\n      \"source\": [\n        \"movies_df\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"7-KTRC5HD5sO\"\n      },\n      \"source\": [\n        \"### Exercise\\n\",\n        \"\\n\",\n        \"Read all the `Person` nodes store them into a Python variable called `person_df` and then verify the results\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"ZhnsFC9KEsLp\"\n      },\n      \"outputs\": [],\n      \"source\": [\n        \"person_df = # write your spark code here\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"<details>\\n\",\n        \"<summary>\\n\",\n        \"Show a possible solution\\n\",\n        \"</summary>\\n\",\n        \"\\n\",\n        \"```python\\n\",\n        \"person_df = (spark.read\\n\",\n        \"  .format('org.neo4j.spark.DataSource')\\n\",\n        \"  .option('labels', ':Person')\\n\",\n        \"  .load())\\n\",\n        \"```\\n\",\n        \"\\n\",\n        \"</details>\\n\",\n        \"\\n\"\n      ],\n      \"metadata\": {\n        \"id\": \"O4WEzidAZBh-\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"D5_zXyweE-QM\"\n      },\n      \"outputs\": [],\n      \"source\": [\n        \"\\\"\\\"\\\"\\n\",\n        \" This paragraph is for validating the code the you\\n\",\n        \" wrote above, please execute it after you\\n\",\n        \" created the person_df\\n\",\n        \"\\\"\\\"\\\"\\n\",\n        \"\\n\",\n        \"assert person_df.count() == 133\\n\",\n        \"assert person_df.schema.fieldNames() == ['<id>', '<labels>', 'name', 'born']\\n\",\n        \"assert person_df.collect()[0][\\\"<labels>\\\"] == ['Person']\\n\",\n        \"print(\\\"All assertion are successfuly satisfied. Congrats you created your first DataFrame\\\")\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"m1hgGMLCRoZx\"\n      },\n      \"source\": [\n        \"## Read relationships via `relationship` option\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"HgPockV0I5Q3\"\n      },\n      \"source\": [\n        \"There are two way to transform relationships into DataFrame\\n\",\n        \"\\n\",\n        \"* having all the node and relationship data flattened into the DataFrame\\n\",\n        \"* having all the node properties in maps and the relationship data as columns\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"m0DBqZLtKtvX\"\n      },\n      \"source\": [\n        \"### DataFrame with flattened data\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"796cuMwXR2zi\"\n      },\n      \"outputs\": [],\n      \"source\": [\n        \"actedin_df = (spark.read\\n\",\n        \"            .format('org.neo4j.spark.DataSource')\\n\",\n        \"            .option('relationship', 'ACTED_IN')\\n\",\n        \"            .option('relationship.source.labels', ':Person')\\n\",\n        \"            .option('relationship.target.labels', ':Movie')\\n\",\n        \"            .load())\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"### Schema description\"\n      ],\n      \"metadata\": {\n        \"id\": \"yzyviI5vXO4K\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"5uDWZqoySNGc\"\n      },\n      \"outputs\": [],\n      \"source\": [\n        \"actedin_df.printSchema()\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"The `movies_df` contains a set of fields, the first two (generally) are always:\\n\",\n        \"\\n\",\n        \"* `<rel.id>` which represents the internal Neo4j relationship id\\n\",\n        \"* `<rel.type>` which represents the relationship type\\n\",\n        \"* `<source/target.id>` which represents the internal Neo4j node id\\n\",\n        \"* `<source/target.labels>` which represents the list of labels attached to the node\\n\",\n        \"* `rel.*` which represents the properties attached to the relationship\\n\",\n        \"* `source/target.*` which represents the properties attached to the node\\n\",\n        \"\\n\",\n        \"All other properties are taken from the node via schema resolution by using APOC or Cypher queries\"\n      ],\n      \"metadata\": {\n        \"id\": \"2dB9DL7KZxrX\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"VPHDTL-IUX2X\"\n      },\n      \"outputs\": [],\n      \"source\": [\n        \"actedin_df\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"RoPVDptGKy_m\"\n      },\n      \"source\": [\n        \"### DataFrame with nodes as map\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"8VxgDlBXIt_h\"\n      },\n      \"outputs\": [],\n      \"source\": [\n        \"actedin_map_df = (spark.read\\n\",\n        \"            .format('org.neo4j.spark.DataSource')\\n\",\n        \"            .option('relationship.nodes.map', True)\\n\",\n        \"            .option('relationship', 'ACTED_IN')\\n\",\n        \"            .option('relationship.source.labels', ':Person')\\n\",\n        \"            .option('relationship.target.labels', ':Movie')\\n\",\n        \"            .load())\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"### Schema description\"\n      ],\n      \"metadata\": {\n        \"id\": \"nbGAYcd7YMOp\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"gF5-m4BbI2Ib\"\n      },\n      \"outputs\": [],\n      \"source\": [\n        \"actedin_map_df.printSchema()\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"The `movies_df` contains a set of fields, the first two (generally) are always:\\n\",\n        \"\\n\",\n        \"* `<rel.id>` which represents the internal Neo4j relationship id\\n\",\n        \"* `<rel.type>` which represents the relationship type\\n\",\n        \"* `<source/target>` which represents a map with node values\\n\",\n        \"* `rel.*` which represents the properties attached to the relationship\\n\",\n        \"\\n\",\n        \"All other properties are taken from the node via schema resolution by using APOC or Cypher queries\"\n      ],\n      \"metadata\": {\n        \"id\": \"Zuu42SpfZ502\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"UUYUwE3CLA_r\"\n      },\n      \"outputs\": [],\n      \"source\": [\n        \"actedin_map_df\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"actedin_map_df.collect()[0][\\\"<source>\\\"]\"\n      ],\n      \"metadata\": {\n        \"id\": \"hHPq7neyYDSx\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"### Exercise\\n\",\n        \"\\n\",\n        \"Read all the `DIRECTED` relationships\"\n      ],\n      \"metadata\": {\n        \"id\": \"Viop-9_thCbF\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"directed_df = # write your spark code here\"\n      ],\n      \"metadata\": {\n        \"id\": \"j0tTsk59hhLh\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"<details>\\n\",\n        \"<summary>\\n\",\n        \"Show a possible solution\\n\",\n        \"</summary>\\n\",\n        \"\\n\",\n        \"```python\\n\",\n        \"directed_df = (spark.read\\n\",\n        \"            .format('org.neo4j.spark.DataSource')\\n\",\n        \"            .option('relationship', 'DIRECTED')\\n\",\n        \"            .option('relationship.source.labels', ':Person')\\n\",\n        \"            .option('relationship.target.labels', ':Movie')\\n\",\n        \"            .load())\\n\",\n        \"```\\n\",\n        \"\\n\",\n        \"</details>\"\n      ],\n      \"metadata\": {\n        \"id\": \"VQYyYSMpj2lf\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"\\\"\\\"\\\"\\n\",\n        \" This paragraph is for validating the code the you\\n\",\n        \" wrote above, please execute it after you\\n\",\n        \" created the directed_df\\n\",\n        \"\\\"\\\"\\\"\\n\",\n        \"\\n\",\n        \"assert directed_df.count() == 44\\n\",\n        \"assert directed_df.schema.fieldNames() == ['<rel.id>',\\n\",\n        \" '<rel.type>',\\n\",\n        \" '<source.id>',\\n\",\n        \" '<source.labels>',\\n\",\n        \" 'source.name',\\n\",\n        \" 'source.born',\\n\",\n        \" '<target.id>',\\n\",\n        \" '<target.labels>',\\n\",\n        \" 'target.title',\\n\",\n        \" 'target.tagline',\\n\",\n        \" 'target.released']\\n\",\n        \"assert directed_df.collect()[0][\\\"<rel.type>\\\"] == 'DIRECTED'\\n\",\n        \"print(\\\"All assertion are successfuly satisfied. Congrats you created your first relationship DataFrame\\\")\"\n      ],\n      \"metadata\": {\n        \"id\": \"HRwaJ8PvhudP\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"## Read arbitrary data via Cypher query\"\n      ],\n      \"metadata\": {\n        \"id\": \"hCpzW904dS2r\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"cypher_df = (spark.read\\n\",\n        \"            .format('org.neo4j.spark.DataSource')\\n\",\n        \"            .option('query', '''\\n\",\n        \"              // Extend Tom Hanks co-actors, to find co-co-actors who haven't worked with Tom Hanks\\n\",\n        \"              MATCH (tom:Person {name:\\\"Tom Hanks\\\"})-[:ACTED_IN]->(m)<-[:ACTED_IN]-(coActors),\\n\",\n        \"                (coActors)-[:ACTED_IN]->(m2)<-[:ACTED_IN]-(cocoActors)\\n\",\n        \"              WHERE NOT (tom)-[:ACTED_IN]->()<-[:ACTED_IN]-(cocoActors)\\n\",\n        \"                AND tom <> cocoActors\\n\",\n        \"              RETURN cocoActors.name AS Recommended, count(*) AS Strength\\n\",\n        \"              ORDER BY Strength DESC\\n\",\n        \"            ''')\\n\",\n        \"            .load())\"\n      ],\n      \"metadata\": {\n        \"id\": \"hplBy0b_dhnb\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"### Schema description\"\n      ],\n      \"metadata\": {\n        \"id\": \"tRZPA6xWeSCT\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"cypher_df.printSchema()\"\n      ],\n      \"metadata\": {\n        \"id\": \"hU-JfgNNeL5f\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"cypher_df\"\n      ],\n      \"metadata\": {\n        \"id\": \"8IcUQsileXQ7\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"%%cypher\\n\",\n        \"// Just for debugging purposes let's check the same query directly from the database\\n\",\n        \"MATCH (tom:Person {name:\\\"Tom Hanks\\\"})-[:ACTED_IN]->(m)<-[:ACTED_IN]-(coActors),\\n\",\n        \"  (coActors)-[:ACTED_IN]->(m2)<-[:ACTED_IN]-(cocoActors)\\n\",\n        \"WHERE NOT (tom)-[:ACTED_IN]->()<-[:ACTED_IN]-(cocoActors)\\n\",\n        \"  AND tom <> cocoActors\\n\",\n        \"RETURN cocoActors.name AS Recommended, count(*) AS Strength\\n\",\n        \"ORDER BY Strength DESC\\n\",\n        \"LIMIT 20\"\n      ],\n      \"metadata\": {\n        \"id\": \"CWtNAeoN4O6S\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"### Exercise\\n\",\n        \"\\n\",\n        \"Return all the actors that have also directed a movie.\\n\",\n        \"\\n\",\n        \"The returned DataFrame must have 3 columns:\\n\",\n        \"\\n\",\n        \"* `name` the actor name\\n\",\n        \"* `acted_in` a list of unique films (title) where he acted in\\n\",\n        \"* `directed` a list of unique films (title) where he was a director\"\n      ],\n      \"metadata\": {\n        \"id\": \"Hyq4KsKQegdE\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"your_cypher_df = # write your spark code here\"\n      ],\n      \"metadata\": {\n        \"id\": \"0h1FFuYxej2f\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"<details>\\n\",\n        \"<summary>\\n\",\n        \"Show a possible solution\\n\",\n        \"</summary>\\n\",\n        \"\\n\",\n        \"```python\\n\",\n        \"your_cypher_df = (spark.read\\n\",\n        \"            .format('org.neo4j.spark.DataSource')\\n\",\n        \"            .option('query', '''\\n\",\n        \"              MATCH (p:Person)\\n\",\n        \"              MATCH (p)-[:ACTED_IN]->(m:Movie)\\n\",\n        \"              MATCH (p)-[:DIRECTED]->(m1:Movie)\\n\",\n        \"              RETURN p.name AS name, collect(m.title) AS acted_in, collect(m1.title) AS directed\\n\",\n        \"            ''')\\n\",\n        \"            .load())\\n\",\n        \"```\\n\",\n        \"\\n\",\n        \"</details>\"\n      ],\n      \"metadata\": {\n        \"id\": \"CQncCY52lCxv\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"\\\"\\\"\\\"\\n\",\n        \" This paragraph is for validating the code the you\\n\",\n        \" wrote above, please execute it after you\\n\",\n        \" created the your_cypher_df\\n\",\n        \"\\\"\\\"\\\"\\n\",\n        \"\\n\",\n        \"assert your_cypher_df.count() == 5\\n\",\n        \"assert your_cypher_df.schema.fieldNames() == ['name', 'acted_in', 'directed']\\n\",\n        \"your_cypher_df_collect = your_cypher_df.collect()\\n\",\n        \"assert frozenset(map(lambda row: row['name'], your_cypher_df_collect)) == frozenset(['Clint Eastwood',\\n\",\n        \" 'Danny DeVito',\\n\",\n        \" 'James Marshall',\\n\",\n        \" 'Werner Herzog',\\n\",\n        \" 'Tom Hanks'])\\n\",\n        \"assert frozenset(map(lambda row: frozenset(row['acted_in']), your_cypher_df_collect)) == set([\\n\",\n        \"      frozenset([\\\"Apollo 13\\\", \\\"You've Got Mail\\\", \\\"A League of Their Own\\\", \\\"Joe Versus the Volcano\\\", \\\"That Thing You Do\\\", \\\"The Da Vinci Code\\\", \\\"Cloud Atlas\\\", \\\"Cast Away\\\", \\\"The Green Mile\\\", \\\"Sleepless in Seattle\\\", \\\"The Polar Express\\\", \\\"Charlie Wilson's War\\\"]),\\n\",\n        \"      frozenset([\\\"What Dreams May Come\\\"]),\\n\",\n        \"      frozenset([\\\"Unforgiven\\\"]),\\n\",\n        \"      frozenset([\\\"A Few Good Men\\\"]),\\n\",\n        \"      frozenset([\\\"Hoffa\\\", \\\"One Flew Over the Cuckoo's Nest\\\"])\\n\",\n        \"    ])\\n\",\n        \"assert frozenset(map(lambda row: frozenset(row['directed']), your_cypher_df_collect)) == set([\\n\",\n        \"      frozenset([\\\"That Thing You Do\\\"]),\\n\",\n        \"      frozenset([\\\"RescueDawn\\\"]),\\n\",\n        \"      frozenset([\\\"Unforgiven\\\"]),\\n\",\n        \"      frozenset([\\\"V for Vendetta\\\", \\\"Ninja Assassin\\\"]),\\n\",\n        \"      frozenset([\\\"Hoffa\\\"])\\n\",\n        \"    ])\\n\",\n        \"print(\\\"All assertion are successfuly satisfied. Congrats you created your first cypher dataframe\\\")\"\n      ],\n      \"metadata\": {\n        \"id\": \"xG_7Wy-_go5V\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"hFpA11aK8ADf\"\n      },\n      \"source\": [\n        \"# Write data from Spark to Neo4j\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"## The graph model\\n\",\n        \"\\n\",\n        \"Our goal is to create this simple graph model\\n\",\n        \"\\n\",\n        \"<img src=\\\"https://dist.neo4j.com/wp-content/uploads/developer-desktop-csv-import-data_model.svg\\\" >\"\n      ],\n      \"metadata\": {\n        \"id\": \"Mx84Qi1PcHF_\"\n      }\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"Trt-L_9pMQf1\"\n      },\n      \"source\": [\n        \"### Download The Dataset\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"h4o07NpuJmaG\"\n      },\n      \"outputs\": [],\n      \"source\": [\n        \"!wget -q https://s3.amazonaws.com/dev.assets.neo4j.com/wp-content/uploads/desktop-csv-import.zip\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"The zip is composed of three files:\\n\",\n        \"* products.csv: describes the products and has three columns (and no header)\\n\",\n        \"* orders.csv: has three columns (with the header) and describe the order\\n\",\n        \"* order-details.csv: is the \\\"join\\\" table between orders and products; it has three columns with header\"\n      ],\n      \"metadata\": {\n        \"id\": \"KKfl_ZyhYYWj\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"nduIG7H_J0-A\"\n      },\n      \"outputs\": [],\n      \"source\": [\n        \"!unzip desktop-csv-import.zip\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"w5kaTPoEQNkT\"\n      },\n      \"source\": [\n        \"### Explore the Dataset\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"L0TZgi_E1gAv\"\n      },\n      \"outputs\": [],\n      \"source\": [\n        \"products_df = (spark.read\\n\",\n        \"      .format('csv')\\n\",\n        \"      .option('inferSchema', True)\\n\",\n        \"      .option('path', '/content/desktop-csv-import/products.csv')\\n\",\n        \"      .load())\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"0tptDEUn2WO6\"\n      },\n      \"outputs\": [],\n      \"source\": [\n        \"products_df.printSchema()\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"ZSW40PxjKvgf\"\n      },\n      \"outputs\": [],\n      \"source\": [\n        \"products_df\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"As you can see in the schema, colums have no name, just a generic `_c` prefix concatenated with an index.\\n\",\n        \"The three columns describe:\\n\",\n        \"* `_c0` is the `id` of the product\\n\",\n        \"* `_c1` is the `name`\\n\",\n        \"* `_c2` is the `price`\\n\",\n        \"\\n\",\n        \"Let's rename these columns!\"\n      ],\n      \"metadata\": {\n        \"id\": \"VrKERh4uXu8J\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"7xabRYlXQZl4\"\n      },\n      \"outputs\": [],\n      \"source\": [\n        \"products_df = (products_df.withColumnRenamed('_c0', 'id')\\n\",\n        \"      .withColumnRenamed('_c1', 'name')\\n\",\n        \"      .withColumnRenamed('_c2', 'price'))\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"w08HTcIeQuNn\"\n      },\n      \"outputs\": [],\n      \"source\": [\n        \"products_df.printSchema()\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"XCkyYIyzQv0X\"\n      },\n      \"outputs\": [],\n      \"source\": [\n        \"products_df\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"## Write nodes via `label` option\"\n      ],\n      \"metadata\": {\n        \"id\": \"XL9oBe0-m680\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"Oy4eoeAMRWxc\"\n      },\n      \"outputs\": [],\n      \"source\": [\n        \"(products_df.write\\n\",\n        \" .format('org.neo4j.spark.DataSource')\\n\",\n        \" .mode('append')\\n\",\n        \" .option('labels', ':Product')\\n\",\n        \" .save())\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"Let's check if the nodes are in the database!\"\n      ],\n      \"metadata\": {\n        \"id\": \"MLxewMeFsQj3\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"%%cypher\\n\",\n        \"MATCH (n:Product)\\n\",\n        \"RETURN n\\n\",\n        \"LIMIT 10\"\n      ],\n      \"metadata\": {\n        \"id\": \"2yoBPvmmsUqt\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"Now just to be sure that we loaded all the nodes into Neo4j we'll count the dataframe and the nodes inside the database\"\n      ],\n      \"metadata\": {\n        \"id\": \"10PLvdmZ0tZT\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"products_df.count()\"\n      ],\n      \"metadata\": {\n        \"id\": \"AmwadsK702Sl\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"%%cypher\\n\",\n        \"MATCH (n:Product)\\n\",\n        \"RETURN count(n)\"\n      ],\n      \"metadata\": {\n        \"id\": \"J8e9jZPG06DL\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"If the two counts are equal, all the data has been properly imported.\"\n      ],\n      \"metadata\": {\n        \"id\": \"T8XAaw3K1Mga\"\n      }\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"### Create Constraints\\n\",\n        \"\\n\",\n        \"Oh but wait, we forgot to create constraints!!! if we go into the Neo4j browser and excute the following query:\\n\",\n        \"\\n\",\n        \"```cypher\\n\",\n        \"show constraints\\n\",\n        \"```\\n\",\n        \"\\n\",\n        \"We should get the constraints of the movie database, but not one for `Product`.\\n\",\n        \"\\n\",\n        \"So please create the constaints for the node `Product`:\\n\",\n        \"\\n\",\n        \"```cypher\\n\",\n        \"CREATE CONSTRAINT product_id FOR (p:Product) REQUIRE p.id IS UNIQUE;\\n\",\n        \"```\\n\",\n        \"\\n\",\n        \"But if you want, you can also delegate the Spark connector to perform optimizations pre-processing by usign the option `schema.optimization.type` which can assume three values:\\n\",\n        \"\\n\",\n        \"* `INDEX`: it creates only indexes on provided nodes.\\n\",\n        \"* `NODE_CONSTRAINTS`: it creates only indexes on provided nodes.\\n\",\n        \"\\n\",\n        \"So let's create the `Order` node with by let the connector creating the constraints for you\"\n      ],\n      \"metadata\": {\n        \"id\": \"jFL_tQk0tsni\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"%%cypher\\n\",\n        \"// Check the constraints\\n\",\n        \"SHOW CONSTRAINTS\"\n      ],\n      \"metadata\": {\n        \"id\": \"T3PUsfIvsi23\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"%%cypher\\n\",\n        \"// Create the constraint for Product node\\n\",\n        \"CREATE CONSTRAINT product_id IF NOT EXISTS FOR (p:Product) REQUIRE p.id IS UNIQUE;\"\n      ],\n      \"metadata\": {\n        \"id\": \"iMF68OU20XhE\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"%%cypher\\n\",\n        \"// Check (again) the constraints\\n\",\n        \"SHOW CONSTRAINTS\"\n      ],\n      \"metadata\": {\n        \"id\": \"w_wSMYvz0fz_\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"As you can see now we have the `product_id` constraint in the result list\"\n      ],\n      \"metadata\": {\n        \"id\": \"2JwYLMva1VnN\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"orders_df = (spark.read\\n\",\n        \"      .format('csv')\\n\",\n        \"      .option('inferSchema', True)\\n\",\n        \"      .option('header', True)\\n\",\n        \"      .option('path', '/content/desktop-csv-import/orders.csv')\\n\",\n        \"      .load())\"\n      ],\n      \"metadata\": {\n        \"id\": \"m5ge2R_Ggd3K\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"orders_df.printSchema()\"\n      ],\n      \"metadata\": {\n        \"id\": \"7UGwHtuJwFU4\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"orders_df\"\n      ],\n      \"metadata\": {\n        \"id\": \"uGmUP5ZMwJkm\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"# we cast orderDate to timestamp in order to have it converted properly into Neo4j\\n\",\n        \"orders_df = orders_df.selectExpr('orderID AS id', 'CAST(orderDate AS TIMESTAMP) AS date', 'shipCountry')\"\n      ],\n      \"metadata\": {\n        \"id\": \"InwYglcUwXNy\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"orders_df.printSchema()\"\n      ],\n      \"metadata\": {\n        \"id\": \"kSJmW81cw_ES\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"orders_df\"\n      ],\n      \"metadata\": {\n        \"id\": \"7VN5RAizxSr2\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"(orders_df.write\\n\",\n        \" .format('org.neo4j.spark.DataSource')\\n\",\n        \" .mode('overwrite')\\n\",\n        \" .option('labels', ':Order')\\n\",\n        \" .option('schema.optimization.type', 'NODE_CONSTRAINTS')\\n\",\n        \" # this is necessary in order to specify what is the constraint field\\n\",\n        \" .option('node.keys', 'id')\\n\",\n        \" .save())\"\n      ],\n      \"metadata\": {\n        \"id\": \"0rwKB9V-xTzu\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"Now let's check if the connector has created the constraint for us\"\n      ],\n      \"metadata\": {\n        \"id\": \"A_T2beEJx3Ho\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"%%cypher\\n\",\n        \"SHOW CONSTRAINTS\"\n      ],\n      \"metadata\": {\n        \"id\": \"hDxdKyFY1sDT\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"As you can see the we have the constraint `spark_NODE_CONSTRAINTS_Order_id` that has been create by the Spark connector itself.\\n\",\n        \"\\n\",\n        \"Now just because we're courious let's check if the data has been propertly loaded.\\n\",\n        \"\\n\",\n        \"The first thing to check is if the count of the Dataframe and the nodes in Neo4j matches.\"\n      ],\n      \"metadata\": {\n        \"id\": \"H5Bne-Mq1vsO\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"orders_df.count()\"\n      ],\n      \"metadata\": {\n        \"id\": \"mANrH-Zt2ShO\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"%%cypher\\n\",\n        \"MATCH (o:Order)\\n\",\n        \"RETURN count(o)\"\n      ],\n      \"metadata\": {\n        \"id\": \"vzCCVYAK2V0X\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"Now we want to check if the data has been loaded with the proper data type, in particular we created a new column `date` by casting `orderDate` to `TIMESTAMP`.\"\n      ],\n      \"metadata\": {\n        \"id\": \"X8BBxCQg2dFM\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"%%cypher\\n\",\n        \"MATCH (o:Order)\\n\",\n        \"RETURN apoc.meta.cypher.type(o.date), count(o)\"\n      ],\n      \"metadata\": {\n        \"id\": \"VN7XMI192xAP\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"So all the `date` values have the same type.\"\n      ],\n      \"metadata\": {\n        \"id\": \"PpXyKtJF3Lk4\"\n      }\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"### Exercise\\n\",\n        \"\\n\",\n        \"Given the `football_teams_df` and `football_player_df` below please:\\n\",\n        \"* for `football_teams_df` insert it as nodes with label `:FootballTeam` in Neo4j.\\n\",\n        \"* for `football_player_df` insert it as nodes with label `:FootballPlayer` in Neo4j.\\n\",\n        \"\\n\",\n        \"Create for both of them constraints via the schema optimization feature:\\n\",\n        \"* for `football_teams_df` the key must be the property `id`\\n\",\n        \"* for `football_player_df` the key must be the property `name`\"\n      ],\n      \"metadata\": {\n        \"id\": \"Zi4Dl2LqmVmN\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"football_teams_df = spark.createDataFrame([{'id': 1, 'name': 'AC Milan'}, {'id': 2, 'name': 'FC Internazionale'}])\\n\",\n        \"football_player_df = spark.createDataFrame([\\n\",\n        \"  {'name': 'Zlatan Ibrahimovic'},\\n\",\n        \"  {'name': 'Sandro Tonali'},\\n\",\n        \"  {'name': 'Nicolò Barella'},\\n\",\n        \"  {'name': 'Marcelo Brozovic'}])\"\n      ],\n      \"metadata\": {\n        \"id\": \"21tFDtgAmVON\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"# write your spark code that persist football_teams_df and football_player_df here\"\n      ],\n      \"metadata\": {\n        \"id\": \"utpvz-fI6blD\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"<details>\\n\",\n        \"<summary>\\n\",\n        \"Show a possible solution\\n\",\n        \"</summary>\\n\",\n        \"\\n\",\n        \"```python\\n\",\n        \"# write the teams\\n\",\n        \"(football_teams_df.write\\n\",\n        \" .format('org.neo4j.spark.DataSource')\\n\",\n        \" .mode('overwrite')\\n\",\n        \" .option('labels', ':FootballTeam')\\n\",\n        \" .option('schema.optimization.type', 'NODE_CONSTRAINTS')\\n\",\n        \" .option('node.keys', 'id')\\n\",\n        \" .save())\\n\",\n        \"# write the players\\n\",\n        \"(football_player_df.write\\n\",\n        \" .format('org.neo4j.spark.DataSource')\\n\",\n        \" .mode('overwrite')\\n\",\n        \" .option('labels', ':FootballPlayer')\\n\",\n        \" .option('schema.optimization.type', 'NODE_CONSTRAINTS')\\n\",\n        \" .option('node.keys', 'name')\\n\",\n        \" .save())\\n\",\n        \"```\\n\",\n        \"\\n\",\n        \"</details>\"\n      ],\n      \"metadata\": {\n        \"id\": \"xeVxPe7PmEy8\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"\\\"\\\"\\\"\\n\",\n        \" This paragraph is for validating the code the you\\n\",\n        \" wrote above, please execute it after you\\n\",\n        \" persisted football_teams_df and\\n\",\n        \" football_player_df in Neo4j as nodes\\n\",\n        \"\\\"\\\"\\\"\\n\",\n        \"\\n\",\n        \"with neo4j_driver.session() as session:\\n\",\n        \"  # count football players\\n\",\n        \"  football_players = session.read_transaction(lambda tx: (tx.run('''\\n\",\n        \"      MATCH (p:FootballPlayer)\\n\",\n        \"      WHERE p.name IN ['Zlatan Ibrahimovic', 'Sandro Tonali',\\n\",\n        \"        'Nicolò Barella', 'Marcelo Brozovic']\\n\",\n        \"      RETURN count(p) AS count\\n\",\n        \"    ''').single()['count']))\\n\",\n        \"  assert football_players == 4\\n\",\n        \"\\n\",\n        \"  # count football teams\\n\",\n        \"  football_teams = session.read_transaction(lambda tx: (tx.run('''\\n\",\n        \"      MATCH (p:FootballTeam)\\n\",\n        \"      WHERE p.name IN ['AC Milan', 'FC Internazionale']\\n\",\n        \"      RETURN count(p) AS count\\n\",\n        \"    ''').single()['count']))\\n\",\n        \"  assert football_teams == 2\\n\",\n        \"\\n\",\n        \"  # count constraints\\n\",\n        \"  football_constraints = session.read_transaction(lambda tx: (tx.run('''\\n\",\n        \"      SHOW CONSTRAINTS YIELD name\\n\",\n        \"      WHERE name IN ['spark_NODE_CONSTRAINTS_FootballPlayer_name', 'spark_NODE_CONSTRAINTS_FootballTeam_id']\\n\",\n        \"      RETURN count(*) AS count\\n\",\n        \"    ''').single()['count']))\\n\",\n        \"  assert football_constraints == 2\\n\",\n        \"\\n\",\n        \"print(\\\"All assertion are successfuly satisfied. Congrats you saved your first Node DataFrame into Neo4j!\\\")\"\n      ],\n      \"metadata\": {\n        \"id\": \"a5zQCEyK6h5f\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"## Write relationships via `relationship` option\"\n      ],\n      \"metadata\": {\n        \"id\": \"QltYkhIuy2Kc\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"order_details_df = (spark.read\\n\",\n        \"      .format('csv')\\n\",\n        \"      .option('inferSchema', True)\\n\",\n        \"      .option('header', True)\\n\",\n        \"      .option('path', '/content/desktop-csv-import/order-details.csv')\\n\",\n        \"      .load())\"\n      ],\n      \"metadata\": {\n        \"id\": \"y3U_X0b7x2UN\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"order_details_df.printSchema()\"\n      ],\n      \"metadata\": {\n        \"id\": \"zFqKW-j-zRyk\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"order_details_df\"\n      ],\n      \"metadata\": {\n        \"id\": \"5s5f3W984Jc0\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"Please remember that this is the pattern that we want to ingest:\\n\",\n        \"\\n\",\n        \"\\n\",\n        \"<img src=\\\"https://dist.neo4j.com/wp-content/uploads/developer-desktop-csv-import-data_model.svg\\\" >\"\n      ],\n      \"metadata\": {\n        \"id\": \"aZWSOtNK2qEw\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"(order_details_df.write\\n\",\n        \" .format('org.neo4j.spark.DataSource')\\n\",\n        \" .mode('overwrite')\\n\",\n        \" .option('relationship', 'CONTAINS')\\n\",\n        \" .option('relationship.save.strategy', 'keys')\\n\",\n        \" .option('relationship.source.labels', ':Product')\\n\",\n        \" .option('relationship.source.save.mode', 'Match')\\n\",\n        \" .option('relationship.source.node.keys', 'productID:id')\\n\",\n        \" .option('relationship.target.labels', ':Order')\\n\",\n        \" .option('relationship.target.save.mode', 'Match')\\n\",\n        \" .option('relationship.target.node.keys', 'orderID:id')\\n\",\n        \" .option('relationship.properties', 'quantity:quantityOrdered')\\n\",\n        \" .save())\"\n      ],\n      \"metadata\": {\n        \"id\": \"rFo3KWA90rmZ\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"Now let's check the count for both Dataframe and relationships in Neo4j\"\n      ],\n      \"metadata\": {\n        \"id\": \"1PaC36iZ3bNf\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"order_details_df.count()\"\n      ],\n      \"metadata\": {\n        \"id\": \"OUZ5FYHP3qvj\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"%%cypher\\n\",\n        \"MATCH (p:Product)-[r:CONTAINS]->(o:Order)\\n\",\n        \"RETURN count(r)\"\n      ],\n      \"metadata\": {\n        \"id\": \"ex8o2pSo34cI\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"### Exercise\\n\",\n        \"\\n\",\n        \"Given the `team_player_df` create a relationship between `:FootballPlayer` and `:FootballTeam` of type `PLAYS_FOR`:\\n\",\n        \"\\n\",\n        \"```cypher\\n\",\n        \"(:FootballPlayer)-[:PLAYS_FOR]->(:FootballTeam)\\n\",\n        \"```\"\n      ],\n      \"metadata\": {\n        \"id\": \"lTBo369687lC\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"team_player_df = spark.createDataFrame([\\n\",\n        \"  {'id': 1, 'football_player': 'Zlatan Ibrahimovic'},\\n\",\n        \"  {'id': 1, 'football_player': 'Sandro Tonali'},\\n\",\n        \"  {'id': 2, 'football_player': 'Nicolò Barella'},\\n\",\n        \"  {'id': 2, 'football_player': 'Marcelo Brozovic'}])\"\n      ],\n      \"metadata\": {\n        \"id\": \"gi9kB0l49f8H\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"# write your spark code that persist team_player_df here\"\n      ],\n      \"metadata\": {\n        \"id\": \"i7ZjASDx_Kiy\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"<details>\\n\",\n        \"<summary>\\n\",\n        \"Show a possible solution\\n\",\n        \"</summary>\\n\",\n        \"\\n\",\n        \"```python\\n\",\n        \"(team_player_df.write\\n\",\n        \" .format('org.neo4j.spark.DataSource')\\n\",\n        \" .mode('overwrite')\\n\",\n        \" .option('relationship', 'PLAYS_FOR')\\n\",\n        \" .option('relationship.save.strategy', 'keys')\\n\",\n        \" .option('relationship.source.labels', ':FootballPlayer')\\n\",\n        \" .option('relationship.source.save.mode', 'Match')\\n\",\n        \" .option('relationship.source.node.keys', 'football_player:name')\\n\",\n        \" .option('relationship.target.labels', ':FootballTeam')\\n\",\n        \" .option('relationship.target.save.mode', 'Match')\\n\",\n        \" .option('relationship.target.node.keys', 'id')\\n\",\n        \" .save())\\n\",\n        \"```\\n\",\n        \"\\n\",\n        \"</details>\"\n      ],\n      \"metadata\": {\n        \"id\": \"oNRJevUSm0Wi\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"\\\"\\\"\\\"\\n\",\n        \" This paragraph is for validating the code the you\\n\",\n        \" wrote above, please execute it after you\\n\",\n        \" persisted team_player_df as relationships\\n\",\n        \"\\\"\\\"\\\"\\n\",\n        \"\\n\",\n        \"with neo4j_driver.session() as session:\\n\",\n        \"  # count relationships\\n\",\n        \"  def count_relationships(tx):\\n\",\n        \"    result = tx.run('''\\n\",\n        \"      MATCH (p:FootballPlayer)-[:PLAYS_FOR]->(t:FootballTeam)\\n\",\n        \"      RETURN t.name AS team, collect(p.name) AS players\\n\",\n        \"      ORDER by team\\n\",\n        \"    ''')\\n\",\n        \"    return [{'team': record['team'], 'players': set(record['players'])} for record in result]\\n\",\n        \"\\n\",\n        \"  actual = session.read_transaction(count_relationships)\\n\",\n        \"  expected = [\\n\",\n        \"    {'team': 'AC Milan', 'players': frozenset(['Zlatan Ibrahimovic', 'Sandro Tonali'])},\\n\",\n        \"    {'team': 'FC Internazionale', 'players': frozenset(['Nicolò Barella', 'Marcelo Brozovic'])}\\n\",\n        \"  ]\\n\",\n        \"  assert actual == expected\\n\",\n        \"\\n\",\n        \"print(\\\"All assertion are successfuly satisfied. Congrats you saved your first Relationship DataFrame into Neo4j!\\\")\"\n      ],\n      \"metadata\": {\n        \"id\": \"LDYbmoUx_Owb\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"## Write custom graphs via Cypher Query\\n\",\n        \"\\n\",\n        \"Now let's consider that two actors created an order and bought several products, and we want to add information in our database.\"\n      ],\n      \"metadata\": {\n        \"id\": \"vBq9NCWlZkHw\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"actor_orders = [\\n\",\n        \"  {'actor_name': 'Cuba Gooding Jr.', 'order_id': 1, 'products': [11, 42, 72], 'quantities': [1, 2, 3], 'order_date': '2022-06-07 00:00:00'},\\n\",\n        \"  {'actor_name': 'Tom Hanks', 'order_id': 2, 'products': [24, 55, 75], 'quantities': [3, 2, 1], 'order_date': '2022-06-06 00:00:00'}\\n\",\n        \"]\\n\",\n        \"\\n\",\n        \"actor_orders_df = spark.createDataFrame(actor_orders)\"\n      ],\n      \"metadata\": {\n        \"id\": \"3y_yEOouaHxe\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"actor_orders_df.printSchema()\"\n      ],\n      \"metadata\": {\n        \"id\": \"hYo7nlgvbfdm\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"actor_orders_df\"\n      ],\n      \"metadata\": {\n        \"id\": \"fOkW4w2lbhZP\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"In this case please go into Neo4j and create the following constraint:\\n\",\n        \"\\n\",\n        \"```cypher\\n\",\n        \"CREATE CONSTRAINT person_name FOR (p:Person) REQUIRE p.name is UNIQUE;\\n\",\n        \"```\"\n      ],\n      \"metadata\": {\n        \"id\": \"q0wAIB5l7qp9\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"%%cypher\\n\",\n        \"// if you didn't before create the constraint on Person.name\\n\",\n        \"CREATE CONSTRAINT person_name IF NOT EXISTS FOR (p:Person) REQUIRE p.name is UNIQUE;\"\n      ],\n      \"metadata\": {\n        \"id\": \"-_Lxm_zV4qw2\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"(actor_orders_df.write\\n\",\n        \" .format('org.neo4j.spark.DataSource')\\n\",\n        \" .mode('overwrite')\\n\",\n        \" .option('query', '''\\n\",\n        \"  MATCH (person:Person {name: event.actor_name})\\n\",\n        \"  MERGE (order:Order {id: event.order_id, date: datetime(replace(event.order_date, ' ', 'T'))})\\n\",\n        \"  MERGE (person)-[:CREATED]->(order)\\n\",\n        \"  WITH event, order\\n\",\n        \"  UNWIND range(0, size(event.products) - 1) AS index\\n\",\n        \"  MATCH (product:Product {id: event.products[index]})\\n\",\n        \"  MERGE (product)-[:CONTAINS{quantityOrdered: event.quantities[index]}]->(order)\\n\",\n        \" ''')\\n\",\n        \" .save())\"\n      ],\n      \"metadata\": {\n        \"id\": \"cm3RQyLbbjue\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"What we expect now is that for the two actors there are two orders one per each, then each order contains three products.\"\n      ],\n      \"metadata\": {\n        \"id\": \"61LUSN4F6pQq\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"%%cypher\\n\",\n        \"MATCH (a:Person)-[:CREATED]->(o:Order)<-[c:CONTAINS]-(p:Product)\\n\",\n        \"WHERE a.name IN ['Cuba Gooding Jr.', 'Tom Hanks']\\n\",\n        \"RETURN a.name, o.id, o.date, p.name, c.quantityOrdered\"\n      ],\n      \"metadata\": {\n        \"id\": \"8fVMQiTf61mN\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"### Exercise\\n\",\n        \"\\n\",\n        \"Given `neo4j_resources_df` build a small Knowledge Graph in Neo4j with the following structure:\\n\",\n        \"\\n\",\n        \"```cypher\\n\",\n        \"(:Author{name})-[:CREATED]->(:Resource{name})-[:HAS_TAG]->(:Tag{name})\\n\",\n        \"```\"\n      ],\n      \"metadata\": {\n        \"id\": \"pn7IM8me9R3I\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"neo4j_resources_df = spark.createDataFrame([\\n\",\n        \"    {'author': 'LARUS Business Automation', 'resource': 'Galileo.XAI', 'tags': ['Graph Machine Learning', 'Neo4j', 'Explainable AI', 'Artificial Intelligence']},\\n\",\n        \"    {'author': 'Neo4j', 'resource': 'Graph Data Science Library', 'tags': ['Graph Machine Learning', 'Algorithms']},\\n\",\n        \"    {'author': 'Michael Hunger', 'resource': 'APOC', 'tags': ['Graph Data Integration', 'Graph Algorithms']}\\n\",\n        \"])\"\n      ],\n      \"metadata\": {\n        \"id\": \"_wmoLl8d9RVz\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"neo4j_resources_df\"\n      ],\n      \"metadata\": {\n        \"id\": \"NkG1jCynLXgJ\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"# write your spark code that persist neo4j_resources_df here\"\n      ],\n      \"metadata\": {\n        \"id\": \"8EQmY-qhsbi1\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"<details>\\n\",\n        \"<summary>\\n\",\n        \"Show a possible solution\\n\",\n        \"</summary>\\n\",\n        \"\\n\",\n        \"```python\\n\",\n        \"(neo4j_resources_df.write\\n\",\n        \" .format('org.neo4j.spark.DataSource')\\n\",\n        \" .mode('overwrite')\\n\",\n        \" .option('query', '''\\n\",\n        \"    MERGE (a:Author {name: event.author})\\n\",\n        \"    MERGE (r:Resource {name: event.resource})\\n\",\n        \"    MERGE (a)-[:CREATED]->(r)\\n\",\n        \"    WITH a, r, event\\n\",\n        \"    UNWIND event.tags AS tag\\n\",\n        \"    MERGE (t:Tag{name: tag})\\n\",\n        \"    MERGE (r)-[:HAS_TAG]->(t)\\n\",\n        \" ''')\\n\",\n        \" .save())\\n\",\n        \"```\\n\",\n        \"\\n\",\n        \"</details>\"\n      ],\n      \"metadata\": {\n        \"id\": \"KCfw_saanywo\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"\\\"\\\"\\\"\\n\",\n        \" This paragraph is for validating the code the you\\n\",\n        \" wrote above, please execute it after you\\n\",\n        \" persisted neo4j_resources_df as Cypher query\\n\",\n        \"\\\"\\\"\\\"\\n\",\n        \"\\n\",\n        \"with neo4j_driver.session() as session:\\n\",\n        \"  # count relationships\\n\",\n        \"  def check_graph_consistency(tx):\\n\",\n        \"    result = tx.run('''\\n\",\n        \"      MATCH (a:Author)-[:CREATED]->(r:Resource)-[:HAS_TAG]->(t:Tag)\\n\",\n        \"      RETURN a.name AS author, r.name AS resource, collect(t.name) AS tags\\n\",\n        \"      ORDER By author\\n\",\n        \"    ''')\\n\",\n        \"    return [{'author': record['author'], 'resource': record['resource'], 'tags': set(record['tags'])} for record in result]\\n\",\n        \"\\n\",\n        \"  actual = session.read_transaction(check_graph_consistency)\\n\",\n        \"  expected = [\\n\",\n        \"    {'author': 'LARUS Business Automation', 'resource': 'Galileo.XAI', 'tags': frozenset(['Graph Machine Learning', 'Neo4j', 'Explainable AI', 'Artificial Intelligence'])},\\n\",\n        \"    {'author': 'Michael Hunger', 'resource': 'APOC', 'tags': frozenset(['Graph Data Integration', 'Graph Algorithms'])},\\n\",\n        \"    {'author': 'Neo4j', 'resource': 'Graph Data Science Library', 'tags': frozenset(['Graph Machine Learning', 'Algorithms'])}\\n\",\n        \"  ]\\n\",\n        \"  assert actual == expected\\n\",\n        \"\\n\",\n        \"print(\\\"All assertion are successfuly satisfied. Congrats you saved your first Knowledge Graph DataFrame into Neo4j!\\\")\"\n      ],\n      \"metadata\": {\n        \"id\": \"LwqbSsEcsgDi\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [],\n      \"metadata\": {\n        \"id\": \"_LbqufNZMj6-\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    }\n  ],\n  \"metadata\": {\n    \"colab\": {\n      \"provenance\": [],\n      \"toc_visible\": true\n    },\n    \"kernelspec\": {\n      \"display_name\": \"Python 3\",\n      \"name\": \"python3\"\n    },\n    \"language_info\": {\n      \"name\": \"python\"\n    }\n  },\n  \"nbformat\": 4,\n  \"nbformat_minor\": 0\n}"
  },
  {
    "path": "examples/neo4j_data_science.ipynb",
    "content": "{\n  \"nbformat\": 4,\n  \"nbformat_minor\": 0,\n  \"metadata\": {\n    \"colab\": {\n      \"provenance\": [],\n      \"toc_visible\": true\n    },\n    \"kernelspec\": {\n      \"name\": \"python3\",\n      \"display_name\": \"Python 3\"\n    },\n    \"language_info\": {\n      \"name\": \"python\"\n    }\n  },\n  \"cells\": [\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"Open this notebook in Google Colab <a target=\\\"_blank\\\" href=\\\"https://colab.research.google.com/github/neo4j/neo4j-spark-connector/blob/5.0/examples/neo4j_data_science.ipynb\\\">\\n\",\n        \"  <img src=\\\"https://colab.research.google.com/assets/colab-badge.svg\\\" alt=\\\"Open In Colab\\\"/>\\n\",\n        \"</a>\"\n      ],\n      \"metadata\": {\n        \"id\": \"ciNaixnkx1vj\"\n      }\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"# Example of a Simple data science workflow with Neo4j and Spark\"\n      ],\n      \"metadata\": {\n        \"id\": \"zADiJjnuVfq2\"\n      }\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"This notebook contains a set of examples that explains how the Neo4j Spark connector can fit in you Data Scinece workflow, how you can combine Spark Neo4j and the Graph Data Science library to extract insights from your data and mostly important it allows you to test your knowledge with a set of exercises after each section.\\n\",\n        \"\\n\",\n        \"If you have any questions or problems feel free to write a post in the [Neo4j community forum](https://community.neo4j.com/) or in [Discord](https://discord.com/invite/neo4j).\\n\",\n        \"\\n\",\n        \"If you want more exercises feel free to open an issue in the [GitHub repository](https://github.com/neo4j/neo4j-spark-connector).\\n\",\n        \"\\n\",\n        \"Enjoy!\"\n      ],\n      \"metadata\": {\n        \"id\": \"nLucMn17V0YK\"\n      }\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"# Notes about this notebook\\n\",\n        \"\\n\",\n        \"This code contains a simple data science workflow that combines Neo4j's Graph Data Science Library with the Neo4j Connector for Apache Spark.\\n\",\n        \"\\n\",\n        \"Going forward you'll find code examples in:\\n\",\n        \"\\n\",\n        \"* PySpark\\n\",\n        \"* PySpark Pandas\\n\",\n        \"\\n\",\n        \"You can choose to navigate by using one of them, or both, but we suggest you do one at time to ensure you understand the APIs.\"\n      ],\n      \"metadata\": {\n        \"id\": \"pWWY8190RB98\"\n      }\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"# Create the sandbox instance\\n\",\n        \"\\n\",\n        \"You can easily spin-up a Neo4j sandbox by click [here](https://sandbox.neo4j.com/?usecase=fraud-detection)\\n\",\n        \"\\n\",\n        \"After that you'll be redirect in a webpage like this:\\n\",\n        \"\\n\",\n        \"<img src=\\\"data:image/png;base64,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dgfckKQVQ1ISBLeahgYjJMiU7oAbcnIPNXkTBLeahgYjJMiU7oAbcnIPNXkTBLeahgYjJMiU7oAbcnIPNXkTBLeahgYjJMiU7oAbcnIPNXkTBLeahgYjJMiU7oAbcnIPNXkTBLeahgYjJMiU7oAbcnIPNXkTBLeahgYjJMiU7oAbcnIPNXkTBLeahgYjJMiU7oAbcnIPNXkTBLeahgYjJMiU7oAbcnIPNXkTBLeahgYjJMiU7oAbcnIPNXkTBLeahgYjJMiU7oAbcnIPNXkTBLeahgYjJMiU7oAbcnIPNXkTBLeahgYjJMiU7oAbcnIPNXkTBLeahgYjJMiU7oAbcnIPNXkTBLeahgYjJMiU7oAbcnIPNXkTBLeahgYjJMiU7oAbcnIPNXkTBLeahgYjJMiU7oAbcnIPNXkTBLeahgYjJMiU7oAbcnIPNXkTBLeahgYjJMiU7oAbcnIPNXkTBLeahgYjJMiU7oAbcnIPNXkTBLeahgYjJMiU7oAbcnIPNXkTBLeahgYjJMiU7oAbcnIPNXkTBLeahgYjJMiU7oAbcnIPNXkTBLeahgYjJMiU7oAbcnIPNXkTBLeahgYjJMiU7oAbcnIPNXkTBLeahgYjJMiU7oAbcnIPNXkTBLeahgYjJMiU7oAbcnIPNXkTBLeahgYjJMiU7oAbcnIPNXkTBLeahgYjJMiU7oAbcnIPNXkTBLeahgYjJMiU7oAbcnIPNXkTBLeahgYjJMiU7oAbcnIPNXkTBLeahgYjJMiU7oAbcnIPNXkTBLeahgYjJMiU7oAbcnIPNXkTBLeahgYjJMiU7oAbcnIPNXkTBLeahgYjJMiU7oAbcnIPNXkTBLeahgYjJMiU7oAbcnIPNXkTBLeahgYjJMiU7oAbcnIPNXkTBLeahgYjJMiU7oAbcnIPNXkTBLeahgYjJMiU7oAbcnIPNXkTBLeahgYjJMiU7oAbcnIPNXkTBLeahgYjJMiU7oAbcnIPNXkTBLeahgYjJMiU7oAbcnIPNXkTBLeahgYjJMiU7oAbcnIPNXkTBLeahgYjJMiU7oAbcnIPNXkTBLeahgYjJMiU7oAbcnIPNXkTBLeahgYjJMiU7oAbcnIPNXkTBLeahgYjJMiU7oAbcnIPNXkTBLeahgYjJMiU7oAbcnIPNXkTBLeahgYjJMiU7oAbcnIPNXkTBLeahgYjJMiU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mkKDERLklO6AG3Jyh0peguBWU2gwQoKc0h1wQ07uUMlLENxqCg1GSJBTugNuyMkdKnkJgltNocEICXJKd8ANOblDJS9BcKspNBghQU7pDrghJ3eo5CUIbjWFBiMkyCndATfk5A6VvATBrabQYIQEOaU74Iac3KGSlyC41RQajJAgp3QH3JCTO1TyEgS3mkKDERLklO6AG3Jyh0peguBWU2gwQoKc0h1wQ07uUMlLENxqCg1GSJBTugNuyMkdKnkJgltNocEICXJKd8ANOblDJS9BcKspNBghQU7pDrghJ3eo5CUIbjWFBiMkyCndATfk5A6VvATBrabQYIQEOaU74Iac3KGSlyC41RQajJAgp3QH3JCTO1TyEgS3mkKDERLklO6AG3Jyh0peguBWU2gwQoKc0h1wQ07uUMlLENxqCg1GSJBTugNuyMkdKnkJgltNocEICXJKd8ANOblDJS9BcKspNBghQU7pDrghJ3eo5CUIbjWFBiMkyCndATfk5A6VvATBrabQYIQEOaU74Iac3KGSlyC41RQajJAgp3QH3JCTO1TyEgS3mkKDERLklO6AG3Jyh0peguBWU2gwQoKc0h1wQ07uUMlLENxqCg1GSJBTugNuyMkdKnkJgltNocEICXJKd8ANOblDJS9BcKspNBghQU7pDrghJ3eo5CUIbjWFBiMkyCndATfk5A6VvATBrabQYIQEOaU74Iac3KGSlyC41RQajJAgp3QH3JCTO1TyEgS3mkKDERLklO6AG3Jyh0peguBWU2gwQoKc0h1wQ07uUMlLENxqCg1GSJBTugNuyMkdKnkJgltNocEICXJKd8ANOblDJS9BcKspNBghQU7pDrghJ3eo5CUIbjWFBiMkyCndATfk5A6VvATBrabQYIQEOaU74Iac3KGSlyC41RQajJAgp3QH3JCTO1TyEgS3mkKDERLklO6AG3Jyh0peguBWU2gwQoKc0h1wQ07uUMlLENxqCg1GSJBTugNuyMkdKnkJgltNocEICXJKd8ANOblDJS9BcKspNBghQU7pDrghJ3eo5CUIbjWFBiMkyCndATfk5A6VvATBrabQYIQEOaU74Iac3KGSlyC41RQajJAgp3QH3JCTO1TyEgS3mkKDERLklO6AG3Jyh0peguBWU2gwQoKc0h1wQ07uUMlLENxqCg1GSJBTugNuyMkdKnkJgltN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vpGEVLuiBRWgFJMZ5hKKmeAbSUi1K1pQAUoxmWEuoZgJvpGEVLuiBRWgFJMZ5hKKmeAbSUi1K1pQAUoxmWEuoZgJvpGEVLuiBRWgFJMZ5hKKmeAbSUi1K1pQAUoxmWEuoZgJvpGEVLuiBRWgFJMZ5hKKmeAbSUi1K1pQAUoxmWEuoZgJvpGEVLuiBRWgFJMZ5hKKmeAbSUi1K1pQAUoxmWEuoZgJvpGEVLuiBRWgFJMZ5hKKmeAbSUi1K1pQAUoxmWEuoZgJvpGEVLuiBRWgFJMZ5hKKmeAbSUi1K1pQAUoxmWEuoZgJvpGEVLuiBRWgFJMZ5hKKmeAbSUi1K1pQAUoxmWEuoZgJvpGEVLuiBRWgFJMZ5hKKmeAbSUi1K1pQAUoxmWEuoZgJvpGEVLuiBRWgFJMZ5hKKmeAbSUi1K1pQAUoxmWEuoZgJvpGEVLuiBRWgFJMZ5hKKmeAbSUi1K1pQAUoxmWEuoZgJvpGEVLuiBRWgFJMZ5hKKmeAbSUi1K1pQAUoxmWEuoZgJvpGEVLuiBRWgFJMZ5hKKmeAbSUi1K1pQAUoxmWEuoZgJvpGEVLuiBRWgFJMZ5hKKmeAbSUi1K1pQAUoxmWEuoZgJvpGEVLuiBRWgFJMZ5hKKmeAbSUi1K1pQAUoxmWEuoZgJvpGEVLuiBRWgFJMZ5hKKmeAbSUi1K1pQAUoxmWEuoZgJvpGEVLuiBRWgFJMZ5hKKmeAbSUi1K1pQAUoxmWEuoZgJvpGEVLuiBRWgFJMZ5hKKmeAbSUi1K1pQAUoxmWEuoZgJvpGEVLuiBRWgFJMZ5hKKmeAbSUi1K1pQAUoxmWEuoZgJvpGEVLuiBRWgFJMZ5hKKmeAbSUi1K1pQAUoxmWEuoZgJvpGEVLuiBRWgFJMZ5hKKmeAbSUi1K1pQAUoxmWEuoZgJvpGEVLuiBRWgFJMZ5hKKmeAbSUi1K1pQAUoxmWEuoZgJvpGEVLuiBRWgFJMZ5hKKmeAbSUi1K1pQAUoxmWEuoZgJvpGEVLuiBRWgFJMZ5hKKmeAbSUi1K1pQAUoxmWEuoZgJvpGEVLuiBRWgFJMZ5hKKmeAbSUi1K1pQAUoxmWEuoZgJvpGEVLuiBRWgFJMZ5hKKmeAbSUi1K1pQAUoxmWEuoZgJvpGEVLuiBRWgFJMZ5hKKmeAbSUi1K1pQAUoxmWEuoZgJvpGEVLuiBRWg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\\\" >\\n\",\n        \"\\n\",\n        \"Please click in the **Connection details tab** and copy your connection parameters into the Python variables below\"\n      ],\n      \"metadata\": {\n        \"id\": \"3hCQBmBKVaHm\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"ttxf62TPVP-w\"\n      },\n      \"outputs\": [],\n      \"source\": [\n        \"neo4j_url = \\\"\\\" # put your neo4j url here\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"neo4j_user = \\\"neo4j\\\" # put your neo4j user here\"\n      ],\n      \"metadata\": {\n        \"id\": \"-lPr1hfIGtfL\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"neo4j_password = \\\"\\\" # put your neo4j password here\"\n      ],\n      \"metadata\": {\n        \"id\": \"yoI29jjvGvlX\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"### Configure the Spark Environment\"\n      ],\n      \"metadata\": {\n        \"id\": \"Capd99x5G2rm\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"spark_version = '3.3.4'\"\n      ],\n      \"metadata\": {\n        \"id\": \"OiHMiko1-Qf7\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"!apt-get install openjdk-17-jdk-headless -qq > /dev/null\"\n      ],\n      \"metadata\": {\n        \"id\": \"qdjzLBDzGx5l\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"!wget -q https://dlcdn.apache.org/spark/spark-$spark_version/spark-$spark_version-bin-hadoop3.tgz\"\n      ],\n      \"metadata\": {\n        \"id\": \"7JT9OKhzG7Lq\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"A3gsnSHl0F99\"\n      },\n      \"outputs\": [],\n      \"source\": [\n        \"!tar xf spark-$spark_version-bin-hadoop3.tgz\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"hSBQWKs90vSx\"\n      },\n      \"outputs\": [],\n      \"source\": [\n        \"!pip install -q findspark\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"tnW0a1Gj080k\"\n      },\n      \"outputs\": [],\n      \"source\": [\n        \"import os\\n\",\n        \"os.environ[\\\"JAVA_HOME\\\"] = \\\"/usr/lib/jvm/java-17-openjdk-amd64\\\"\\n\",\n        \"os.environ[\\\"SPARK_HOME\\\"] = f\\\"/content/spark-{spark_version}-bin-hadoop3\\\"\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"dlUBSezK1DpZ\"\n      },\n      \"outputs\": [],\n      \"source\": [\n        \"import findspark\\n\",\n        \"findspark.init()\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"dOUJ-W871Tur\"\n      },\n      \"outputs\": [],\n      \"source\": [\n        \"from pyspark.sql import SparkSession\\n\",\n        \"spark = (SparkSession.builder\\n\",\n        \"        .master('local[*]')\\n\",\n        \"        .appName('Data science workflow with Neo4j and Spark')\\n\",\n        \"        .config('spark.ui.port', '4050')\\n\",\n        \"        # Just to show dataframes as tables\\n\",\n        \"        #.config('spark.sql.repl.eagerEval.enabled', False)\\n\",\n        \"        .config('spark.jars.packages', 'org.neo4j:neo4j-connector-apache-spark_2.12:5.1.0_for_spark_3')\\n\",\n        \"        # As we're using always the same database instance we'll\\n\",\n        \"        # define them as global variables\\n\",\n        \"        # so we don't need to repeat them each time\\n\",\n        \"        .config(\\\"neo4j.url\\\", neo4j_url)\\n\",\n        \"        .config(\\\"neo4j.authentication.type\\\", \\\"basic\\\")\\n\",\n        \"        .config(\\\"neo4j.authentication.basic.username\\\", neo4j_user)\\n\",\n        \"        .config(\\\"neo4j.authentication.basic.password\\\", neo4j_password)\\n\",\n        \"        .getOrCreate())\\n\",\n        \"spark\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"# import utility functions that we'll use in the notebook\\n\",\n        \"from pyspark.sql.types import *\\n\",\n        \"from pyspark.sql.functions import *\"\n      ],\n      \"metadata\": {\n        \"id\": \"pghCcGnJWcZQ\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"## Import PySpark Pandas\\n\",\n        \"\\n\",\n        \"Pandas API on Apache Spark (PySpark) enables data scientists and data engineers to run their existing Pandas code on Spark. Prior to this API, you had to do a significant code rewrite from Pandas DataFrame to PySpark DataFrame which is time-consuming and error-prone.\\n\",\n        \"\\n\",\n        \"In this notebook we'll use both PySpark Dataframes and and PySpark Pandas.\\n\",\n        \"\\n\",\n        \"The only thing that we need to do is to import the library using the statement below.\"\n      ],\n      \"metadata\": {\n        \"id\": \"klQ2Ah6CFBV1\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"import pyspark.pandas as ps\"\n      ],\n      \"metadata\": {\n        \"id\": \"lDkBcHySCBT0\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"\\n\",\n        \"## Exercises prerequisite\\n\",\n        \"\\n\",\n        \"In this notebook we and going to test your knowledge. Some of the exercises require the Neo4j Python driver to check if the exercises are being solved correctly.\\n\",\n        \"\\n\",\n        \"*Neo4j Python Driver is required only for verifying the exercises when you persist data from Spark to Neo4j*\\n\",\n        \"\\n\",\n        \"**It's not required by the Spark connector!!!**\\n\",\n        \"\\n\",\n        \"We'll use [Cy2Py](https://github.com/conker84/cy2py), a Jupyter extension that easily allows you to connect to Neo4j and visualize data from Jupyter notebooks.\\n\",\n        \"For a detailed instruction about how to use it please dive into [this example](https://github.com/conker84/cy2py/blob/main/examples/Neo4j_Crime_Investigation_Dataset.ipynb)\"\n      ],\n      \"metadata\": {\n        \"id\": \"b6_YNZnZ5GdT\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"!pip install -q cy2py\"\n      ],\n      \"metadata\": {\n        \"id\": \"f5ZZJylo5Bbz\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"let's load the extension\"\n      ],\n      \"metadata\": {\n        \"id\": \"uKYEPEgOcG2b\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"%load_ext cy2py\"\n      ],\n      \"metadata\": {\n        \"id\": \"38EeXF6icKOK\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"You can query the database via **cy2py** in this simple way\"\n      ],\n      \"metadata\": {\n        \"id\": \"peqcEHj0b35T\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"# define the colors for the nodes\\n\",\n        \"colors = {\\n\",\n        \"  ':Client': '#D18711',\\n\",\n        \"  ':Bank': '#0541B2',\\n\",\n        \"  ':Merchant': '#9E14AA',\\n\",\n        \"  ':Mule': '#6113A3',\\n\",\n        \"  ':CashIn': '#328918',\\n\",\n        \"  ':CashOut': '#C1A23D',\\n\",\n        \"  ':Debit': '#A32727',\\n\",\n        \"  ':Payment': '#3B80C4',\\n\",\n        \"  ':Transfer': '#088472',\\n\",\n        \"  ':Transaction': '#D10B4F',\\n\",\n        \"  ':Email': '#EA5D1E',\\n\",\n        \"  ':SSN': '#707070',\\n\",\n        \"  ':Phone': '#4B4444',\\n\",\n        \"}\"\n      ],\n      \"metadata\": {\n        \"id\": \"dw2P-XpfLCJY\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"%%cypher -u $neo4j_url -us $neo4j_user -pw $neo4j_password -co $colors\\n\",\n        \"CALL apoc.meta.graph()\"\n      ],\n      \"metadata\": {\n        \"id\": \"BfFOTNkncMqp\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"# Problem Definition\\n\"\n      ],\n      \"metadata\": {\n        \"id\": \"d-x29ClTPBnv\"\n      }\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"## What is Fraud?\\n\",\n        \"Fraud occurs when an individual or group of individuals, or a business entity intentionally deceives another individual or business entity with misrepresentation of identity, products, services, or financial transactions and/or false promises with no intention of fulfilling them.\"\n      ],\n      \"metadata\": {\n        \"id\": \"79q5QJfcPMa6\"\n      }\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"## Fraud Categories\\n\"\n      ],\n      \"metadata\": {\n        \"id\": \"naUmXhC-PQGR\"\n      }\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"### First-party Fraud\\n\",\n        \"An individual, or group of individuals, misrepresent their identity or give false information when applying for a product or services to receive more favourable rates or when have no intention of repayment.\"\n      ],\n      \"metadata\": {\n        \"id\": \"edTfWFSAPUKF\"\n      }\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"### Second-party Fraud\\n\",\n        \"An individual knowingly gives their identity or personal information to another individual to commit fraud or someone is perpetrating fraud in his behalf.\"\n      ],\n      \"metadata\": {\n        \"id\": \"Zr9sGs_9PYmH\"\n      }\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"### Third-party Fraud\\n\",\n        \"An individual, or a group of individuals, create or use another person’s identity, or personal details, to open or takeover an account.\"\n      ],\n      \"metadata\": {\n        \"id\": \"o45K16ryPcBu\"\n      }\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"## The dataset\\n\",\n        \"\\n\",\n        \"We will use Paysim dataset for the hands-on exercises. Paysim is a synthetic dataset that mimics real world mobile money transfer network.\\n\",\n        \"\\n\",\n        \"For more information on the dataset, please visit this [blog page](https://www.sisu.io/posts/paysim/)\"\n      ],\n      \"metadata\": {\n        \"id\": \"dFje1N1cPq_9\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"%%cypher\\n\",\n        \"CALL apoc.meta.graph()\"\n      ],\n      \"metadata\": {\n        \"id\": \"AAeicV33PDXa\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"There are five types of transactions in this database. List all transaction types and corresponding metrics by iterating over all the transactions.\"\n      ],\n      \"metadata\": {\n        \"id\": \"Ux5tg_OzUvgT\"\n      }\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"#### Code in PySpark\"\n      ],\n      \"metadata\": {\n        \"id\": \"viWCvG1MU632\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"transaction_df = (spark.read\\n\",\n        \"        .format('org.neo4j.spark.DataSource')\\n\",\n        \"        .option('labels', ':Transaction')\\n\",\n        \"        .load())\\n\",\n        \"\\n\",\n        \"transaction_df_count = transaction_df.count()\\n\",\n        \"\\n\",\n        \"transaction_df = (transaction_df.groupBy('<labels>')\\n\",\n        \"  .count()\\n\",\n        \"  .withColumnRenamed('<labels>', 'transaction'))\\n\",\n        \"\\n\",\n        \"transaction_df = (transaction_df\\n\",\n        \"      .withColumn('transaction', transaction_df['transaction'].getItem(0))\\n\",\n        \"      .withColumn('% transactions', transaction_df['count'] / transaction_df_count))\\n\",\n        \"\\n\",\n        \"transaction_df.show(truncate=False)\"\n      ],\n      \"metadata\": {\n        \"id\": \"xsIlmR-EQLeb\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"#### Code in PySpark Pandas\"\n      ],\n      \"metadata\": {\n        \"id\": \"U2JUpe4NU6Jz\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"transaction_ps = ps.read_spark_io(format=\\\"org.neo4j.spark.DataSource\\\", options={\\\"labels\\\": \\\"Transaction\\\"})\\n\",\n        \"\\n\",\n        \"transaction_ps_count = transaction_ps.count()[0] * 1.0\\n\",\n        \"\\n\",\n        \"transaction_ps = (transaction_ps.groupby(['<labels>'])\\n\",\n        \"                  .size()\\n\",\n        \"                  .reset_index(name='% transactions'))\\n\",\n        \"\\n\",\n        \"transaction_ps = transaction_ps.rename(columns={'<labels>': 'label'})\\n\",\n        \"\\n\",\n        \"transaction_ps['% transactions'] = transaction_ps['% transactions'].astype(float).div(transaction_ps_count * 1.0)\\n\",\n        \"\\n\",\n        \"transaction_ps.label = [x[0] for x in transaction_ps.label.to_numpy()]\\n\",\n        \"\\n\",\n        \"transaction_ps\"\n      ],\n      \"metadata\": {\n        \"id\": \"rfkeCU0PVFXx\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"##### Plot the data\\n\",\n        \"You can also use Python libraries like [Ploty](https://plotly.com/python/) to plot results\"\n      ],\n      \"metadata\": {\n        \"id\": \"t2RufDichKkQ\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"import plotly.express as px\\n\",\n        \"\\n\",\n        \"# we use to_pandas() in order to transform the PySpark Pandas to a real Pandas Dataframe\\n\",\n        \"fig = px.pie(transaction_ps.to_pandas(), values='% transactions', names='label')\\n\",\n        \"\\n\",\n        \"fig.show()\"\n      ],\n      \"metadata\": {\n        \"id\": \"Wn4HMYGVhV1t\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"# Exploit first-party Fraud\\n\",\n        \"\\n\",\n        \"Synthetic identity fraud and first party fraud can be identified by performing entity link analysis to detect identities linked to other identities via shared PII.\\n\",\n        \"\\n\",\n        \"There are three types of personally identifiable information (PII) in this dataset - SSN, Email and Phone Number\\n\",\n        \"\\n\",\n        \"Our hypothesis is that clients who share identifiers are suspicious and have a higher potential to commit fraud. However, all shared identifier links are not suspicious, for example, two people sharing an email address. Hence, we compute a fraud score based on shared PII relationships and label the top X percentile clients as fraudsters.\\n\",\n        \"\\n\",\n        \"We will first identify clients that share identifiers and create a new relationship between clients that share identifiers\"\n      ],\n      \"metadata\": {\n        \"id\": \"VwPKEtu2QLlv\"\n      }\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"## Enrich the dataset\"\n      ],\n      \"metadata\": {\n        \"id\": \"E162NudWkW2n\"\n      }\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"In order to perfrorm our investigation we want to enrich the base dataset by identifing clients that share PII.\"\n      ],\n      \"metadata\": {\n        \"id\": \"Y3MfFaKqH7Lm\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"%%cypher\\n\",\n        \"MATCH (c1:Client)-[:HAS_EMAIL|:HAS_PHONE|:HAS_SSN]->(n)<-[:HAS_EMAIL|:HAS_PHONE|:HAS_SSN]-(c2:Client)\\n\",\n        \"WHERE id(c1) < id(c2)\\n\",\n        \"RETURN c1.id, c2.id, count(*) AS freq\\n\",\n        \"ORDER BY freq DESC;\"\n      ],\n      \"metadata\": {\n        \"id\": \"zJfRBlNNP9A1\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"Now we can reuse the same Cypher query for creating our Dataframe and then use the Neo4j Spark Connector to create a new `SHARED_IDENTIFIERS` relationship betwen two clients:\\n\",\n        \"\\n\",\n        \"**(:Client)-[:SHARED_IDENTIFIERS]->(:Client)**\\n\",\n        \"\\n\"\n      ],\n      \"metadata\": {\n        \"id\": \"4J6d8U8bkMW_\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"%%cypher\\n\",\n        \"// let's check if there relationships are in there\\n\",\n        \"MATCH (c:Client)-[r:SHARED_IDENTIFIERS]->(c2:Client)\\n\",\n        \"RETURN *\\n\",\n        \"LIMIT 10\"\n      ],\n      \"metadata\": {\n        \"id\": \"sQ7Nf_IUQQ1J\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"As you can see there are no relationships in the database\"\n      ],\n      \"metadata\": {\n        \"id\": \"6zUwaYxgQhbC\"\n      }\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"### Code in PySpark\"\n      ],\n      \"metadata\": {\n        \"id\": \"7CAiMFJ3LPmP\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"shared_identifiers_df = (spark.read.format(\\\"org.neo4j.spark.DataSource\\\")\\n\",\n        \"  .option(\\\"query\\\", \\\"\\\"\\\"\\n\",\n        \"    MATCH (c1:Client)-[:HAS_EMAIL|:HAS_PHONE|:HAS_SSN]->(n)<-[:HAS_EMAIL|:HAS_PHONE|:HAS_SSN]-(c2:Client)\\n\",\n        \"    WHERE id(c1) < id(c2)\\n\",\n        \"    RETURN c1.id AS source, c2.id AS target, count(*) AS freq\\n\",\n        \"  \\\"\\\"\\\")\\n\",\n        \"  .load())\\n\",\n        \"\\n\",\n        \"(shared_identifiers_df.write\\n\",\n        \"  .format(\\\"org.neo4j.spark.DataSource\\\")\\n\",\n        \"  .mode(\\\"Overwrite\\\")\\n\",\n        \"  .option(\\\"relationship\\\", \\\"SHARED_IDENTIFIERS\\\")\\n\",\n        \"  .option(\\\"relationship.save.strategy\\\", \\\"keys\\\")\\n\",\n        \"  .option(\\\"relationship.source.labels\\\", \\\":Client\\\")\\n\",\n        \"  .option(\\\"relationship.source.save.mode\\\", \\\"Overwrite\\\")\\n\",\n        \"  .option(\\\"relationship.source.node.keys\\\", \\\"source:id\\\")\\n\",\n        \"  .option(\\\"relationship.target.labels\\\", \\\":Client\\\")\\n\",\n        \"  .option(\\\"relationship.target.node.keys\\\", \\\"target:id\\\")\\n\",\n        \"  .option(\\\"relationship.target.save.mode\\\", \\\"Overwrite\\\")\\n\",\n        \"  .option(\\\"relationship.properties\\\", \\\"freq:count\\\")\\n\",\n        \"  .save())\"\n      ],\n      \"metadata\": {\n        \"id\": \"36irb2nuj5Hi\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"### Code in PySpark Pandas\"\n      ],\n      \"metadata\": {\n        \"id\": \"h07CRHnlLU-G\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"shared_identifiers_ps = ps.read_spark_io(format=\\\"org.neo4j.spark.DataSource\\\", options={\\\"query\\\": \\\"\\\"\\\"\\n\",\n        \"  MATCH (c1:Client)-[:HAS_EMAIL|:HAS_PHONE|:HAS_SSN]->(n)<-[:HAS_EMAIL|:HAS_PHONE|:HAS_SSN]-(c2:Client)\\n\",\n        \"  WHERE id(c1) < id(c2)\\n\",\n        \"  RETURN c1.id AS source, c2.id AS target, count(*) AS freq\\n\",\n        \"\\\"\\\"\\\"})\\n\",\n        \"\\n\",\n        \"shared_identifiers_ps.spark.to_spark_io(format=\\\"org.neo4j.spark.DataSource\\\", mode=\\\"Overwrite\\\", options={\\n\",\n        \"    \\\"relationship\\\": \\\"SHARED_IDENTIFIERS\\\",\\n\",\n        \"    \\\"relationship.save.strategy\\\": \\\"keys\\\",\\n\",\n        \"    \\\"relationship.source.labels\\\": \\\":Client\\\",\\n\",\n        \"    \\\"relationship.source.save.mode\\\": \\\"Overwrite\\\",\\n\",\n        \"    \\\"relationship.source.node.keys\\\": \\\"source:id\\\",\\n\",\n        \"    \\\"relationship.target.labels\\\": \\\":Client\\\",\\n\",\n        \"    \\\"relationship.target.node.keys\\\": \\\"target:id\\\",\\n\",\n        \"    \\\"relationship.target.save.mode\\\": \\\"Overwrite\\\",\\n\",\n        \"    \\\"relationship.properties\\\": \\\"freq:count\\\"\\n\",\n        \"})\"\n      ],\n      \"metadata\": {\n        \"id\": \"vZ6So9x_MBY_\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"%%cypher\\n\",\n        \"// let's check (again) if there relationships are in there\\n\",\n        \"MATCH (c:Client)-[r:SHARED_IDENTIFIERS]->(c2:Client)\\n\",\n        \"RETURN *\\n\",\n        \"LIMIT 10\"\n      ],\n      \"metadata\": {\n        \"id\": \"A6iUPMYMQAzF\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"## Build Fraud detection workflow in Neo4j GDS\\n\",\n        \"\\n\",\n        \"We will construct a workflow with graph algorithms to detect fraud rings, score clients based on the number of common connections and rank them to select the top few suspicious clients and label them as fraudsters.\\n\",\n        \"\\n\",\n        \"1. Identify clusters of clients sharing PII using a community detection algorithm (Weakly Connected Components)\\n\",\n        \"2. Find similar clients within the clusters using pairwise similarity algorithms (Node Similarity)\\n\",\n        \"3. Calculate and assign fraud score to clients using centrality algorithms (Degree Centrality)\\n\",\n        \"4. Use computed fraud scores to label clients as potential fraudsters\"\n      ],\n      \"metadata\": {\n        \"id\": \"Fy8roSDHQw3h\"\n      }\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"## Identify groups of clients sharing PII (Fraud rings)\\n\",\n        \"\\n\",\n        \"Run Weakly connected components to find clusters of clients sharing PII.\\n\",\n        \"\\n\",\n        \"Weakly Connected Components is used to find groups of connected nodes, where all nodes in the same set form a connected component. WCC is often used early in an analysis understand the structure of a graph. More informaton here: [WCC documentation](https://neo4j.com/docs/graph-data-science/current/algorithms/wcc/)\"\n      ],\n      \"metadata\": {\n        \"id\": \"bysMYQ23WFVl\"\n      }\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"### Create a graph projection\\n\",\n        \"\\n\",\n        \"A central concept in the GDS library is the management of in-memory graphs. Graph algorithms run on a graph data model which is a projection of the Neo4j property graph data model. For more information, please click here: [Graph Management](https://neo4j.com/docs/graph-data-science/current/management-ops/)\\n\",\n        \"\\n\",\n        \"A projected graph can be stored in the catalog under a user-defined name. Using that name, the graph can be referred to by any algorithm in the library.\"\n      ],\n      \"metadata\": {\n        \"id\": \"39g6Fq1dTgLt\"\n      }\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"Consider that the original Cypher query is the following:\\n\",\n        \"```cypher\\n\",\n        \"CALL gds.graph.project('wcc',\\n\",\n        \"    {\\n\",\n        \"        Client: {\\n\",\n        \"            label: 'Client'\\n\",\n        \"        }\\n\",\n        \"    },\\n\",\n        \"    {\\n\",\n        \"        SHARED_IDENTIFIERS:{\\n\",\n        \"            type: 'SHARED_IDENTIFIERS',\\n\",\n        \"            orientation: 'UNDIRECTED',\\n\",\n        \"            properties: {\\n\",\n        \"                count: {\\n\",\n        \"                    property: 'count'\\n\",\n        \"                }\\n\",\n        \"            }\\n\",\n        \"        }\\n\",\n        \"    }\\n\",\n        \") YIELD graphName,nodeCount,relationshipCount,projectMillis;\\n\",\n        \"```\\n\",\n        \"\\n\",\n        \"which will be translate into:\"\n      ],\n      \"metadata\": {\n        \"id\": \"fXQwdpJfVGIq\"\n      }\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"#### Code in PySpark\"\n      ],\n      \"metadata\": {\n        \"id\": \"-fkvDjHcUV5Z\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"wcc_graph_proj_df = (spark.read.format(\\\"org.neo4j.spark.DataSource\\\")\\n\",\n        \"  .option(\\\"gds\\\", \\\"gds.graph.project\\\")\\n\",\n        \"  .option(\\\"gds.graphName\\\", \\\"wcc\\\")\\n\",\n        \"  .option(\\\"gds.nodeProjection.Client.label\\\", \\\"Client\\\")\\n\",\n        \"  .option(\\\"gds.relationshipProjection.SHARED_IDENTIFIERS.type\\\", \\\"SHARED_IDENTIFIERS\\\")\\n\",\n        \"  .option(\\\"gds.relationshipProjection.SHARED_IDENTIFIERS.orientation\\\", \\\"UNDIRECTED\\\")\\n\",\n        \"  .option(\\\"gds.relationshipProjection.SHARED_IDENTIFIERS.properties.count.property\\\", \\\"count\\\")\\n\",\n        \"  .load())\\n\",\n        \"\\n\",\n        \"wcc_graph_proj_df.show(truncate=False)\"\n      ],\n      \"metadata\": {\n        \"id\": \"4dBHWHh8R7US\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"#### Code in PySpark Pandas\"\n      ],\n      \"metadata\": {\n        \"id\": \"cauhX4FRVYMy\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"wcc_graph_proj_ps = ps.read_spark_io(format=\\\"org.neo4j.spark.DataSource\\\", options={\\n\",\n        \"  \\\"gds\\\": \\\"gds.graph.project\\\",\\n\",\n        \"  \\\"gds.graphName\\\": \\\"wcc\\\",\\n\",\n        \"  \\\"gds.nodeProjection.Client.label\\\": \\\"Client\\\",\\n\",\n        \"  \\\"gds.relationshipProjection.SHARED_IDENTIFIERS.type\\\": \\\"SHARED_IDENTIFIERS\\\",\\n\",\n        \"  \\\"gds.relationshipProjection.SHARED_IDENTIFIERS.orientation\\\": \\\"UNDIRECTED\\\",\\n\",\n        \"  \\\"gds.relationshipProjection.SHARED_IDENTIFIERS.properties.count.property\\\": \\\"count\\\"\\n\",\n        \"})\\n\",\n        \"\\n\",\n        \"wcc_graph_proj_ps\"\n      ],\n      \"metadata\": {\n        \"id\": \"ZndBGbXPVeqU\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"### Run the WCC algorithm\\n\",\n        \"\\n\",\n        \"The original Cypher query is:\\n\",\n        \"\\n\",\n        \"```cypher\\n\",\n        \"CALL gds.wcc.stream('wcc',\\n\",\n        \"    {\\n\",\n        \"        nodeLabels: ['Client'],\\n\",\n        \"        relationshipTypes: ['SHARED_IDENTIFIERS'],\\n\",\n        \"        consecutiveIds: true\\n\",\n        \"    }\\n\",\n        \")\\n\",\n        \"YIELD nodeId, componentId\\n\",\n        \"RETURN gds.util.asNode(nodeId).id AS clientId, componentId\\n\",\n        \"ORDER BY componentId\\n\",\n        \"LIMIT 20\\n\",\n        \"```\\n\",\n        \"\\n\",\n        \"which is transate into:\"\n      ],\n      \"metadata\": {\n        \"id\": \"P4oIKsUNn-ZH\"\n      }\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"#### Code in PySpark\"\n      ],\n      \"metadata\": {\n        \"id\": \"Ygw7T3lSWbsQ\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"# get the clients\\n\",\n        \"clients_df = (spark.read.format(\\\"org.neo4j.spark.DataSource\\\")\\n\",\n        \"  .option(\\\"labels\\\", \\\"Client\\\")\\n\",\n        \"  .load())\\n\",\n        \"\\n\",\n        \"# invoke the gds wcc stream procedure\\n\",\n        \"wcc_df = (spark.read.format(\\\"org.neo4j.spark.DataSource\\\")\\n\",\n        \"  .option(\\\"gds\\\", \\\"gds.wcc.stream\\\")\\n\",\n        \"  .option(\\\"gds.graphName\\\", \\\"wcc\\\")\\n\",\n        \"  .option(\\\"gds.nodeLabels\\\", \\\"['Client']\\\")\\n\",\n        \"  .option(\\\"gds.relationshipTypes\\\", \\\"['SHARED_IDENTIFIERS']\\\")\\n\",\n        \"  .option(\\\"gds.consecutiveIds\\\", \\\"true\\\")\\n\",\n        \"  .load())\\n\",\n        \"\\n\",\n        \"# join the two dataframes and show id, componentId\\n\",\n        \"client_component_df = (clients_df.join(wcc_df, clients_df[\\\"<id>\\\"] == wcc_df[\\\"nodeId\\\"], \\\"inner\\\")\\n\",\n        \"  .select(\\\"id\\\", \\\"componentId\\\"))\\n\",\n        \"\\n\",\n        \"client_component_df.show(truncate=False)\"\n      ],\n      \"metadata\": {\n        \"id\": \"6RtkJV9GWHnu\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"#### Code in PySpark Pandas\"\n      ],\n      \"metadata\": {\n        \"id\": \"xQI9gQNQYMWe\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"# get the clients\\n\",\n        \"clients_ps = ps.read_spark_io(format=\\\"org.neo4j.spark.DataSource\\\", options={\\\"labels\\\": \\\"Client\\\"})\\n\",\n        \"\\n\",\n        \"# invoke the gds wcc stream procedure\\n\",\n        \"wcc_ps = ps.read_spark_io(format=\\\"org.neo4j.spark.DataSource\\\", options={\\n\",\n        \"  \\\"gds\\\": \\\"gds.wcc.stream\\\",\\n\",\n        \"  \\\"gds.graphName\\\": \\\"wcc\\\",\\n\",\n        \"  \\\"gds.nodeLabels\\\": \\\"['Client']\\\",\\n\",\n        \"  \\\"gds.relationshipTypes\\\": \\\"['SHARED_IDENTIFIERS']\\\",\\n\",\n        \"  \\\"gds.consecutiveIds\\\": \\\"true\\\"\\n\",\n        \"})\\n\",\n        \"\\n\",\n        \"# join the two pandas df and show id, componentId\\n\",\n        \"client_component_ps = clients_ps.join(wcc_ps.set_index(\\\"nodeId\\\"), on=\\\"<id>\\\")[[\\\"id\\\", \\\"componentId\\\"]]\\n\",\n        \"\\n\",\n        \"# we show only the first 20\\n\",\n        \"client_component_ps[:20]\"\n      ],\n      \"metadata\": {\n        \"id\": \"AvlUnpIQYQsZ\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"### Write results to the database.\\n\",\n        \"Now that we identified clusters of clients sharing PII, we want to store these results back into the database by enriching the `Client` node.\\n\",\n        \"We'll add the component id of the cluster as `firstPartyFraudGroup` property\"\n      ],\n      \"metadata\": {\n        \"id\": \"eNgmAuheZqfA\"\n      }\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"#### Code in PySpark\"\n      ],\n      \"metadata\": {\n        \"id\": \"EKNcuklDaRKY\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"(client_component_df\\n\",\n        \"  .withColumnRenamed(\\\"componentId\\\", \\\"firstPartyFraudGroup\\\")\\n\",\n        \"  .write\\n\",\n        \"  .format(\\\"org.neo4j.spark.DataSource\\\")\\n\",\n        \"  .mode(\\\"Overwrite\\\")\\n\",\n        \"  .option(\\\"labels\\\", \\\"Client\\\")\\n\",\n        \"  .option(\\\"node.keys\\\", \\\"id\\\")\\n\",\n        \"  .save())\"\n      ],\n      \"metadata\": {\n        \"id\": \"yQb0H-p7ZrRP\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"#### Code in PySpark Pandas\"\n      ],\n      \"metadata\": {\n        \"id\": \"-HK28CGoa5_p\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"(client_component_ps\\n\",\n        \"  .rename(columns={\\\"componentId\\\": \\\"firstPartyFraudGroup\\\"})\\n\",\n        \"  .spark\\n\",\n        \"  .to_spark_io(format=\\\"org.neo4j.spark.DataSource\\\", mode=\\\"Overwrite\\\", options={\\n\",\n        \"      \\\"labels\\\": \\\"Client\\\",\\n\",\n        \"      \\\"node.keys\\\": \\\"id\\\"\\n\",\n        \"  }))\"\n      ],\n      \"metadata\": {\n        \"id\": \"zJDS-0bta8_s\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"%%cypher\\n\",\n        \"// Visualize clusters with greater than 9 client nodes.\\n\",\n        \"MATCH (c:Client)\\n\",\n        \"WITH c.firstPartyFraudGroup AS fpGroupID, collect(c.id) AS fGroup\\n\",\n        \"WITH *, size(fGroup) AS groupSize WHERE groupSize >= 9\\n\",\n        \"WITH * LIMIT 1\\n\",\n        \"MATCH p=(c:Client)-[:HAS_SSN|HAS_EMAIL|HAS_PHONE]->()\\n\",\n        \"WHERE c.firstPartyFraudGroup = fpGroupID\\n\",\n        \"RETURN p\"\n      ],\n      \"metadata\": {\n        \"id\": \"oOsrNUZocx21\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"## Compute pairwise similarity scores\\n\",\n        \"\\n\",\n        \"We use node similarity algorithm to find similar nodes based on the relationships to other nodes. Node similarity uses Jaccard metric ([Node Similarity](https://neo4j.com/docs/graph-data-science/current/algorithms/node-similarity/#algorithms-node-similarity))\\n\",\n        \"\\n\",\n        \"Node similarity algorithms work on bipartite graphs (two types of nodes and relationships between them). Here we project client nodes (one type) and three identifiers nodes (that are considered as second type) into memory.\"\n      ],\n      \"metadata\": {\n        \"id\": \"5CCwYp1FfoMU\"\n      }\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"### Project the graph\\n\",\n        \"\\n\",\n        \"The original Cypher query is\\n\",\n        \"\\n\",\n        \"```cypher\\n\",\n        \"MATCH(c:Client) WHERE c.firstPartyFraudGroup is not NULL\\n\",\n        \"WITH collect(c) as clients\\n\",\n        \"MATCH(n) WHERE n:Email OR n:Phone OR n:SSN\\n\",\n        \"WITH clients, collect(n) as identifiers\\n\",\n        \"WITH clients + identifiers as nodes\\n\",\n        \"\\n\",\n        \"MATCH(c:Client) -[:HAS_EMAIL|:HAS_PHONE|:HAS_SSN]->(id)\\n\",\n        \"WHERE c.firstPartyFraudGroup is not NULL\\n\",\n        \"WITH nodes, collect({source: c, target: id}) as relationships\\n\",\n        \"\\n\",\n        \"CALL gds.graph.project.cypher('similarity',\\n\",\n        \"    \\\"UNWIND $nodes as n RETURN id(n) AS id,labels(n) AS labels\\\",\\n\",\n        \"    \\\"UNWIND $relationships as r RETURN id(r['source']) AS source, id(r['target']) AS target, 'HAS_IDENTIFIER' as type\\\",\\n\",\n        \"    { parameters: {nodes: nodes, relationships: relationships}}\\n\",\n        \")\\n\",\n        \"YIELD graphName, nodeCount, relationshipCount, projectMillis\\n\",\n        \"RETURN graphName, nodeCount, relationshipCount, projectMillis\\n\",\n        \"```\\n\",\n        \"\\n\",\n        \"Which is translated into\"\n      ],\n      \"metadata\": {\n        \"id\": \"aLGQxFtpnQHa\"\n      }\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"#### Code in PySpark\"\n      ],\n      \"metadata\": {\n        \"id\": \"aPSY4htNgLVG\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"similarity_graph_proj_df = (spark.read.format(\\\"org.neo4j.spark.DataSource\\\")\\n\",\n        \"  .option(\\\"gds\\\", \\\"gds.graph.project.cypher\\\")\\n\",\n        \"  .option(\\\"gds.graphName\\\", \\\"similarity\\\")\\n\",\n        \"  .option(\\\"gds.nodeQuery\\\", \\\"\\\"\\\"\\n\",\n        \"    MATCH (n)\\n\",\n        \"    WHERE (n:Client AND n.firstPartyFraudGroup is not NULL) OR n:Email OR n:Phone OR n:SSN\\n\",\n        \"    RETURN id(n) AS id, labels(n) AS labels\\n\",\n        \"  \\\"\\\"\\\")\\n\",\n        \"  .option(\\\"gds.relationshipQuery\\\", \\\"\\\"\\\"\\n\",\n        \"    MATCH (s:Client)-[:HAS_EMAIL|:HAS_PHONE|:HAS_SSN]->(t)\\n\",\n        \"    WHERE s.firstPartyFraudGroup is not NULL\\n\",\n        \"    RETURN id(s) AS source, id(t) AS target, 'HAS_IDENTIFIER' as type\\n\",\n        \"  \\\"\\\"\\\")\\n\",\n        \"  .load())\\n\",\n        \"\\n\",\n        \"similarity_graph_proj_df.show(truncate=False)\"\n      ],\n      \"metadata\": {\n        \"id\": \"eNvVkJTRfuqM\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"#### Code in PySpark Pandas\"\n      ],\n      \"metadata\": {\n        \"id\": \"PcJCKDDhmbtr\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"similarity_graph_proj_ps = ps.read_spark_io(format=\\\"org.neo4j.spark.DataSource\\\", options={\\n\",\n        \"  \\\"gds\\\": \\\"gds.graph.project.cypher\\\",\\n\",\n        \"  \\\"gds.graphName\\\": \\\"similarity\\\",\\n\",\n        \"  \\\"gds.nodeQuery\\\": \\\"\\\"\\\"\\n\",\n        \"    MATCH (n)\\n\",\n        \"    WHERE (n:Client AND n.firstPartyFraudGroup is not NULL) OR n:Email OR n:Phone OR n:SSN\\n\",\n        \"    RETURN id(n) AS id, labels(n) AS labels\\n\",\n        \"  \\\"\\\"\\\",\\n\",\n        \"  \\\"gds.relationshipQuery\\\": \\\"\\\"\\\"\\n\",\n        \"    MATCH (s:Client)-[:HAS_EMAIL|:HAS_PHONE|:HAS_SSN]->(t)\\n\",\n        \"    WHERE s.firstPartyFraudGroup is not NULL\\n\",\n        \"    RETURN id(s) AS source, id(t) AS target, 'HAS_IDENTIFIER' as type\\n\",\n        \"  \\\"\\\"\\\"\\n\",\n        \"})\\n\",\n        \"\\n\",\n        \"similarity_graph_proj_ps\"\n      ],\n      \"metadata\": {\n        \"id\": \"odriamHwmiEQ\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"### Compute the node similarity\\n\",\n        \"\\n\",\n        \"We can mutate in-memory graph by writing outputs from the algorithm as node or relationship properties.\\n\",\n        \"\\n\",\n        \"In this particular case all the procedures with `mutate` and `write` suffix are not supported from the Neo4j Spark Connector, in this case we'll write a Cypher query:\\n\"\n      ],\n      \"metadata\": {\n        \"id\": \"TfnVREvvmzG4\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"%%cypher\\n\",\n        \"CALL gds.nodeSimilarity.mutate('similarity',\\n\",\n        \"    {\\n\",\n        \"        topK:15,\\n\",\n        \"        mutateProperty: 'jaccardScore',\\n\",\n        \"        mutateRelationshipType:'SIMILAR_TO'\\n\",\n        \"    }\\n\",\n        \");\"\n      ],\n      \"metadata\": {\n        \"id\": \"E0_WoCLlnIr6\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"Mutate mode is very fast compared to write mode and it helps in optimizing algorithm execution times, then we write back the property from in-memory graph to the database and use it for further analysis:\"\n      ],\n      \"metadata\": {\n        \"id\": \"JnC3C7urPyN_\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"%%cypher\\n\",\n        \"CALL gds.graph.writeRelationship('similarity', 'SIMILAR_TO', 'jaccardScore');\"\n      ],\n      \"metadata\": {\n        \"id\": \"xajV8enLPvIN\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"## Exercise: Calculate First-party Fraud Score\\n\",\n        \"\\n\",\n        \"We compute first party fraud score using weighted degree centrality algorithm.\\n\",\n        \"\\n\",\n        \"In this step, we compute and assign fraud score (`firstPartyFraudScore`) to clients in the clusters identified in previous steps based on `SIMILAR_TO` relationships weighted by `jaccardScore`\\n\",\n        \"\\n\",\n        \"Weighted degree centrality algorithm add up similarity scores (`jaccardScore`) on the incoming `SIMILAR_TO` relationships for a given node in a cluster and assign the sum as the corresponding `firstPartyFraudScore`. This score represents clients who are similar to many others in the cluster in terms of sharing identifiers. Higher `firstPartyFraudScore` represents greater potential for committing fraud.\"\n      ],\n      \"metadata\": {\n        \"id\": \"qpXXoWeIQk9U\"\n      }\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"### Code in PySpark\"\n      ],\n      \"metadata\": {\n        \"id\": \"fAp_acV-RBOu\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"# invoke the gds.degree.stream procedure\"\n      ],\n      \"metadata\": {\n        \"id\": \"ZPAHXvT6Qouy\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"<details>\\n\",\n        \"<summary>\\n\",\n        \"Show a possible solution\\n\",\n        \"</summary>\\n\",\n        \"\\n\",\n        \"```python\\n\",\n        \"similarity_df = (spark.read.format(\\\"org.neo4j.spark.DataSource\\\")\\n\",\n        \"  .option(\\\"gds\\\", \\\"gds.degree.stream\\\")\\n\",\n        \"  .option(\\\"gds.graphName\\\", \\\"similarity\\\")\\n\",\n        \"  .option(\\\"gds.nodeLabels\\\", \\\"['Client']\\\")\\n\",\n        \"  .option(\\\"gds.relationshipTypes\\\", \\\"['SIMILAR_TO']\\\")\\n\",\n        \"  .option(\\\"gds.relationshipWeightProperty\\\", \\\"jaccardScore\\\")\\n\",\n        \"  .load())\\n\",\n        \"\\n\",\n        \"# join the two dataframes and show id, score\\n\",\n        \"client_similarity_df = (clients_df.join(similarity_df, clients_df[\\\"<id>\\\"] == similarity_df[\\\"nodeId\\\"], \\\"inner\\\")\\n\",\n        \"  .select(\\\"id\\\", \\\"score\\\")\\n\",\n        \"  .withColumnRenamed(\\\"score\\\", \\\"firstPartyFraudScore\\\"))\\n\",\n        \"\\n\",\n        \"# write the results back to the database\\n\",\n        \"(client_similarity_df.write.format('org.neo4j.spark.DataSource')\\n\",\n        \"  .mode(\\\"Overwrite\\\")\\n\",\n        \"  .option(\\\"labels\\\", \\\"Client\\\")\\n\",\n        \"  .option(\\\"node.keys\\\", \\\"id\\\")\\n\",\n        \"  .save())\\n\",\n        \"```\\n\",\n        \"\\n\",\n        \"</details>\"\n      ],\n      \"metadata\": {\n        \"id\": \"1qKbMW3FSwLE\"\n      }\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"### Code in PySpark Pandas\\n\",\n        \"\\n\"\n      ],\n      \"metadata\": {\n        \"id\": \"na2h6VLov-ZA\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"# invoke the gds.degree.stream procedure\"\n      ],\n      \"metadata\": {\n        \"id\": \"7ObUlkdmwDzi\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"<details>\\n\",\n        \"<summary>\\n\",\n        \"Show a possible solution\\n\",\n        \"</summary>\\n\",\n        \"\\n\",\n        \"```python\\n\",\n        \"similarity_ps = ps.read_spark_io(format=\\\"org.neo4j.spark.DataSource\\\", options={\\n\",\n        \"  \\\"gds\\\": \\\"gds.degree.stream\\\",\\n\",\n        \"  \\\"gds.graphName\\\": \\\"similarity\\\",\\n\",\n        \"  \\\"gds.nodeLabels\\\": \\\"['Client']\\\",\\n\",\n        \"  \\\"gds.relationshipTypes\\\": \\\"['SIMILAR_TO']\\\",\\n\",\n        \"  \\\"gds.relationshipWeightProperty\\\": \\\"jaccardScore\\\"\\n\",\n        \"})\\n\",\n        \"\\n\",\n        \"# join the two pandas df and show id, score\\n\",\n        \"client_similarity_ps = (clients_ps.join(similarity_ps.set_index(\\\"nodeId\\\"), on=\\\"<id>\\\")[[\\\"id\\\", \\\"score\\\"]]\\n\",\n        \"                        .rename(columns={\\\"score\\\": \\\"firstPartyFraudScore\\\"}))\\n\",\n        \"\\n\",\n        \"# write the results back to the database\\n\",\n        \"client_similarity_ps.spark.to_spark_io(format=\\\"org.neo4j.spark.DataSource\\\", mode=\\\"Overwrite\\\", options={\\n\",\n        \"    \\\"labels\\\": \\\"Client\\\",\\n\",\n        \"    \\\"node.keys\\\": \\\"id\\\"\\n\",\n        \"})\\n\",\n        \"```\\n\",\n        \"\\n\",\n        \"</details>\"\n      ],\n      \"metadata\": {\n        \"id\": \"m8Cy4NtsS3nQ\"\n      }\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"### Verifiy the result\\n\",\n        \"\\n\",\n        \"We expect that:\\n\",\n        \"- `similarity_df`/`similarity_ps`\\n\",\n        \" - has two columns:\\n\",\n        \"   - `nodeId` of long type\\n\",\n        \"   - `score` of double type\\n\",\n        \" - a count of **9134** rows\\n\",\n        \"- `client_similarity_df`/`client_similarity_ps`\\n\",\n        \" - has two columns:\\n\",\n        \"   - `id` of long type\\n\",\n        \"   - `score` of double type\\n\",\n        \" - a count of 2433 rows\"\n      ],\n      \"metadata\": {\n        \"id\": \"I_TKq9TmU3cS\"\n      }\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"#### Test PySpark Dataframe\"\n      ],\n      \"metadata\": {\n        \"id\": \"Dow9PWAtxBPu\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"assert StructType([StructField(\\\"nodeId\\\", LongType()), StructField(\\\"score\\\", DoubleType())]) == similarity_df.schema\\n\",\n        \"assert 9134 == similarity_df.count()\\n\",\n        \"\\n\",\n        \"assert StructType([StructField(\\\"id\\\", StringType()), StructField(\\\"firstPartyFraudScore\\\", DoubleType())]) == client_similarity_df.schema\\n\",\n        \"assert 2433 == client_similarity_df.count()\\n\",\n        \"print(\\\"All assertion are successfuly satisfied.\\\")\"\n      ],\n      \"metadata\": {\n        \"id\": \"5E6fUHwZU7PN\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"#### Test PySpark Pandas\"\n      ],\n      \"metadata\": {\n        \"id\": \"feuIfTCqxGKt\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"assert StructType([StructField(\\\"nodeId\\\", LongType()), StructField(\\\"score\\\", DoubleType())]) == similarity_ps.to_spark().schema\\n\",\n        \"assert 9134 == similarity_ps.count()[0]\\n\",\n        \"\\n\",\n        \"assert StructType([StructField(\\\"id\\\", StringType()), StructField(\\\"firstPartyFraudScore\\\", DoubleType())]) == client_similarity_ps.to_spark().schema\\n\",\n        \"assert 2433 == client_similarity_ps.count()[0]\\n\",\n        \"print(\\\"All assertion are successfuly satisfied.\\\")\"\n      ],\n      \"metadata\": {\n        \"id\": \"OHel2EYoxFpC\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"We find clients with first-party fraud score greater than some threshold (X) and label those top X percentile clients as fraudsters. In this example, using 95th percentile as a threshold, we set a property FirstPartyFraudster on the Client node.\"\n      ],\n      \"metadata\": {\n        \"id\": \"YBhfX5DYXsom\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"%%cypher\\n\",\n        \"MATCH (c:Client)\\n\",\n        \"WHERE c.firstPartyFraudScore IS NOT NULL\\n\",\n        \"WITH percentileCont(c.firstPartyFraudScore, 0.95) AS firstPartyFraudThreshold\\n\",\n        \"MATCH (c:Client)\\n\",\n        \"WHERE c.firstPartyFraudScore > firstPartyFraudThreshold\\n\",\n        \"SET c:FirstPartyFraudster\"\n      ],\n      \"metadata\": {\n        \"id\": \"bSb4rZ-aXvYV\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"# Second-party Fraud / Money Mules\\n\",\n        \"\\n\",\n        \"The first step is to find out clients who weren't identified as first party fraudsters but they transact with first party fraudsters.\"\n      ],\n      \"metadata\": {\n        \"id\": \"WyKyntZ_YC1g\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"%%cypher\\n\",\n        \"MATCH p=(:Client:FirstPartyFraudster)-[]-(:Transaction)-[]-(c:Client)\\n\",\n        \"WHERE NOT c:FirstPartyFraudster\\n\",\n        \"RETURN p\\n\",\n        \"LIMIT 50\"\n      ],\n      \"metadata\": {\n        \"id\": \"C94Yg_psYTRW\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"Also, lets find out what types of transactions do these Clients perform with first party fraudsters\"\n      ],\n      \"metadata\": {\n        \"id\": \"Tm9WYZnwsQif\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"%%cypher\\n\",\n        \"MATCH (:Client:FirstPartyFraudster)-[]-(txn:Transaction)-[]-(c:Client)\\n\",\n        \"WHERE NOT c:FirstPartyFraudster\\n\",\n        \"UNWIND labels(txn) AS transactionType\\n\",\n        \"RETURN transactionType, count(*) AS freq\"\n      ],\n      \"metadata\": {\n        \"id\": \"x2P9Y7IzY2Vl\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"## Create new relationships\\n\",\n        \"\\n\",\n        \"Let’s go ahead and create `TRANSFER_TO` relationships between clients with `firstPartyFraudster` tags and other clients. Also add the total amount from all such transactions as a property on `TRANSFER_TO` relationships.\\n\",\n        \"\\n\",\n        \"Since the total amount transferred from a fraudster to a client and the total amount transferred in the reverse direction are not the same, we have to create relationships in two separate queries.\\n\",\n        \"\\n\",\n        \"* `TRANSFER_TO` relationship from a fraudster to a client (look at the directions in queries)\\n\",\n        \"* Add `SecondPartyFraudSuspect` tag to these clients\"\n      ],\n      \"metadata\": {\n        \"id\": \"f2HTap1vuLBW\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"%%cypher\\n\",\n        \"MATCH (c1:FirstPartyFraudster)-[]->(t:Transaction)-[]->(c2:Client)\\n\",\n        \"WHERE NOT c2:FirstPartyFraudster\\n\",\n        \"WITH c1, c2, sum(t.amount) AS totalAmount\\n\",\n        \"SET c2:SecondPartyFraudSuspect\\n\",\n        \"CREATE (c1)-[:TRANSFER_TO {amount:totalAmount}]->(c2)\"\n      ],\n      \"metadata\": {\n        \"id\": \"lfGkbJk2ueau\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"* `TRANSFER_TO` relationship from a client to a fraudster.\"\n      ],\n      \"metadata\": {\n        \"id\": \"6yO2wJP6uksA\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"%%cypher\\n\",\n        \"MATCH (c1:FirstPartyFraudster)<-[]-(t:Transaction)<-[]-(c2:Client)\\n\",\n        \"WHERE NOT c2:FirstPartyFraudster\\n\",\n        \"WITH c1, c2, sum(t.amount) AS totalAmount\\n\",\n        \"SET c2:SecondPartyFraudSuspect\\n\",\n        \"CREATE (c1)<-[:TRANSFER_TO {amount:totalAmount}]-(c2);\"\n      ],\n      \"metadata\": {\n        \"id\": \"WUeeP4MhujzM\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"Visualize newly created `TRANSFER_TO` relationships\"\n      ],\n      \"metadata\": {\n        \"id\": \"68rcS85lutUx\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"%%cypher\\n\",\n        \"MATCH p=(:Client:FirstPartyFraudster)-[:TRANSFER_TO]-(c:Client)\\n\",\n        \"WHERE NOT c:FirstPartyFraudster\\n\",\n        \"RETURN p\\n\",\n        \"LIMIT 50\"\n      ],\n      \"metadata\": {\n        \"id\": \"LC5kSXOGuu1w\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"## Goal\\n\",\n        \"\\n\",\n        \"Our objective is to find out clients who may have supported the first party fraudsters and were not identified as potential first party fraudsters.\\n\",\n        \"\\n\",\n        \"Our hypothesis is that clients who perform transactions of type `Transfer` where they either send or receive money from first party fraudsters are flagged as suspects for second party fraud.\\n\",\n        \"\\n\",\n        \"To identify such clients, make use of `TRANSFER_TO` relationships and use this recipe:\\n\",\n        \"\\n\",\n        \"* Use **WCC** (community detection) to identify networks of clients who are connected to first party fraudsters\\n\",\n        \"* Use **PageRank** (centrality) to score clients based on their influence in terms of the amount of money transferred to/from fraudsters\\n\",\n        \"* Assign risk score (`secondPartyFraudScore`) to these clients\"\n      ],\n      \"metadata\": {\n        \"id\": \"6swyguhivCEL\"\n      }\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"## Exercise: Project the graph\\n\",\n        \"\\n\",\n        \"Let’s use native projection and create an in-memory graph with Client nodes and TRANSFER_TO relationships.\\n\",\n        \"\\n\",\n        \"We want to project:\\n\",\n        \"* `Client` for `nodeProjection`\\n\",\n        \"* `TRANSFER_TO` for `relationshipProjection`\\n\",\n        \"* for the configuration we want to set `relationshipProperties` to `amount`\"\n      ],\n      \"metadata\": {\n        \"id\": \"ILntBuwxvXCz\"\n      }\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"### Code in PySpark\"\n      ],\n      \"metadata\": {\n        \"id\": \"zgKufo0Z2C8e\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"second_party_graph_proj_df = # insert your PySpark code here\"\n      ],\n      \"metadata\": {\n        \"id\": \"JmhR2nhwvWRu\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"<details>\\n\",\n        \"<summary>\\n\",\n        \"Show a possible solution\\n\",\n        \"</summary>\\n\",\n        \"\\n\",\n        \"```python\\n\",\n        \"second_party_graph_proj_df = (spark.read.format(\\\"org.neo4j.spark.DataSource\\\")\\n\",\n        \"  .option(\\\"gds\\\", \\\"gds.graph.project\\\")\\n\",\n        \"  .option(\\\"gds.graphName\\\", \\\"SecondPartyFraudNetwork\\\")\\n\",\n        \"  .option(\\\"gds.nodeProjection\\\", \\\"Client\\\")\\n\",\n        \"  .option(\\\"gds.relationshipProjection\\\", \\\"TRANSFER_TO\\\")\\n\",\n        \"  .option(\\\"gds.configuration.relationshipProperties\\\", \\\"amount\\\")\\n\",\n        \"  .load())\\n\",\n        \"```\\n\",\n        \"\\n\",\n        \"</details>\"\n      ],\n      \"metadata\": {\n        \"id\": \"Ab6GEhJ_Tsrx\"\n      }\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"### Code in PySpark Pandas\"\n      ],\n      \"metadata\": {\n        \"id\": \"QHnI8W5J2Gcp\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"second_party_graph_proj_ps = # insert your PySpark Pandas code here\"\n      ],\n      \"metadata\": {\n        \"id\": \"kD6vXaab3JdM\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"<details>\\n\",\n        \"<summary>\\n\",\n        \"Show a possible solution\\n\",\n        \"</summary>\\n\",\n        \"\\n\",\n        \"```python\\n\",\n        \"second_party_graph_proj_ps = ps.read_spark_io(format=\\\"org.neo4j.spark.DataSource\\\", options={\\n\",\n        \"  \\\"gds\\\": \\\"gds.graph.project\\\",\\n\",\n        \"  \\\"gds.graphName\\\": \\\"SecondPartyFraudNetwork\\\",\\n\",\n        \"  \\\"gds.nodeProjection\\\": \\\"Client\\\",\\n\",\n        \"  \\\"gds.relationshipProjection\\\": \\\"TRANSFER_TO\\\",\\n\",\n        \"  \\\"gds.configuration.relationshipProperties\\\": \\\"amount\\\"\\n\",\n        \"})\\n\",\n        \"```\\n\",\n        \"\\n\",\n        \"</details>\"\n      ],\n      \"metadata\": {\n        \"id\": \"c0VjV2rBTy10\"\n      }\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"### Verify the projection\"\n      ],\n      \"metadata\": {\n        \"id\": \"ZVul68Wi162b\"\n      }\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"#### Test PySpark Dataframe\"\n      ],\n      \"metadata\": {\n        \"id\": \"jlOuUGA833ny\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"second_party_graph_proj_df.cache()\\n\",\n        \"\\n\",\n        \"first_row = [\\n\",\n        \"    {\\n\",\n        \"     \\\"node\\\": list(row[\\\"nodeProjection\\\"].keys())[0],\\n\",\n        \"     \\\"rel\\\": list(row[\\\"relationshipProjection\\\"].keys())[0],\\n\",\n        \"     \\\"graphName\\\": row[\\\"graphName\\\"],\\n\",\n        \"     \\\"nodeCount\\\": row[\\\"nodeCount\\\"],\\n\",\n        \"     \\\"relCount\\\": row[\\\"relationshipCount\\\"]\\n\",\n        \"    } for row in second_party_graph_proj_df.collect()\\n\",\n        \"][0]\\n\",\n        \"\\n\",\n        \"assert first_row == {\\\"node\\\": \\\"Client\\\", \\\"rel\\\": \\\"TRANSFER_TO\\\", \\\"graphName\\\": \\\"SecondPartyFraudNetwork\\\", \\\"nodeCount\\\": 2433, \\\"relCount\\\": 367}\\n\",\n        \"print(\\\"All assertion are successfuly satisfied.\\\")\"\n      ],\n      \"metadata\": {\n        \"id\": \"hkjx6Nu339wW\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"#### Test PySpark Pandas\"\n      ],\n      \"metadata\": {\n        \"id\": \"37mDMX8G4EPE\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"second_party_graph_proj_ps_df = second_party_graph_proj_ps.to_spark()\\n\",\n        \"\\n\",\n        \"second_party_graph_proj_ps_df.cache()\\n\",\n        \"\\n\",\n        \"first_row = [\\n\",\n        \"    {\\n\",\n        \"     \\\"node\\\": list(row[\\\"nodeProjection\\\"].keys())[0],\\n\",\n        \"     \\\"rel\\\": list(row[\\\"relationshipProjection\\\"].keys())[0],\\n\",\n        \"     \\\"graphName\\\": row[\\\"graphName\\\"],\\n\",\n        \"     \\\"nodeCount\\\": row[\\\"nodeCount\\\"],\\n\",\n        \"     \\\"relCount\\\": row[\\\"relationshipCount\\\"]\\n\",\n        \"    } for row in second_party_graph_proj_ps_df.collect()\\n\",\n        \"][0]\\n\",\n        \"\\n\",\n        \"assert first_row == {\\\"node\\\": \\\"Client\\\", \\\"rel\\\": \\\"TRANSFER_TO\\\", \\\"graphName\\\": \\\"SecondPartyFraudNetwork\\\", \\\"nodeCount\\\": 2433, \\\"relCount\\\": 367}\\n\",\n        \"print(\\\"All assertion are successfuly satisfied.\\\")\"\n      ],\n      \"metadata\": {\n        \"id\": \"spF535cp4IcR\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"## Check clusters with more than one clients\\n\",\n        \"We will see if there are any clusters with more than one clients in them and if there are, then we should add a tag `secondPartyFraudGroup` to find them later using local queries.\"\n      ],\n      \"metadata\": {\n        \"id\": \"32FL1L324QxV\"\n      }\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"### Code in PySpark\"\n      ],\n      \"metadata\": {\n        \"id\": \"UljCEN-s40mc\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"# invoke gds.wcc.stream on\\n\",\n        \"second_party_wcc_df = (spark.read.format(\\\"org.neo4j.spark.DataSource\\\")\\n\",\n        \"  .option(\\\"gds\\\", \\\"gds.wcc.stream\\\")\\n\",\n        \"  .option(\\\"gds.graphName\\\", \\\"SecondPartyFraudNetwork\\\")\\n\",\n        \"  .load())\\n\",\n        \"\\n\",\n        \"# join the two dataframes aggregate by componentId\\n\",\n        \"# and filtering for clusters with a size greater then 1\\n\",\n        \"second_party_client_component_df = (clients_df.join(second_party_wcc_df, clients_df[\\\"<id>\\\"] == second_party_wcc_df[\\\"nodeId\\\"], \\\"inner\\\")\\n\",\n        \"  .groupBy(\\\"componentId\\\")\\n\",\n        \"  .agg(count(\\\"*\\\").alias(\\\"count\\\"), collect_list(clients_df[\\\"id\\\"]).alias(\\\"cluster\\\"))\\n\",\n        \"  .filter(size(\\\"cluster\\\") > 1))\\n\",\n        \"\\n\",\n        \"second_party_client_component_df = (second_party_client_component_df\\n\",\n        \"                                    .withColumn(\\\"id\\\", explode(col(\\\"cluster\\\")))\\n\",\n        \"                                    .select(\\\"id\\\", \\\"componentId\\\"))\\n\",\n        \"\\n\",\n        \"\\n\",\n        \"second_party_client_component_df.show(truncate=False)\"\n      ],\n      \"metadata\": {\n        \"id\": \"jKK3m8rH150-\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"### Code in PySpark Pandas\"\n      ],\n      \"metadata\": {\n        \"id\": \"cL0e6QHDZZZi\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"second_party_wcc_ps = ps.read_spark_io(format=\\\"org.neo4j.spark.DataSource\\\", options={\\n\",\n        \"  \\\"gds\\\": \\\"gds.wcc.stream\\\",\\n\",\n        \"  \\\"gds.graphName\\\": \\\"SecondPartyFraudNetwork\\\"\\n\",\n        \"})\\n\",\n        \"\\n\",\n        \"second_party_client_component_ps = (clients_ps.join(second_party_wcc_ps.set_index(\\\"nodeId\\\"), on=\\\"<id>\\\")\\n\",\n        \"  .groupby([\\\"componentId\\\"])\\n\",\n        \"  .id\\n\",\n        \"  .apply(list)\\n\",\n        \"  .reset_index()\\n\",\n        \"  .rename(columns={'id': 'cluster'})\\n\",\n        \")\\n\",\n        \"\\n\",\n        \"second_party_client_component_ps = second_party_client_component_ps[second_party_client_component_ps[\\\"cluster\\\"].apply(lambda a: len(a)) > 1]\\n\",\n        \"\\n\",\n        \"second_party_client_component_ps = (second_party_client_component_ps\\n\",\n        \"                                    .explode(\\\"cluster\\\")\\n\",\n        \"                                    .rename(columns={'cluster': 'id'})\\n\",\n        \"                                    [[\\\"id\\\", \\\"componentId\\\"]])\\n\",\n        \"\\n\",\n        \"second_party_client_component_ps[:20]\"\n      ],\n      \"metadata\": {\n        \"id\": \"49OxrIuTZdb-\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"### Exercise: Write the results back to database\\n\",\n        \"\\n\",\n        \"Write a Spark job that given the columns (`id`, `componentId`) retrieve the `Client` by the `id` and set for the node a property `secondPartyFraudGroup` with the value of `componentId`\"\n      ],\n      \"metadata\": {\n        \"id\": \"9IsIbHD7b3cL\"\n      }\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"#### Code in PySpark\"\n      ],\n      \"metadata\": {\n        \"id\": \"1U2kzCyWdv8l\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"# write your PySpark code here\"\n      ],\n      \"metadata\": {\n        \"id\": \"PTid4oiqg_lu\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"<details>\\n\",\n        \"<summary>\\n\",\n        \"Show a possible solution\\n\",\n        \"</summary>\\n\",\n        \"\\n\",\n        \"```python\\n\",\n        \"(second_party_client_component_df\\n\",\n        \"  .withColumnRenamed(\\\"componentId\\\", \\\"secondPartyFraudGroup\\\")\\n\",\n        \"  .write\\n\",\n        \"  .format(\\\"org.neo4j.spark.DataSource\\\")\\n\",\n        \"  .mode(\\\"Overwrite\\\")\\n\",\n        \"  .option(\\\"labels\\\", \\\"Client\\\")\\n\",\n        \"  .option(\\\"node.keys\\\", \\\"id\\\")\\n\",\n        \"  .save())\\n\",\n        \"```\\n\",\n        \"\\n\",\n        \"</details>\"\n      ],\n      \"metadata\": {\n        \"id\": \"BQB9o9JCYuOs\"\n      }\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"#### Code in PySpark Pandas\"\n      ],\n      \"metadata\": {\n        \"id\": \"QgUs-jzIdyWJ\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"# write your PySpark Pandas code here\"\n      ],\n      \"metadata\": {\n        \"id\": \"Copd3BPHduvJ\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"<details>\\n\",\n        \"<summary>\\n\",\n        \"Show a possible solution\\n\",\n        \"</summary>\\n\",\n        \"\\n\",\n        \"```python\\n\",\n        \"(client_component_ps\\n\",\n        \"  .rename(columns={\\\"componentId\\\": \\\"secondPartyFraudGroup\\\"})\\n\",\n        \"  .spark\\n\",\n        \"  .to_spark_io(format=\\\"org.neo4j.spark.DataSource\\\", mode=\\\"Overwrite\\\", options={\\n\",\n        \"      \\\"labels\\\": \\\"Client\\\",\\n\",\n        \"      \\\"node.keys\\\": \\\"id\\\"\\n\",\n        \"  }))\\n\",\n        \"```\\n\",\n        \"\\n\",\n        \"</details>\"\n      ],\n      \"metadata\": {\n        \"id\": \"7uiMcrNHY3GS\"\n      }\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"source\": [\n        \"#### Verify the Spark job result\"\n      ],\n      \"metadata\": {\n        \"id\": \"0mi9x4ragzyX\"\n      }\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [\n        \"secondPartyFraudGroup_check_count = %cypher -u $neo4j_url MATCH (c:Client) WHERE c.secondPartyFraudGroup IS NOT NULL RETURN count(c) AS count\\n\",\n        \"assert 2433 == secondPartyFraudGroup_check_count['count'][0]\\n\",\n        \"print(\\\"All assertion are successfuly satisfied.\\\")\"\n      ],\n      \"metadata\": {\n        \"id\": \"UM3TB_KxgzSh\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"code\",\n      \"source\": [],\n      \"metadata\": {\n        \"id\": \"xSkwu_ovYaI7\"\n      },\n      \"execution_count\": null,\n      \"outputs\": []\n    }\n  ]\n}"
  },
  {
    "path": "jreleaser.yml",
    "content": "# Generated with JReleaser 1.17.0 at 2025-04-28T13:27:24.943485+01:00\nproject:\n  name: neo4j-spark-connector\n  description: Neo4j Connector for Spark\n  authors:\n    - Connectors Team\n  license: Apache-2.0\n  copyright: Neo4j, Inc.\n  links:\n    homepage: https://github.com/neo4j/neo4j-spark-connector\n  languages:\n    java:\n      groupId: org.neo4j\n\nrelease:\n  github:\n    owner: neo4j\n    name: neo4j-spark-connector\n    tagName: \"{{projectVersion}}\"\n    update:\n      enabled: true\n      sections:\n        - TITLE\n        - BODY\n        - ASSETS\n    artifacts: false\n    files: true\n    checksums: true\n    changelog:\n      formatted: ALWAYS\n      preset: conventional-commits\n      skipMergeCommits: true\n      format: \"- {{commitShortHash}} {{conventionalCommitDescription}}\"\n      links: true\n      labelers:\n        - title: ci\n          label: ci\n      excludeLabels:\n        - ci\n      hide:\n        contributors:\n          - '[bot]'\n          - GitHub\n\nchecksum:\n  name: 'neo4j-connector-apache-spark-{{projectVersion}}_checksums.txt'\n  algorithms:\n    - SHA_256\n  files: true\n  artifacts: true\n  individual: true\n\nfiles:\n  globs:\n    - pattern: artifacts/*.jar\n    - pattern: artifacts/*.zip\n      extraProperties:\n        skipRelease: \"true\"\n\nassemble:\n  archive:\n    zip:\n      active: ALWAYS\n      exported: true\n      stereotype: NONE\n      archiveName: neo4j-connector-apache-spark-{{projectVersion}}\n      distributionType: BINARY\n      attachPlatform: false\n      formats:\n        - ZIP\n      fileSets:\n        - input: '{{basedir}}/artifacts'\n          output: .\n          includes:\n            - '{{projectName}}-{{projectVersion}}*.jar'\n      templateDirectory: spark-3/src/jreleaser/assemblers/zip\n\nhooks:\n  script:\n\n    before:\n      - filter:\n          includes: [ \"assemble\" ]\n        shell: BASH\n        run: |\n          rm -rf artifacts\n      - filter:\n          includes: [ \"assemble\" ]\n        matrix:\n          vars:\n            scala: [ \"2.12\", \"2.13\" ]\n        continueOnError: false\n        verbose: true\n        shell: BASH\n        run: |\n          mkdir artifacts || true\n          ./maven-release.sh deploy {{matrix.scala}} default::file://{{basedir}}/target/{{matrix.scala}}/maven-artifacts\n          cp -r {{basedir}}/target/{{matrix.scala}}/maven-artifacts artifacts/\n          cp -r {{basedir}}/spark-3/target/{{projectName}}*.zip artifacts/\n          cp -r {{basedir}}/spark-3/target/{{projectName}}*.jar artifacts/\n\nsigning:\n  active: ALWAYS\n  mode: COMMAND\n  command:\n    homeDir: '~/.gnupg'\n\ndeploy:\n  maven:\n    active: ALWAYS\n    mavenCentral:\n      artifacts:\n        active: ALWAYS\n        url: https://central.sonatype.com/api/v1/publisher\n        applyMavenCentralRules: true\n        namespace: org.neo4j\n        verifyPom: false\n        stagingRepositories:\n          - ./artifacts/maven-artifacts\n\nannounce:\n  slack:\n    channels:\n      - '#release'\n      - '#team-spark'\n    message: ':tada: @release-pm {{projectNameCapitalized}} {{projectVersion}} has been released! {{releaseNotesUrl}}'\n"
  },
  {
    "path": "maven-release.sh",
    "content": "#!/bin/bash\n\nset -eEuxo pipefail\n\nif [[ $# -lt 2 ]] ; then\n    echo \"Usage ./maven-release.sh <GOAL> <SCALA-VERSION> [<ALT_DEPLOYMENT_REPOSITORY>]\"\n    exit 1\nfi\n\nexit_script() {\n  echo \"Process terminated cleaning up resources\"\n  mv -f pom.xml.bak pom.xml\n  mv -f common/pom.xml.bak common/pom.xml\n  mv -f test-support/pom.xml.bak test-support/pom.xml\n  mv -f spark-3/pom.xml.bak spark-3/pom.xml\n  trap - SIGINT SIGTERM # clear the trap\n  kill -- -$$ || true # Sends SIGTERM to child/sub processes\n}\n\nmvn_evaluate() {\n  local expression\n  expression=\"${1}\"\n  ./mvnw -B help:evaluate -Dexpression=\"${expression}\" --quiet -DforceStdout\n}\n\ntrap exit_script SIGINT SIGTERM\n\nGOAL=$1\nSCALA_VERSION=$2\nSPARK_VERSION=3\nif [[ $# -eq 3 ]] ; then\n  ALT_DEPLOYMENT_REPOSITORY=\"-DaltDeploymentRepository=$3\"\nelse\n  ALT_DEPLOYMENT_REPOSITORY=\"\"\nfi\n\ncase $(sed --help 2>&1) in\n  *GNU*) sed_i () { sed -i \"$@\"; };;\n  *) sed_i () { sed -i '' \"$@\"; };;\nesac\n\n\n\nPROJECT_VERSION=$(mvn_evaluate \"project.version\")\nSPARK_PACKAGES_VERSION=\"${PROJECT_VERSION}-s_$SCALA_VERSION\"\n\n# backup files\ncp pom.xml pom.xml.bak\ncp common/pom.xml common/pom.xml.bak\ncp test-support/pom.xml test-support/pom.xml.bak\ncp spark-3/pom.xml spark-3/pom.xml.bak\n\n./mvnw -B versions:set -DnewVersion=${PROJECT_VERSION}_for_spark_${SPARK_VERSION} -DgenerateBackupPoms=false\n\n# replace pom files with target scala version\nsed_i \"s/<artifactId>neo4j-connector-apache-spark_parent<\\/artifactId>/<artifactId>neo4j-connector-apache-spark_${SCALA_VERSION}_parent<\\/artifactId>/\" pom.xml\nsed_i \"s/<artifactId>neo4j-connector-apache-spark_parent<\\/artifactId>/<artifactId>neo4j-connector-apache-spark_${SCALA_VERSION}_parent<\\/artifactId>/\" \"test-support/pom.xml\"\nsed_i \"s/<artifactId>neo4j-connector-apache-spark_test-support<\\/artifactId>/<artifactId>neo4j-connector-apache-spark_${SCALA_VERSION}_test-support<\\/artifactId>/\" \"test-support/pom.xml\"\n\nsed_i \"s/<artifactId>neo4j-connector-apache-spark_common<\\/artifactId>/<artifactId>neo4j-connector-apache-spark_${SCALA_VERSION}_common<\\/artifactId>/\" \"common/pom.xml\"\nsed_i \"s/<artifactId>neo4j-connector-apache-spark_parent<\\/artifactId>/<artifactId>neo4j-connector-apache-spark_${SCALA_VERSION}_parent<\\/artifactId>/\" \"common/pom.xml\"\nsed_i \"s/<artifactId>neo4j-connector-apache-spark_test-support<\\/artifactId>/<artifactId>neo4j-connector-apache-spark_${SCALA_VERSION}_test-support<\\/artifactId>/\" \"common/pom.xml\"\n\nsed_i \"s/<artifactId>neo4j-connector-apache-spark<\\/artifactId>/<artifactId>neo4j-connector-apache-spark_${SCALA_VERSION}<\\/artifactId>/\" \"spark-3/pom.xml\"\nsed_i \"s/<artifactId>neo4j-connector-apache-spark_parent<\\/artifactId>/<artifactId>neo4j-connector-apache-spark_${SCALA_VERSION}_parent<\\/artifactId>/\" \"spark-3/pom.xml\"\nsed_i \"s/<artifactId>neo4j-connector-apache-spark_common<\\/artifactId>/<artifactId>neo4j-connector-apache-spark_${SCALA_VERSION}_common<\\/artifactId>/\" \"spark-3/pom.xml\"\nsed_i \"s/<artifactId>neo4j-connector-apache-spark_test-support<\\/artifactId>/<artifactId>neo4j-connector-apache-spark_${SCALA_VERSION}_test-support<\\/artifactId>/\" \"spark-3/pom.xml\"\nsed_i \"s/<spark-packages.version\\/>/<spark-packages.version>${SPARK_PACKAGES_VERSION}<\\/spark-packages.version>/\" \"spark-3/pom.xml\"\n\n# build\n./mvnw -B clean \"${GOAL}\" -Dscala-\"${SCALA_VERSION}\" -DskipTests ${ALT_DEPLOYMENT_REPOSITORY}\n\nif [ ! ${CI:-false} = true ]; then\n  exit_script\nfi\n"
  },
  {
    "path": "mvnw",
    "content": "#!/bin/sh\n# ----------------------------------------------------------------------------\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#    http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing,\n# software distributed under the License is distributed on an\n# \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n# KIND, either express or implied.  See the License for the\n# specific language governing permissions and limitations\n# under the License.\n# ----------------------------------------------------------------------------\n\n# ----------------------------------------------------------------------------\n# Apache Maven Wrapper startup batch script, version 3.3.2\n#\n# Optional ENV vars\n# -----------------\n#   JAVA_HOME - location of a JDK home dir, required when download maven via java source\n#   MVNW_REPOURL - repo url base for downloading maven distribution\n#   MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven\n#   MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output\n# ----------------------------------------------------------------------------\n\nset -euf\n[ \"${MVNW_VERBOSE-}\" != debug ] || set -x\n\n# OS specific support.\nnative_path() { printf %s\\\\n \"$1\"; }\ncase \"$(uname)\" in\nCYGWIN* | MINGW*)\n  [ -z \"${JAVA_HOME-}\" ] || JAVA_HOME=\"$(cygpath --unix \"$JAVA_HOME\")\"\n  native_path() { cygpath --path --windows \"$1\"; }\n  ;;\nesac\n\n# set JAVACMD and JAVACCMD\nset_java_home() {\n  # For Cygwin and MinGW, ensure paths are in Unix format before anything is touched\n  if [ -n \"${JAVA_HOME-}\" ]; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ]; then\n      # IBM's JDK on AIX uses strange locations for the executables\n      JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n      JAVACCMD=\"$JAVA_HOME/jre/sh/javac\"\n    else\n      JAVACMD=\"$JAVA_HOME/bin/java\"\n      JAVACCMD=\"$JAVA_HOME/bin/javac\"\n\n      if [ ! -x \"$JAVACMD\" ] || [ ! -x \"$JAVACCMD\" ]; then\n        echo \"The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run.\" >&2\n        echo \"JAVA_HOME is set to \\\"$JAVA_HOME\\\", but \\\"\\$JAVA_HOME/bin/java\\\" or \\\"\\$JAVA_HOME/bin/javac\\\" does not exist.\" >&2\n        return 1\n      fi\n    fi\n  else\n    JAVACMD=\"$(\n      'set' +e\n      'unset' -f command 2>/dev/null\n      'command' -v java\n    )\" || :\n    JAVACCMD=\"$(\n      'set' +e\n      'unset' -f command 2>/dev/null\n      'command' -v javac\n    )\" || :\n\n    if [ ! -x \"${JAVACMD-}\" ] || [ ! -x \"${JAVACCMD-}\" ]; then\n      echo \"The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run.\" >&2\n      return 1\n    fi\n  fi\n}\n\n# hash string like Java String::hashCode\nhash_string() {\n  str=\"${1:-}\" h=0\n  while [ -n \"$str\" ]; do\n    char=\"${str%\"${str#?}\"}\"\n    h=$(((h * 31 + $(LC_CTYPE=C printf %d \"'$char\")) % 4294967296))\n    str=\"${str#?}\"\n  done\n  printf %x\\\\n $h\n}\n\nverbose() { :; }\n[ \"${MVNW_VERBOSE-}\" != true ] || verbose() { printf %s\\\\n \"${1-}\"; }\n\ndie() {\n  printf %s\\\\n \"$1\" >&2\n  exit 1\n}\n\ntrim() {\n  # MWRAPPER-139:\n  #   Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds.\n  #   Needed for removing poorly interpreted newline sequences when running in more\n  #   exotic environments such as mingw bash on Windows.\n  printf \"%s\" \"${1}\" | tr -d '[:space:]'\n}\n\n# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties\nwhile IFS=\"=\" read -r key value; do\n  case \"${key-}\" in\n  distributionUrl) distributionUrl=$(trim \"${value-}\") ;;\n  distributionSha256Sum) distributionSha256Sum=$(trim \"${value-}\") ;;\n  esac\ndone <\"${0%/*}/.mvn/wrapper/maven-wrapper.properties\"\n[ -n \"${distributionUrl-}\" ] || die \"cannot read distributionUrl property in ${0%/*}/.mvn/wrapper/maven-wrapper.properties\"\n\ncase \"${distributionUrl##*/}\" in\nmaven-mvnd-*bin.*)\n  MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/\n  case \"${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)\" in\n  *AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;;\n  :Darwin*x86_64) distributionPlatform=darwin-amd64 ;;\n  :Darwin*arm64) distributionPlatform=darwin-aarch64 ;;\n  :Linux*x86_64*) distributionPlatform=linux-amd64 ;;\n  *)\n    echo \"Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version\" >&2\n    distributionPlatform=linux-amd64\n    ;;\n  esac\n  distributionUrl=\"${distributionUrl%-bin.*}-$distributionPlatform.zip\"\n  ;;\nmaven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;;\n*) MVN_CMD=\"mvn${0##*/mvnw}\" _MVNW_REPO_PATTERN=/org/apache/maven/ ;;\nesac\n\n# apply MVNW_REPOURL and calculate MAVEN_HOME\n# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash>\n[ -z \"${MVNW_REPOURL-}\" ] || distributionUrl=\"$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*\"$_MVNW_REPO_PATTERN\"}\"\ndistributionUrlName=\"${distributionUrl##*/}\"\ndistributionUrlNameMain=\"${distributionUrlName%.*}\"\ndistributionUrlNameMain=\"${distributionUrlNameMain%-bin}\"\nMAVEN_USER_HOME=\"${MAVEN_USER_HOME:-${HOME}/.m2}\"\nMAVEN_HOME=\"${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string \"$distributionUrl\")\"\n\nexec_maven() {\n  unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || :\n  exec \"$MAVEN_HOME/bin/$MVN_CMD\" \"$@\" || die \"cannot exec $MAVEN_HOME/bin/$MVN_CMD\"\n}\n\nif [ -d \"$MAVEN_HOME\" ]; then\n  verbose \"found existing MAVEN_HOME at $MAVEN_HOME\"\n  exec_maven \"$@\"\nfi\n\ncase \"${distributionUrl-}\" in\n*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;;\n*) die \"distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'\" ;;\nesac\n\n# prepare tmp dir\nif TMP_DOWNLOAD_DIR=\"$(mktemp -d)\" && [ -d \"$TMP_DOWNLOAD_DIR\" ]; then\n  clean() { rm -rf -- \"$TMP_DOWNLOAD_DIR\"; }\n  trap clean HUP INT TERM EXIT\nelse\n  die \"cannot create temp dir\"\nfi\n\nmkdir -p -- \"${MAVEN_HOME%/*}\"\n\n# Download and Install Apache Maven\nverbose \"Couldn't find MAVEN_HOME, downloading and installing it ...\"\nverbose \"Downloading from: $distributionUrl\"\nverbose \"Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName\"\n\n# select .zip or .tar.gz\nif ! command -v unzip >/dev/null; then\n  distributionUrl=\"${distributionUrl%.zip}.tar.gz\"\n  distributionUrlName=\"${distributionUrl##*/}\"\nfi\n\n# verbose opt\n__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR=''\n[ \"${MVNW_VERBOSE-}\" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v\n\n# normalize http auth\ncase \"${MVNW_PASSWORD:+has-password}\" in\n'') MVNW_USERNAME='' MVNW_PASSWORD='' ;;\nhas-password) [ -n \"${MVNW_USERNAME-}\" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;;\nesac\n\nif [ -z \"${MVNW_USERNAME-}\" ] && command -v wget >/dev/null; then\n  verbose \"Found wget ... using wget\"\n  wget ${__MVNW_QUIET_WGET:+\"$__MVNW_QUIET_WGET\"} \"$distributionUrl\" -O \"$TMP_DOWNLOAD_DIR/$distributionUrlName\" || die \"wget: Failed to fetch $distributionUrl\"\nelif [ -z \"${MVNW_USERNAME-}\" ] && command -v curl >/dev/null; then\n  verbose \"Found curl ... using curl\"\n  curl ${__MVNW_QUIET_CURL:+\"$__MVNW_QUIET_CURL\"} -f -L -o \"$TMP_DOWNLOAD_DIR/$distributionUrlName\" \"$distributionUrl\" || die \"curl: Failed to fetch $distributionUrl\"\nelif set_java_home; then\n  verbose \"Falling back to use Java to download\"\n  javaSource=\"$TMP_DOWNLOAD_DIR/Downloader.java\"\n  targetZip=\"$TMP_DOWNLOAD_DIR/$distributionUrlName\"\n  cat >\"$javaSource\" <<-END\n\tpublic class Downloader extends java.net.Authenticator\n\t{\n\t  protected java.net.PasswordAuthentication getPasswordAuthentication()\n\t  {\n\t    return new java.net.PasswordAuthentication( System.getenv( \"MVNW_USERNAME\" ), System.getenv( \"MVNW_PASSWORD\" ).toCharArray() );\n\t  }\n\t  public static void main( String[] args ) throws Exception\n\t  {\n\t    setDefault( new Downloader() );\n\t    java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() );\n\t  }\n\t}\n\tEND\n  # For Cygwin/MinGW, switch paths to Windows format before running javac and java\n  verbose \" - Compiling Downloader.java ...\"\n  \"$(native_path \"$JAVACCMD\")\" \"$(native_path \"$javaSource\")\" || die \"Failed to compile Downloader.java\"\n  verbose \" - Running Downloader.java ...\"\n  \"$(native_path \"$JAVACMD\")\" -cp \"$(native_path \"$TMP_DOWNLOAD_DIR\")\" Downloader \"$distributionUrl\" \"$(native_path \"$targetZip\")\"\nfi\n\n# If specified, validate the SHA-256 sum of the Maven distribution zip file\nif [ -n \"${distributionSha256Sum-}\" ]; then\n  distributionSha256Result=false\n  if [ \"$MVN_CMD\" = mvnd.sh ]; then\n    echo \"Checksum validation is not supported for maven-mvnd.\" >&2\n    echo \"Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties.\" >&2\n    exit 1\n  elif command -v sha256sum >/dev/null; then\n    if echo \"$distributionSha256Sum  $TMP_DOWNLOAD_DIR/$distributionUrlName\" | sha256sum -c >/dev/null 2>&1; then\n      distributionSha256Result=true\n    fi\n  elif command -v shasum >/dev/null; then\n    if echo \"$distributionSha256Sum  $TMP_DOWNLOAD_DIR/$distributionUrlName\" | shasum -a 256 -c >/dev/null 2>&1; then\n      distributionSha256Result=true\n    fi\n  else\n    echo \"Checksum validation was requested but neither 'sha256sum' or 'shasum' are available.\" >&2\n    echo \"Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties.\" >&2\n    exit 1\n  fi\n  if [ $distributionSha256Result = false ]; then\n    echo \"Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised.\" >&2\n    echo \"If you updated your Maven version, you need to update the specified distributionSha256Sum property.\" >&2\n    exit 1\n  fi\nfi\n\n# unzip and move\nif command -v unzip >/dev/null; then\n  unzip ${__MVNW_QUIET_UNZIP:+\"$__MVNW_QUIET_UNZIP\"} \"$TMP_DOWNLOAD_DIR/$distributionUrlName\" -d \"$TMP_DOWNLOAD_DIR\" || die \"failed to unzip\"\nelse\n  tar xzf${__MVNW_QUIET_TAR:+\"$__MVNW_QUIET_TAR\"} \"$TMP_DOWNLOAD_DIR/$distributionUrlName\" -C \"$TMP_DOWNLOAD_DIR\" || die \"failed to untar\"\nfi\nprintf %s\\\\n \"$distributionUrl\" >\"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/mvnw.url\"\nmv -- \"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain\" \"$MAVEN_HOME\" || [ -d \"$MAVEN_HOME\" ] || die \"fail to move MAVEN_HOME\"\n\nclean || :\nexec_maven \"$@\"\n"
  },
  {
    "path": "mvnw.cmd",
    "content": "<# : batch portion\r\n@REM ----------------------------------------------------------------------------\r\n@REM Licensed to the Apache Software Foundation (ASF) under one\r\n@REM or more contributor license agreements.  See the NOTICE file\r\n@REM distributed with this work for additional information\r\n@REM regarding copyright ownership.  The ASF licenses this file\r\n@REM to you under the Apache License, Version 2.0 (the\r\n@REM \"License\"); you may not use this file except in compliance\r\n@REM with the License.  You may obtain a copy of the License at\r\n@REM\r\n@REM    http://www.apache.org/licenses/LICENSE-2.0\r\n@REM\r\n@REM Unless required by applicable law or agreed to in writing,\r\n@REM software distributed under the License is distributed on an\r\n@REM \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\r\n@REM KIND, either express or implied.  See the License for the\r\n@REM specific language governing permissions and limitations\r\n@REM under the License.\r\n@REM ----------------------------------------------------------------------------\r\n\r\n@REM ----------------------------------------------------------------------------\r\n@REM Apache Maven Wrapper startup batch script, version 3.3.2\r\n@REM\r\n@REM Optional ENV vars\r\n@REM   MVNW_REPOURL - repo url base for downloading maven distribution\r\n@REM   MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven\r\n@REM   MVNW_VERBOSE - true: enable verbose log; others: silence the output\r\n@REM ----------------------------------------------------------------------------\r\n\r\n@IF \"%__MVNW_ARG0_NAME__%\"==\"\" (SET __MVNW_ARG0_NAME__=%~nx0)\r\n@SET __MVNW_CMD__=\r\n@SET __MVNW_ERROR__=\r\n@SET __MVNW_PSMODULEP_SAVE=%PSModulePath%\r\n@SET PSModulePath=\r\n@FOR /F \"usebackq tokens=1* delims==\" %%A IN (`powershell -noprofile \"& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}\"`) DO @(\r\n  IF \"%%A\"==\"MVN_CMD\" (set __MVNW_CMD__=%%B) ELSE IF \"%%B\"==\"\" (echo %%A) ELSE (echo %%A=%%B)\r\n)\r\n@SET PSModulePath=%__MVNW_PSMODULEP_SAVE%\r\n@SET __MVNW_PSMODULEP_SAVE=\r\n@SET __MVNW_ARG0_NAME__=\r\n@SET MVNW_USERNAME=\r\n@SET MVNW_PASSWORD=\r\n@IF NOT \"%__MVNW_CMD__%\"==\"\" (%__MVNW_CMD__% %*)\r\n@echo Cannot start maven from wrapper >&2 && exit /b 1\r\n@GOTO :EOF\r\n: end batch / begin powershell #>\r\n\r\n$ErrorActionPreference = \"Stop\"\r\nif ($env:MVNW_VERBOSE -eq \"true\") {\r\n  $VerbosePreference = \"Continue\"\r\n}\r\n\r\n# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties\r\n$distributionUrl = (Get-Content -Raw \"$scriptDir/.mvn/wrapper/maven-wrapper.properties\" | ConvertFrom-StringData).distributionUrl\r\nif (!$distributionUrl) {\r\n  Write-Error \"cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties\"\r\n}\r\n\r\nswitch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) {\r\n  \"maven-mvnd-*\" {\r\n    $USE_MVND = $true\r\n    $distributionUrl = $distributionUrl -replace '-bin\\.[^.]*$',\"-windows-amd64.zip\"\r\n    $MVN_CMD = \"mvnd.cmd\"\r\n    break\r\n  }\r\n  default {\r\n    $USE_MVND = $false\r\n    $MVN_CMD = $script -replace '^mvnw','mvn'\r\n    break\r\n  }\r\n}\r\n\r\n# apply MVNW_REPOURL and calculate MAVEN_HOME\r\n# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash>\r\nif ($env:MVNW_REPOURL) {\r\n  $MVNW_REPO_PATTERN = if ($USE_MVND) { \"/org/apache/maven/\" } else { \"/maven/mvnd/\" }\r\n  $distributionUrl = \"$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')\"\r\n}\r\n$distributionUrlName = $distributionUrl -replace '^.*/',''\r\n$distributionUrlNameMain = $distributionUrlName -replace '\\.[^.]*$','' -replace '-bin$',''\r\n$MAVEN_HOME_PARENT = \"$HOME/.m2/wrapper/dists/$distributionUrlNameMain\"\r\nif ($env:MAVEN_USER_HOME) {\r\n  $MAVEN_HOME_PARENT = \"$env:MAVEN_USER_HOME/wrapper/dists/$distributionUrlNameMain\"\r\n}\r\n$MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString(\"x2\")}) -join ''\r\n$MAVEN_HOME = \"$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME\"\r\n\r\nif (Test-Path -Path \"$MAVEN_HOME\" -PathType Container) {\r\n  Write-Verbose \"found existing MAVEN_HOME at $MAVEN_HOME\"\r\n  Write-Output \"MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD\"\r\n  exit $?\r\n}\r\n\r\nif (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) {\r\n  Write-Error \"distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl\"\r\n}\r\n\r\n# prepare tmp dir\r\n$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile\r\n$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path \"$TMP_DOWNLOAD_DIR_HOLDER.dir\"\r\n$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null\r\ntrap {\r\n  if ($TMP_DOWNLOAD_DIR.Exists) {\r\n    try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }\r\n    catch { Write-Warning \"Cannot remove $TMP_DOWNLOAD_DIR\" }\r\n  }\r\n}\r\n\r\nNew-Item -Itemtype Directory -Path \"$MAVEN_HOME_PARENT\" -Force | Out-Null\r\n\r\n# Download and Install Apache Maven\r\nWrite-Verbose \"Couldn't find MAVEN_HOME, downloading and installing it ...\"\r\nWrite-Verbose \"Downloading from: $distributionUrl\"\r\nWrite-Verbose \"Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName\"\r\n\r\n$webclient = New-Object System.Net.WebClient\r\nif ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) {\r\n  $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD)\r\n}\r\n[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12\r\n$webclient.DownloadFile($distributionUrl, \"$TMP_DOWNLOAD_DIR/$distributionUrlName\") | Out-Null\r\n\r\n# If specified, validate the SHA-256 sum of the Maven distribution zip file\r\n$distributionSha256Sum = (Get-Content -Raw \"$scriptDir/.mvn/wrapper/maven-wrapper.properties\" | ConvertFrom-StringData).distributionSha256Sum\r\nif ($distributionSha256Sum) {\r\n  if ($USE_MVND) {\r\n    Write-Error \"Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties.\"\r\n  }\r\n  Import-Module $PSHOME\\Modules\\Microsoft.PowerShell.Utility -Function Get-FileHash\r\n  if ((Get-FileHash \"$TMP_DOWNLOAD_DIR/$distributionUrlName\" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) {\r\n    Write-Error \"Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property.\"\r\n  }\r\n}\r\n\r\n# unzip and move\r\nExpand-Archive \"$TMP_DOWNLOAD_DIR/$distributionUrlName\" -DestinationPath \"$TMP_DOWNLOAD_DIR\" | Out-Null\r\nRename-Item -Path \"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain\" -NewName $MAVEN_HOME_NAME | Out-Null\r\ntry {\r\n  Move-Item -Path \"$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME\" -Destination $MAVEN_HOME_PARENT | Out-Null\r\n} catch {\r\n  if (! (Test-Path -Path \"$MAVEN_HOME\" -PathType Container)) {\r\n    Write-Error \"fail to move MAVEN_HOME\"\r\n  }\r\n} finally {\r\n  try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }\r\n  catch { Write-Warning \"Cannot remove $TMP_DOWNLOAD_DIR\" }\r\n}\r\n\r\nWrite-Output \"MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD\"\r\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"devDependencies\": {\n    \"@commitlint/cli\": \"^20.4.2\",\n    \"@commitlint/config-conventional\": \"^20.4.2\",\n    \"@commitlint/lint\": \"^20.4.2\",\n    \"@commitlint/load\": \"^20.4.0\",\n    \"danger\": \"^13.0.7\",\n    \"husky\": \"^9.1.7\"\n  },\n  \"scripts\": {\n    \"prepare\": \"husky\"\n  }\n}\n"
  },
  {
    "path": "pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n        xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <groupId>org.neo4j</groupId>\n    <artifactId>neo4j-connector-apache-spark_parent</artifactId>\n    <version>5.4.3-SNAPSHOT</version>\n    <packaging>pom</packaging>\n    <name>neo4j-connector-apache-spark_parent</name>\n    <description>Neo4j Connector for Apache Spark using the binary Bolt Driver</description>\n    <url>https://github.com/neo4j/neo4j-spark-connector</url>\n    <organization>\n        <name>Neo4j, Inc.</name>\n        <url>https://neo4j.com/</url>\n    </organization>\n    <licenses>\n        <license>\n            <name>Apache License, Version 2.0</name>\n            <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>\n            <distribution>manual</distribution>\n        </license>\n    </licenses>\n    <developers>\n        <developer>\n            <id>team-connectors</id>\n            <name>Connectors Team</name>\n            <organization>Neo4j</organization>\n            <organizationUrl>https://neo4j.com</organizationUrl>\n        </developer>\n    </developers>\n    <modules>\n        <module>common</module>\n        <module>test-support</module>\n        <module>spark-3</module>\n    </modules>\n    <scm>\n        <url>https://github.com/neo4j/neo4j-spark-connector</url>\n    </scm>\n    <properties>\n        <build-resources.version>2026.02.5</build-resources.version>\n        <caniuse.version>1.3.3</caniuse.version>\n        <commons-compress.version>1.28.0</commons-compress.version>\n        <commons-lang3.version>3.20.0</commons-lang3.version>\n        <connectors-commons.version>1.0.0-rc2</connectors-commons.version>\n        <cypherdsl.version>2022.11.0</cypherdsl.version>\n        <driver.version>4.4.22</driver.version>\n        <java.version>1.8</java.version>\n        <!-- 3.4.3.Final is the latest jboss-logging version compatible with java 8 -->\n        <jboss-logging.version>3.4.3.Final</jboss-logging.version>\n        <junit.version>4.13.2</junit.version>\n        <license-maven-plugin.version>4.6</license-maven-plugin.version>\n        <licensing-maven-plugin.version>1.7.12</licensing-maven-plugin.version>\n        <licensing.prepend.text>/license/neo4j_apache_v2/notice.txt</licensing.prepend.text>\n        <maven-clean-plugin.version>3.5.0</maven-clean-plugin.version>\n        <maven-compiler-plugin.version>3.15.0</maven-compiler-plugin.version>\n        <maven-dependency-plugin.version>3.10.0</maven-dependency-plugin.version>\n        <maven-deploy-plugin.version>3.1.4</maven-deploy-plugin.version>\n        <maven-enforcer-plugin.version>3.6.2</maven-enforcer-plugin.version>\n        <maven-failsafe-plugin.version>3.5.5</maven-failsafe-plugin.version>\n        <maven-install-plugin.version>3.1.4</maven-install-plugin.version>\n        <maven-jar-plugin.version>3.5.0</maven-jar-plugin.version>\n        <maven-resources-plugin.version>3.5.0</maven-resources-plugin.version>\n        <maven-site-plugin.version>3.21.0</maven-site-plugin.version>\n        <maven-source-plugin.version>3.4.0</maven-source-plugin.version>\n        <maven-surefire-plugin.version>3.5.5</maven-surefire-plugin.version>\n        <neo4j.experimental>false</neo4j.experimental>\n        <neo4j.version>4.4.20</neo4j.version>\n        <netty-bom.version>4.1.132.Final</netty-bom.version>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <scala-maven-plugin.version>4.9.10</scala-maven-plugin.version>\n        <scala.binary.version>2.12</scala.binary.version>\n        <scala.version>2.12.20</scala.version>\n        <slf4j-api.version>2.0.17</slf4j-api.version>\n        <sortpom-maven-plugin.version>4.0.0</sortpom-maven-plugin.version>\n        <spark.version>3.5.8</spark.version>\n        <spotless-maven-plugin.version>3.4.0</spotless-maven-plugin.version>\n        <surefire.jvm.args/>\n        <testcontainers.version>2.0.4</testcontainers.version>\n    </properties>\n    <dependencyManagement>\n        <dependencies>\n            <dependency>\n                <groupId>io.netty</groupId>\n                <artifactId>netty-bom</artifactId>\n                <version>${netty-bom.version}</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n            <dependency>\n                <groupId>org.testcontainers</groupId>\n                <artifactId>testcontainers-bom</artifactId>\n                <version>${testcontainers.version}</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n            <dependency>\n                <groupId>junit</groupId>\n                <artifactId>junit</artifactId>\n                <version>${junit.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.commons</groupId>\n                <artifactId>commons-compress</artifactId>\n                <version>${commons-compress.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.commons</groupId>\n                <artifactId>commons-lang3</artifactId>\n                <version>${commons-lang3.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.spark</groupId>\n                <artifactId>spark-sql_${scala.binary.version}</artifactId>\n                <version>${spark.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.hamcrest</groupId>\n                <artifactId>hamcrest</artifactId>\n                <version>3.0</version>\n            </dependency>\n            <dependency>\n                <groupId>org.jboss.logging</groupId>\n                <artifactId>jboss-logging</artifactId>\n                <version>${jboss-logging.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.neo4j</groupId>\n                <artifactId>caniuse-core</artifactId>\n                <version>${caniuse.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.neo4j</groupId>\n                <artifactId>caniuse-neo4j-detection</artifactId>\n                <version>${caniuse.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.neo4j</groupId>\n                <artifactId>neo4j-cypher-dsl</artifactId>\n                <version>${cypherdsl.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.neo4j.connectors</groupId>\n                <artifactId>commons-authn-keycloak</artifactId>\n                <version>${connectors-commons.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.neo4j.connectors</groupId>\n                <artifactId>commons-authn-provided</artifactId>\n                <version>${connectors-commons.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.neo4j.connectors</groupId>\n                <artifactId>commons-authn-spi</artifactId>\n                <version>${connectors-commons.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.neo4j.connectors</groupId>\n                <artifactId>commons-reauth-driver</artifactId>\n                <version>${connectors-commons.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.neo4j.driver</groupId>\n                <artifactId>neo4j-java-driver-slim</artifactId>\n                <version>${driver.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.scala-lang</groupId>\n                <artifactId>scala-library</artifactId>\n                <version>${scala.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.scala-lang</groupId>\n                <artifactId>scala-reflect</artifactId>\n                <version>${scala.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.scalatest</groupId>\n                <artifactId>scalatest_${scala.binary.version}</artifactId>\n                <version>3.2.20</version>\n            </dependency>\n            <dependency>\n                <groupId>org.scalatestplus</groupId>\n                <artifactId>junit-4-13_${scala.binary.version}</artifactId>\n                <version>3.2.20.0</version>\n            </dependency>\n            <dependency>\n                <groupId>org.slf4j</groupId>\n                <artifactId>slf4j-api</artifactId>\n                <version>${slf4j-api.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.spark</groupId>\n                <artifactId>spark-core_${scala.binary.version}</artifactId>\n                <version>${spark.version}</version>\n                <scope>provided</scope>\n                <exclusions>\n                    <exclusion>\n                        <groupId>org.apache.xbean</groupId>\n                        <artifactId>xbean-asm6-shaded</artifactId>\n                    </exclusion>\n                </exclusions>\n            </dependency>\n        </dependencies>\n    </dependencyManagement>\n    <build>\n        <pluginManagement>\n            <plugins>\n                <plugin>\n                    <groupId>org.codehaus.mojo</groupId>\n                    <artifactId>versions-maven-plugin</artifactId>\n                    <version>2.21.0</version>\n                    <configuration>\n                        <generateBackupPoms>false</generateBackupPoms>\n                    </configuration>\n                </plugin>\n                <plugin>\n                    <groupId>org.apache.maven.plugins</groupId>\n                    <artifactId>maven-clean-plugin</artifactId>\n                    <version>${maven-clean-plugin.version}</version>\n                </plugin>\n                <plugin>\n                    <groupId>org.apache.maven.plugins</groupId>\n                    <artifactId>maven-deploy-plugin</artifactId>\n                    <version>${maven-deploy-plugin.version}</version>\n                </plugin>\n                <plugin>\n                    <groupId>org.apache.maven.plugins</groupId>\n                    <artifactId>maven-install-plugin</artifactId>\n                    <version>${maven-install-plugin.version}</version>\n                </plugin>\n                <plugin>\n                    <groupId>org.apache.maven.plugins</groupId>\n                    <artifactId>maven-site-plugin</artifactId>\n                    <version>${maven-site-plugin.version}</version>\n                </plugin>\n                <plugin>\n                    <groupId>org.apache.maven.plugins</groupId>\n                    <artifactId>maven-jar-plugin</artifactId>\n                    <version>${maven-jar-plugin.version}</version>\n                    <configuration>\n                        <archive>\n                            <manifest>\n                                <addDefaultImplementationEntries>true</addDefaultImplementationEntries>\n                            </manifest>\n                        </archive>\n                    </configuration>\n                </plugin>\n                <plugin>\n                    <groupId>org.apache.maven.plugins</groupId>\n                    <artifactId>maven-resources-plugin</artifactId>\n                    <version>${maven-resources-plugin.version}</version>\n                    <configuration>\n                        <propertiesEncoding>${project.build.sourceEncoding}</propertiesEncoding>\n                    </configuration>\n                </plugin>\n                <plugin>\n                    <groupId>org.neo4j.build.plugins</groupId>\n                    <artifactId>licensing-maven-plugin</artifactId>\n                    <version>${licensing-maven-plugin.version}</version>\n                    <configuration>\n                        <failIfDisliked>true</failIfDisliked>\n                        <failIfMissing>true</failIfMissing>\n                        <plainTextReport>true</plainTextReport>\n                        <prependText>${licensing.prepend.text}</prependText>\n                        <excludedGroups>^((org.neo4j){1}|(org.neo4j.connectors){1}|(org.neo4j.connectors.kafka){1}|(org.neo4j.driver){1})$</excludedGroups>\n                        <includedScopes>compile,runtime</includedScopes>\n                    </configuration>\n                    <dependencies>\n                        <dependency>\n                            <groupId>org.neo4j.build</groupId>\n                            <artifactId>resources</artifactId>\n                            <version>${build-resources.version}</version>\n                        </dependency>\n                    </dependencies>\n                    <executions>\n                        <execution>\n                            <id>list-all-licenses</id>\n                            <goals>\n                                <goal>check</goal>\n                            </goals>\n                            <phase>compile</phase>\n                            <configuration>\n                                <licensingRequirementFiles>\n                                    <!--suppress UnresolvedMavenProperty -->\n                                    <licensingRequirementFile>licensing/licensing-requirements-base.xml</licensingRequirementFile>\n                                </licensingRequirementFiles>\n                                <thirdPartyLicensingFilename>${project.artifactId}-${project.version}-NOTICE.txt</thirdPartyLicensingFilename>\n                                <checkExistingNoticeFile>${project.build.directory}/../NOTICE.txt</checkExistingNoticeFile>\n                                <listPrependText>/licensing/list-prefix.txt</listPrependText>\n                                <listReport>${project.artifactId}-${project.version}-LICENSES.txt</listReport>\n                                <checkExistingLicensesFile>${project.build.directory}/../LICENSES.txt</checkExistingLicensesFile>\n                            </configuration>\n                        </execution>\n                    </executions>\n                </plugin>\n                <plugin>\n                    <groupId>org.apache.maven.plugins</groupId>\n                    <artifactId>maven-source-plugin</artifactId>\n                    <version>${maven-source-plugin.version}</version>\n                    <executions>\n                        <execution>\n                            <id>attach-sources</id>\n                            <goals>\n                                <goal>jar</goal>\n                            </goals>\n                        </execution>\n                    </executions>\n                </plugin>\n                <plugin>\n                    <groupId>org.apache.maven.plugins</groupId>\n                    <artifactId>maven-enforcer-plugin</artifactId>\n                    <version>${maven-enforcer-plugin.version}</version>\n                    <executions>\n                        <execution>\n                            <id>enforce</id>\n                            <goals>\n                                <goal>enforce</goal>\n                            </goals>\n                            <phase>validate</phase>\n                            <configuration>\n                                <rules>\n                                    <requireMavenVersion>\n                                        <version>[3.6.3,)</version>\n                                    </requireMavenVersion>\n                                    <requireJavaVersion>\n                                        <version>8</version>\n                                    </requireJavaVersion>\n                                    <dependencyConvergence/>\n                                </rules>\n                            </configuration>\n                        </execution>\n                    </executions>\n                </plugin>\n                <plugin>\n                    <groupId>org.apache.maven.plugins</groupId>\n                    <artifactId>maven-compiler-plugin</artifactId>\n                    <version>${maven-compiler-plugin.version}</version>\n                    <configuration>\n                        <source>${java.version}</source>\n                        <target>${java.version}</target>\n                    </configuration>\n                </plugin>\n                <plugin>\n                    <groupId>org.apache.maven.plugins</groupId>\n                    <artifactId>maven-failsafe-plugin</artifactId>\n                    <version>${maven-failsafe-plugin.version}</version>\n                    <configuration>\n                        <includes>\n                            <include>**/*IT.*</include>\n                            <include>**/*TSE.*</include>\n                        </includes>\n                        <forkCount>1</forkCount>\n                        <reuseForks>false</reuseForks>\n                        <argLine>${surefire.jvm.args}</argLine>\n                        <useModulePath>false</useModulePath>\n                    </configuration>\n                    <executions>\n                        <execution>\n                            <goals>\n                                <goal>integration-test</goal>\n                                <goal>verify</goal>\n                            </goals>\n                            <phase>integration-test</phase>\n                        </execution>\n                    </executions>\n                </plugin>\n                <plugin>\n                    <groupId>org.apache.maven.plugins</groupId>\n                    <artifactId>maven-dependency-plugin</artifactId>\n                    <version>${maven-dependency-plugin.version}</version>\n                </plugin>\n                <plugin>\n                    <groupId>com.mycila</groupId>\n                    <artifactId>license-maven-plugin</artifactId>\n                    <version>${license-maven-plugin.version}</version>\n                    <configuration>\n                        <strictCheck>true</strictCheck>\n                        <licenseSets>\n                            <licenseSet>\n                                <header>/license/neo4j_apache_v2/header.txt</header>\n                                <includes>\n                                    <include>src/**/*.scala</include>\n                                    <include>src/**/*.java</include>\n                                </includes>\n                            </licenseSet>\n                        </licenseSets>\n                        <mapping>\n                            <scala>SLASHSTAR_STYLE</scala>\n                        </mapping>\n                    </configuration>\n                    <dependencies>\n                        <dependency>\n                            <groupId>org.neo4j.build</groupId>\n                            <artifactId>resources</artifactId>\n                            <version>${build-resources.version}</version>\n                        </dependency>\n                    </dependencies>\n                    <executions>\n                        <execution>\n                            <id>check-licenses</id>\n                            <goals>\n                                <goal>check</goal>\n                            </goals>\n                            <phase>compile</phase>\n                        </execution>\n                    </executions>\n                </plugin>\n                <plugin>\n                    <groupId>org.apache.maven.plugins</groupId>\n                    <artifactId>maven-surefire-plugin</artifactId>\n                    <version>${maven-surefire-plugin.version}</version>\n                    <configuration>\n                        <argLine>${surefire.jvm.args}</argLine>\n                    </configuration>\n                </plugin>\n                <plugin>\n                    <groupId>net.alchim31.maven</groupId>\n                    <artifactId>scala-maven-plugin</artifactId>\n                    <version>${scala-maven-plugin.version}</version>\n                    <configuration>\n                        <scalaVersion>${scala.version}</scalaVersion>\n                        <scalaCompatVersion>${scala.binary.version}</scalaCompatVersion>\n                        <args>\n                            <arg>-target:jvm-1.8</arg>\n                        </args>\n                        <jvmArgs>\n                            <jvmArg>-Xms64m</jvmArg>\n                            <jvmArg>-Xmx1024m</jvmArg>\n                        </jvmArgs>\n                    </configuration>\n                    <executions>\n                        <execution>\n                            <id>scala-compile</id>\n                            <goals>\n                                <goal>add-source</goal>\n                                <goal>compile</goal>\n                                <goal>testCompile</goal>\n                                <goal>doc-jar</goal>\n                            </goals>\n                            <phase>process-resources</phase>\n                        </execution>\n                        <execution>\n                            <id>scala-test-compile</id>\n                            <goals>\n                                <goal>testCompile</goal>\n                            </goals>\n                            <phase>test-compile</phase>\n                        </execution>\n                    </executions>\n                </plugin>\n                <plugin>\n                    <artifactId>maven-assembly-plugin</artifactId>\n                    <version>3.8.0</version>\n                    <configuration>\n                        <descriptorRefs>\n                            <descriptorRef>jar-with-dependencies</descriptorRef>\n                        </descriptorRefs>\n                        <finalName>${project.artifactId}-${project.version}</finalName>\n                        <appendAssemblyId>false</appendAssemblyId>\n                    </configuration>\n                    <executions>\n                        <execution>\n                            <goals>\n                                <goal>single</goal>\n                            </goals>\n                            <phase>package</phase>\n                        </execution>\n                    </executions>\n                </plugin>\n                <plugin>\n                    <groupId>com.github.ekryd.sortpom</groupId>\n                    <artifactId>sortpom-maven-plugin</artifactId>\n                    <version>${sortpom-maven-plugin.version}</version>\n                    <configuration>\n                        <encoding>${project.build.sourceEncoding}</encoding>\n                        <keepBlankLines>false</keepBlankLines>\n                        <indentAttribute>schemaLocation</indentAttribute>\n                        <nrOfIndentSpace>4</nrOfIndentSpace>\n                        <sortProperties>true</sortProperties>\n                        <sortDependencies>scope,groupId,artifactId</sortDependencies>\n                        <createBackupFile>false</createBackupFile>\n                        <expandEmptyElements>false</expandEmptyElements>\n                    </configuration>\n                    <executions>\n                        <execution>\n                            <goals>\n                                <goal>verify</goal>\n                            </goals>\n                            <phase>validate</phase>\n                            <configuration>\n                                <verifyFail>STOP</verifyFail>\n                            </configuration>\n                        </execution>\n                    </executions>\n                </plugin>\n                <plugin>\n                    <groupId>com.diffplug.spotless</groupId>\n                    <artifactId>spotless-maven-plugin</artifactId>\n                    <version>${spotless-maven-plugin.version}</version>\n                    <configuration>\n                        <scala>\n                            <!-- These are the defaults, you can override if you want -->\n                            <includes>\n                                <include>src/main/scala/**/*.scala</include>\n                                <include>src/test/scala/**/*.scala</include>\n                            </includes>\n                            <scalafmt>\n                                <version>3.8.4-RC3</version>\n                                <file>scalafmt/scalafmt.conf</file>\n                                <scalaMajorVersion>2.12</scalaMajorVersion>\n                            </scalafmt>\n                        </scala>\n                    </configuration>\n                    <dependencies>\n                        <dependency>\n                            <groupId>org.neo4j.build</groupId>\n                            <artifactId>resources</artifactId>\n                            <version>${build-resources.version}</version>\n                        </dependency>\n                    </dependencies>\n                    <executions>\n                        <execution>\n                            <goals>\n                                <goal>check</goal>\n                            </goals>\n                            <phase>compile</phase>\n                        </execution>\n                    </executions>\n                </plugin>\n            </plugins>\n        </pluginManagement>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-enforcer-plugin</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n    <profiles>\n        <profile>\n            <id>scala-2.13</id>\n            <activation>\n                <property>\n                    <name>scala-2.13</name>\n                </property>\n            </activation>\n            <properties>\n                <scala.binary.version>2.13</scala.binary.version>\n                <scala.version>2.13.16</scala.version>\n            </properties>\n        </profile>\n        <!-- end scala profiles -->\n        <!-- spark profiles -->\n        <!-- end spark profiles -->\n        <profile>\n            <id>has-sources</id>\n            <activation>\n                <activeByDefault>false</activeByDefault>\n                <file>\n                    <exists>src</exists>\n                </file>\n            </activation>\n            <build>\n                <plugins>\n                    <plugin>\n                        <groupId>org.neo4j.build.plugins</groupId>\n                        <artifactId>licensing-maven-plugin</artifactId>\n                    </plugin>\n                    <plugin>\n                        <groupId>com.mycila</groupId>\n                        <artifactId>license-maven-plugin</artifactId>\n                    </plugin>\n                    <plugin>\n                        <groupId>org.apache.maven.plugins</groupId>\n                        <artifactId>maven-source-plugin</artifactId>\n                    </plugin>\n                </plugins>\n            </build>\n        </profile>\n        <profile>\n            <id>enable-jdk11-plugins</id>\n            <activation>\n                <jdk>[11,)</jdk>\n            </activation>\n            <properties>\n                <surefire.jvm.args>-XX:+IgnoreUnrecognizedVMOptions\n                    --add-opens=java.base/java.lang=ALL-UNNAMED\n                    --add-opens=java.base/java.lang.invoke=ALL-UNNAMED\n                    --add-opens=java.base/java.lang.reflect=ALL-UNNAMED\n                    --add-opens=java.base/java.io=ALL-UNNAMED\n                    --add-opens=java.base/java.net=ALL-UNNAMED\n                    --add-opens=java.base/java.nio=ALL-UNNAMED\n                    --add-opens=java.base/java.util=ALL-UNNAMED\n                    --add-opens=java.base/java.util.concurrent=ALL-UNNAMED\n                    --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED\n                    --add-opens=java.base/sun.nio.ch=ALL-UNNAMED\n                    --add-opens=java.base/sun.nio.cs=ALL-UNNAMED\n                    --add-opens=java.base/sun.security.action=ALL-UNNAMED\n                    --add-opens=java.base/sun.util.calendar=ALL-UNNAMED\n                    --add-opens=java.security.jgss/sun.security.krb5=ALL-UNNAMED\n                    -Djdk.reflect.useDirectMethodHandle=false</surefire.jvm.args>\n            </properties>\n            <build>\n                <plugins>\n                    <plugin>\n                        <groupId>com.github.ekryd.sortpom</groupId>\n                        <artifactId>sortpom-maven-plugin</artifactId>\n                    </plugin>\n                </plugins>\n            </build>\n        </profile>\n        <profile>\n            <id>enable-jdk17-plugins</id>\n            <activation>\n                <jdk>[17,)</jdk>\n            </activation>\n            <build>\n                <plugins>\n                    <plugin>\n                        <groupId>com.diffplug.spotless</groupId>\n                        <artifactId>spotless-maven-plugin</artifactId>\n                    </plugin>\n                </plugins>\n            </build>\n        </profile>\n    </profiles>\n</project>\n"
  },
  {
    "path": "scripts/python/requirements.txt",
    "content": "pyspark==3.5.5\ntestcontainers[neo4j]\nsix\ntzlocal==2.1"
  },
  {
    "path": "scripts/python/test_spark.py",
    "content": "#!/usr/bin/env python3\n\nimport unittest\nimport sys\nimport datetime\n\nfrom tzlocal import get_localzone\nfrom testcontainers.neo4j import Neo4jContainer\nfrom pyspark.sql import SparkSession\nfrom neo4j import Driver\n\n\nclass SparkTest(unittest.TestCase):\n    neo4j_driver: Driver = None\n    neo4j_container: Neo4jContainer = None\n    spark: SparkSession = None\n\n    def tearDown(self):\n        with self.neo4j_driver.session(database=\"system\") as session:\n            session.run(\"CREATE OR REPLACE DATABASE neo4j WAIT 30 seconds\").consume()\n\n    def init_test(self, query, parameters=None):\n        with self.neo4j_driver.session() as session:\n            session.run(query, parameters).consume()\n\n        return (\n            self.spark.read.format(\"org.neo4j.spark.DataSource\")\n            .option(\"url\", self.neo4j_container.get_connection_url())\n            .option(\"authentication.type\", \"basic\")\n            .option(\"authentication.basic.username\", \"neo4j\")\n            .option(\"authentication.basic.password\", \"password\")\n            .option(\"labels\", \"Person\")\n            .load()\n        )\n\n    def test_string(self):\n        name = \"Foobar\"\n        df = self.init_test(\"CREATE (p:Person {name: '\" + name + \"'})\")\n\n        assert name == df.select(\"name\").collect()[0].name\n\n    def test_int(self):\n        age = 32\n        df = self.init_test(\"CREATE (p:Person {age: \" + str(age) + \"})\")\n\n        assert age == df.select(\"age\").collect()[0].age\n\n    def test_double(self):\n        score = 32.3\n        df = self.init_test(\"CREATE (p:Person {score: \" + str(score) + \"})\")\n\n        assert score == df.select(\"score\").collect()[0].score\n\n    def test_boolean(self):\n        df = self.init_test(\"CREATE (p:Person {boolean: true})\")\n\n        assert True == df.select(\"boolean\").collect()[0].boolean\n\n    def test_time(self):\n        time = datetime.time(12, 23, 0, 0, get_localzone())\n        df = self.init_test(\n            \"CREATE (p:Person {myTime: time({hour:12, minute: 23, second: 0})})\"\n        )\n\n        timeResult = df.select(\"myTime\").collect()[0].myTime\n\n        assert \"offset-time\" == timeResult.type\n        # .replace used in case of UTC timezone because of https://stackoverflow.com/a/42777551/1409772\n        assert str(time).replace(\"+00:00\", \"Z\") == timeResult.value.split(\"+\")[0]\n\n    def test_datetime(self):\n        dtString = \"2015-06-24T12:50:35\"\n        df = self.init_test(\n            \"CREATE (p:Person {datetime: datetime('\" + dtString + \"')})\"\n        )\n\n        dt = datetime.datetime(2015, 6, 24, 12, 50, 35, 0)\n        dtResult = df.select(\"datetime\").collect()[0].datetime\n\n        assert dt == dtResult\n\n    def test_date(self):\n        df = self.init_test(\"CREATE (p:Person {born: date('2009-10-10')})\")\n\n        dt = datetime.date(2009, 10, 10)\n        dtResult = df.select(\"born\").collect()[0].born\n\n        assert dt == dtResult\n\n    def test_point(self):\n        df = self.init_test(\"CREATE (p:Person {location: point({x: 12.12, y: 13.13})})\")\n\n        pointResult = df.select(\"location\").collect()[0].location\n        assert \"point-2d\" == pointResult[0]\n        assert 7203 == pointResult[1]\n        assert 12.12 == pointResult[2]\n        assert 13.13 == pointResult[3]\n\n    def test_point3d(self):\n        df = self.init_test(\n            \"CREATE (p:Person {location: point({x: 12.12, y: 13.13, z: 1})})\"\n        )\n\n        pointResult = df.select(\"location\").collect()[0].location\n        assert \"point-3d\" == pointResult[0]\n        assert 9157 == pointResult[1]\n        assert 12.12 == pointResult[2]\n        assert 13.13 == pointResult[3]\n        assert 1.0 == pointResult[4]\n\n    def test_geopoint(self):\n        df = self.init_test(\n            \"CREATE (p:Person {location: point({longitude: 12.12, latitude: 13.13})})\"\n        )\n\n        pointResult = df.select(\"location\").collect()[0].location\n        assert \"point-2d\" == pointResult[0]\n        assert 4326 == pointResult[1]\n        assert 12.12 == pointResult[2]\n        assert 13.13 == pointResult[3]\n\n    def test_duration(self):\n        df = self.init_test(\n            \"CREATE (p:Person {range: duration({days: 14, hours:16, minutes: 12})})\"\n        )\n\n        durationResult = df.select(\"range\").collect()[0].range\n        assert \"duration\" == durationResult[0]\n        assert 0 == durationResult[1]\n        assert 14 == durationResult[2]\n        assert 58320 == durationResult[3]\n        assert 0 == durationResult[4]\n\n    def test_binary(self):\n        byte_array = b\"binaries are byte arrays\"\n        df = self.init_test(\"CREATE (p:Person {bin: $bytes})\", {\"bytes\": byte_array})\n\n        assert byte_array == df.select(\"bin\").collect()[0].bin\n\n    def test_string_array(self):\n        df = self.init_test(\"CREATE (p:Person {names: ['John', 'Doe']})\")\n\n        result = df.select(\"names\").collect()[0].names\n        assert \"John\" == result[0]\n        assert \"Doe\" == result[1]\n\n    def test_int_array(self):\n        df = self.init_test(\"CREATE (p:Person {ages: [24, 56]})\")\n\n        result = df.select(\"ages\").collect()[0].ages\n        assert 24 == result[0]\n        assert 56 == result[1]\n\n    def test_double_array(self):\n        df = self.init_test(\"CREATE (p:Person {scores: [24.11, 56.11]})\")\n\n        result = df.select(\"scores\").collect()[0].scores\n        assert 24.11 == result[0]\n        assert 56.11 == result[1]\n\n    def test_boolean_array(self):\n        df = self.init_test(\"CREATE (p:Person {field: [true, false]})\")\n\n        result = df.select(\"field\").collect()[0].field\n        assert True == result[0]\n        assert False == result[1]\n\n    def test_time_array(self):\n        df = self.init_test(\n            \"CREATE (p:Person {result: [time({hour:11, minute: 23, second: 0}), time({hour:12, minute: 23, second: 0})]})\"\n        )\n\n        timeResult = df.select(\"result\").collect()[0].result\n\n        # .replace used in case of UTC timezone because of https://stackoverflow.com/a/42777551/1409772\n        assert \"offset-time\" == timeResult[0].type\n        assert (\n            str(datetime.time(11, 23, 0, 0, get_localzone())).replace(\"+00:00\", \"Z\")\n            == timeResult[0].value.split(\"+\")[0]\n        )\n\n        # .replace used in case of UTC timezone because of https://stackoverflow.com/a/42777551/1409772\n        assert \"offset-time\" == timeResult[1].type\n        assert (\n            str(datetime.time(12, 23, 0, 0, get_localzone())).replace(\"+00:00\", \"Z\")\n            == timeResult[1].value.split(\"+\")[0]\n        )\n\n    def test_datetime_array(self):\n        df = self.init_test(\n            \"CREATE (p:Person {result: [datetime('2007-12-03T10:15:30'), datetime('2008-12-03T10:15:30')]})\"\n        )\n\n        dt1 = datetime.datetime(2007, 12, 3, 10, 15, 30, 0)\n        dt2 = datetime.datetime(2008, 12, 3, 10, 15, 30, 0)\n        dtResult = df.select(\"result\").collect()[0].result\n\n        assert dt1 == dtResult[0]\n        assert dt2 == dtResult[1]\n\n    def test_date_array(self):\n        df = self.init_test(\n            \"CREATE (p:Person {result: [date('2009-10-10'), date('2008-10-10')]})\"\n        )\n\n        dt1 = datetime.date(2009, 10, 10)\n        dt2 = datetime.date(2008, 10, 10)\n        dtResult = df.select(\"result\").collect()[0].result\n\n        assert dt1 == dtResult[0]\n        assert dt2 == dtResult[1]\n\n    def test_point_array(self):\n        df = self.init_test(\n            \"CREATE (p:Person {location: [point({x: 12.12, y: 13.13}), point({x: 13.13, y: 14.14})]})\"\n        )\n\n        pointResult = df.select(\"location\").collect()[0].location\n        assert \"point-2d\" == pointResult[0][0]\n        assert 7203 == pointResult[0][1]\n        assert 12.12 == pointResult[0][2]\n        assert 13.13 == pointResult[0][3]\n\n        assert \"point-2d\" == pointResult[1][0]\n        assert 7203 == pointResult[1][1]\n        assert 13.13 == pointResult[1][2]\n        assert 14.14 == pointResult[1][3]\n\n    def test_point3d_array(self):\n        df = self.init_test(\n            \"CREATE (p:Person {location: [point({x: 12.12, y: 13.13, z: 1}), point({x: 14.14, y: 15.15, z: 1})]})\"\n        )\n\n        pointResult = df.select(\"location\").collect()[0].location\n        assert \"point-3d\" == pointResult[0][0]\n        assert 9157 == pointResult[0][1]\n        assert 12.12 == pointResult[0][2]\n        assert 13.13 == pointResult[0][3]\n        assert 1.0 == pointResult[0][4]\n\n        assert \"point-3d\" == pointResult[1][0]\n        assert 9157 == pointResult[1][1]\n        assert 14.14 == pointResult[1][2]\n        assert 15.15 == pointResult[1][3]\n        assert 1.0 == pointResult[1][4]\n\n    def test_geopoint_array(self):\n        df = self.init_test(\n            \"CREATE (p:Person {location: [point({longitude: 12.12, latitude: 13.13}), point({longitude: 14.14, latitude: 15.15})]})\"\n        )\n\n        pointResult = df.select(\"location\").collect()[0].location\n        assert \"point-2d\" == pointResult[0][0]\n        assert 4326 == pointResult[0][1]\n        assert 12.12 == pointResult[0][2]\n        assert 13.13 == pointResult[0][3]\n\n        assert \"point-2d\" == pointResult[1][0]\n        assert 4326 == pointResult[1][1]\n        assert 14.14 == pointResult[1][2]\n        assert 15.15 == pointResult[1][3]\n\n    def test_duration_array(self):\n        df = self.init_test(\n            \"CREATE (p:Person {range: [duration({days: 14, hours:16, minutes: 12}), duration({days: 15, hours:16, minutes: 12})]})\"\n        )\n\n        durationResult = df.select(\"range\").collect()[0].range\n        assert \"duration\" == durationResult[0][0]\n        assert 0 == durationResult[0][1]\n        assert 14 == durationResult[0][2]\n        assert 58320 == durationResult[0][3]\n        assert 0 == durationResult[0][4]\n\n        assert \"duration\" == durationResult[1][0]\n        assert 0 == durationResult[1][1]\n        assert 15 == durationResult[1][2]\n        assert 58320 == durationResult[1][3]\n        assert 0 == durationResult[1][4]\n\n    def test_unexisting_property(self):\n        (\n            self.spark.read.format(\"org.neo4j.spark.DataSource\")\n            .option(\"url\", self.neo4j_container.get_connection_url())\n            .option(\"authentication.type\", \"basic\")\n            .option(\"authentication.basic.username\", \"neo4j\")\n            .option(\"authentication.basic.password\", \"password\")\n            .option(\"relationship.properties\", None)\n            .option(\"relationship\", \"FOO\")\n            .option(\"relationship.source.labels\", \":Foo\")\n            .option(\"relationship.target.labels\", \":Bar\")\n            .load()\n        )\n        # In this case we just test that the job has been executed without any exception\n\n    def test_gds(self):\n        with self.neo4j_driver.session() as session:\n            session.run(\n                \"\"\"\n                CREATE\n                  (home:Page {name:'Home'}),\n                  (about:Page {name:'About'}),\n                  (product:Page {name:'Product'}),\n                  (links:Page {name:'Links'}),\n                  (a:Page {name:'Site A'}),\n                  (b:Page {name:'Site B'}),\n                  (c:Page {name:'Site C'}),\n                  (d:Page {name:'Site D'}),\n\n                  (home)-[:LINKS {weight: 0.2}]->(about),\n                  (home)-[:LINKS {weight: 0.2}]->(links),\n                  (home)-[:LINKS {weight: 0.6}]->(product),\n                  (about)-[:LINKS {weight: 1.0}]->(home),\n                  (product)-[:LINKS {weight: 1.0}]->(home),\n                  (a)-[:LINKS {weight: 1.0}]->(home),\n                  (b)-[:LINKS {weight: 1.0}]->(home),\n                  (c)-[:LINKS {weight: 1.0}]->(home),\n                  (d)-[:LINKS {weight: 1.0}]->(home),\n                  (links)-[:LINKS {weight: 0.8}]->(home),\n                  (links)-[:LINKS {weight: 0.05}]->(a),\n                  (links)-[:LINKS {weight: 0.05}]->(b),\n                  (links)-[:LINKS {weight: 0.05}]->(c),\n                  (links)-[:LINKS {weight: 0.05}]->(d);\n            \"\"\"\n            )\n\n        (\n            self.spark.read.format(\"org.neo4j.spark.DataSource\")\n            .option(\"url\", self.neo4j_container.get_connection_url())\n            .option(\"authentication.type\", \"basic\")\n            .option(\"authentication.basic.username\", \"neo4j\")\n            .option(\"authentication.basic.password\", \"password\")\n            .option(\"gds\", \"gds.graph.project\")\n            .option(\"gds.graphName\", \"myGraph\")\n            .option(\"gds.nodeProjection\", \"Page\")\n            .option(\"gds.relationshipProjection\", \"LINKS\")\n            .option(\"gds.configuration.relationshipProperties\", \"weight\")\n            .load()\n            .show(truncate=False)\n        )\n\n        df = (\n            self.spark.read.format(\"org.neo4j.spark.DataSource\")\n            .option(\"url\", self.neo4j_container.get_connection_url())\n            .option(\"authentication.type\", \"basic\")\n            .option(\"authentication.basic.username\", \"neo4j\")\n            .option(\"authentication.basic.password\", \"password\")\n            .option(\"gds\", \"gds.pageRank.stream\")\n            .option(\"gds.graphName\", \"myGraph\")\n            .option(\"gds.configuration.concurrency\", \"2\")\n            .load()\n        )\n\n        assert 8 == df.count()\n\n\nif len(sys.argv) != 3:\n    print(\"Wrong arguments count\")\n    print(sys.argv)\n    sys.exit(1)\n\nneo4j_image = str(sys.argv.pop())\nconnector_jar = str(sys.argv.pop())\ncurrent_time_zone = get_localzone().zone\n\nif __name__ == \"__main__\":\n    with (\n        Neo4jContainer(neo4j_image)\n        .with_env(\"NEO4J_ACCEPT_LICENSE_AGREEMENT\", \"yes\")\n        .with_env(\"NEO4J_db_temporal_timezone\", current_time_zone)\n        .with_env(\"NEO4JLABS_PLUGINS\", '[\"graph-data-science\"]')\n    ) as neo4j_container:\n        with neo4j_container.get_driver() as neo4j_driver:\n            SparkTest.spark = (\n                SparkSession.builder.appName(\"Neo4jConnectorTests\")\n                .master(\"local[*]\")\n                .config(\"spark.jars\", connector_jar)\n                .config(\"spark.driver.host\", \"127.0.0.1\")\n                .getOrCreate()\n            )\n            SparkTest.neo4j_driver = neo4j_driver\n            SparkTest.neo4j_container = neo4j_container\n            unittest.main()\n            SparkTest.spark.close()\n"
  },
  {
    "path": "scripts/release/upload_to_spark_packages.sh",
    "content": "#!/bin/bash\n\nset -eEuo pipefail\n\nif [[ $# -lt 5 ]] ; then\n    echo \"Usage ./upload_to_spark_packages.sh <USER> <TOKEN> <GIT_HASH> <VERSION> <PATH_TO_PACKAGE_FILE>\"\n    exit 1\nfi\n\nUSER=$1\nTOKEN=$2\nGIT_HASH=$3\nVERSION=$4\nPATH_TO_PACKAGE_FILE=$5\n\n# License codes expected:\n#   0 - Apache 2.0\n#   1 - BSD 3-Clause\n#   2 - BSD 2-Clause\n#   3 - GPL-2.0\n#   4 - GPL-3.0\n#   5 - LGPL-2.1\n#   6 - LGPL-3.0\n#   7 - MIT\n#   8 - MPL-2.0\n#   9 - EPL-1.0\n#   10 - Other license\nLICENSE=\"0\"\n\ncurl -X POST 'https://spark-packages.org/api/submit-release' \\\n  -u \"$USER:$TOKEN\" \\\n  -F \"git_commit_sha1=$GIT_HASH\" \\\n  -F \"version=$VERSION\" \\\n  -F \"license_id=$LICENSE\" \\\n  -F \"name=neo4j/neo4j-spark-connector\" \\\n  -F \"artifact_zip=@$PATH_TO_PACKAGE_FILE;type=application/zip\"\n"
  },
  {
    "path": "spark-3/LICENSES.txt",
    "content": "This file contains the full license text of the included third party\nlibraries. For an overview of the licenses see the NOTICE.txt file.\n\n\n------------------------------------------------------------------------------\nApache Software License, Version 2.0\n  JetBrains Java Annotations\n  Kotlin Stdlib\n  Netty/Buffer\n  Netty/Codec\n  Netty/Common\n  Netty/Handler\n  Netty/Resolver\n  Netty/TomcatNative [OpenSSL - Classes]\n  Netty/Transport\n  Netty/Transport/Native/Unix/Common\n  Non-Blocking Reactive Foundation for the JVM\n  org.apiguardian:apiguardian-api\n------------------------------------------------------------------------------\n\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n\n\n\n------------------------------------------------------------------------------\nMIT License\n  SLF4J API Module\n------------------------------------------------------------------------------\n\nThe MIT License\n\nCopyright (c) <year> <copyright holders>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n\n\n\n------------------------------------------------------------------------------\nMIT No Attribution License\n  reactive-streams\n------------------------------------------------------------------------------\n\nMIT No Attribution\n\nCopyright <year> <copyright holders>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this\nsoftware and associated documentation files (the \"Software\"), to deal in the Software\nwithout restriction, including without limitation the rights to use, copy, modify,\nmerge, publish, distribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\nINCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A\nPARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\nHOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\n\n\n"
  },
  {
    "path": "spark-3/NOTICE.txt",
    "content": "Copyright (c) \"Neo4j\"\nNeo4j Sweden AB [https://neo4j.com]\n\nThis file is part of Neo4j.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n\nFull license texts are found in LICENSES.txt.\n\n\nThird-party licenses\n--------------------\n\nApache Software License, Version 2.0\n  JetBrains Java Annotations\n  Kotlin Stdlib\n  Netty/Buffer\n  Netty/Codec\n  Netty/Common\n  Netty/Handler\n  Netty/Resolver\n  Netty/TomcatNative [OpenSSL - Classes]\n  Netty/Transport\n  Netty/Transport/Native/Unix/Common\n  Non-Blocking Reactive Foundation for the JVM\n  org.apiguardian:apiguardian-api\n\nMIT License\n  SLF4J API Module\n\nMIT No Attribution License\n  reactive-streams\n\n"
  },
  {
    "path": "spark-3/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n        xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.neo4j</groupId>\n        <artifactId>neo4j-connector-apache-spark_parent</artifactId>\n        <version>5.4.3-SNAPSHOT</version>\n    </parent>\n    <artifactId>neo4j-connector-apache-spark</artifactId>\n    <packaging>jar</packaging>\n    <name>neo4j-connector-apache-spark-${spark.version}</name>\n    <description>Spark ${spark.version} for Neo4j Connector for Apache Spark using the binary Bolt Driver</description>\n    <properties>\n        <spark-packages.artifactId>neo4j-spark-connector</spark-packages.artifactId>\n        <spark-packages.groupId>neo4j</spark-packages.groupId>\n        <spark-packages.packageName>${spark-packages.artifactId}-${spark-packages.version}</spark-packages.packageName>\n        <spark-packages.version/>\n    </properties>\n    <dependencies>\n        <dependency>\n            <groupId>org.neo4j</groupId>\n            <artifactId>neo4j-connector-apache-spark_common</artifactId>\n            <version>${project.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.neo4j.driver</groupId>\n            <artifactId>neo4j-java-driver-slim</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.spark</groupId>\n            <artifactId>spark-core_${scala.binary.version}</artifactId>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.spark</groupId>\n            <artifactId>spark-sql_${scala.binary.version}</artifactId>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.scala-lang</groupId>\n            <artifactId>scala-library</artifactId>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.scala-lang</groupId>\n            <artifactId>scala-reflect</artifactId>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.neo4j</groupId>\n            <artifactId>neo4j-connector-apache-spark_test-support</artifactId>\n            <version>${project.version}</version>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.neo4j.connectors</groupId>\n            <artifactId>commons-authn-keycloak</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.scalatest</groupId>\n            <artifactId>scalatest_${scala.binary.version}</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>pl.pragmatists</groupId>\n            <artifactId>JUnitParams</artifactId>\n            <version>1.1.1</version>\n            <scope>test</scope>\n        </dependency>\n    </dependencies>\n    <build>\n        <resources>\n            <resource>\n                <filtering>true</filtering>\n                <directory>src/main/resources</directory>\n            </resource>\n        </resources>\n        <plugins>\n            <plugin>\n                <groupId>net.alchim31.maven</groupId>\n                <artifactId>scala-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-failsafe-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-resources-plugin</artifactId>\n                <version>${maven-resources-plugin.version}</version>\n                <configuration>\n                    <encoding>ISO-8859-1</encoding>\n                    <propertiesEncoding>${project.build.sourceEncoding}</propertiesEncoding>\n                </configuration>\n            </plugin>\n            <plugin>\n                <artifactId>maven-assembly-plugin</artifactId>\n                <version>3.8.0</version>\n                <executions>\n                    <execution>\n                        <id>bin</id>\n                        <goals>\n                            <goal>single</goal>\n                        </goals>\n                        <phase>package</phase>\n                        <configuration>\n                            <descriptors>\n                                <descriptor>src/main/assemblies/spark-packages-assembly.xml</descriptor>\n                            </descriptors>\n                            <appendAssemblyId>false</appendAssemblyId>\n                            <finalName>${spark-packages.packageName}</finalName>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "spark-3/src/jreleaser/assemblers/zip/README.txt.tpl",
    "content": "Neo4j Connector for Apache Spark {{projectVersion}}\n\nThis archive contains release materials for the Neo4j Connector for Apache Spark.\n\n**Make sure you use the correct JAR, depending on the Scala version in use in your\nspark environment**\n\nSource Code & Release Notes: https://github.com/neo4j/neo4j-spark-connector/releases\nDocumentation: https://neo4j.com/docs/spark/current/\n\nNeed Support?   Have a Question?\n\nIf you are a Neo4j Enterprise customer, please have a look at the enterprise\nknowledge base, or contact Neo4j Professional Support through:\nhttps://support.neo4j.com/hc/en-us\n\nOtherwise, please consider posting a question on the Neo4j Community site:\nhttps://community.neo4j.com/"
  },
  {
    "path": "spark-3/src/main/assemblies/spark-packages-assembly.xml",
    "content": "<assembly xmlns=\"http://maven.apache.org/ASSEMBLY/2.2.0\"\n          xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n          xsi:schemaLocation=\"http://maven.apache.org/ASSEMBLY/2.2.0 https://maven.apache.org/xsd/assembly-2.2.0.xsd\">\n    <id>bin</id>\n\n    <formats>\n        <format>zip</format>\n    </formats>\n\n    <includeBaseDirectory>false</includeBaseDirectory>\n\n    <files>\n        <file>\n            <source>${project.build.directory}/${project.artifactId}-${project.version}.jar</source>\n            <outputDirectory>/</outputDirectory>\n            <destName>${spark-packages.packageName}.jar</destName>\n        </file>\n        <file>\n            <filtered>true</filtered>\n            <source>src/main/distributions/spark-packages.pom</source>\n            <outputDirectory>/</outputDirectory>\n            <destName>${spark-packages.packageName}.pom</destName>\n        </file>\n    </files>\n\n</assembly>\n"
  },
  {
    "path": "spark-3/src/main/distributions/spark-packages.pom",
    "content": "<project>\n    <modelVersion>4.0.0</modelVersion>\n    <groupId>${spark-packages.groupId}</groupId>\n    <artifactId>${spark-packages.artifactId}</artifactId>\n    <version>${spark-packages.version}</version>\n</project>\n"
  },
  {
    "path": "spark-3/src/main/resources/META-INF/services/org.apache.spark.sql.sources.DataSourceRegister",
    "content": "org.neo4j.spark.DataSource"
  },
  {
    "path": "spark-3/src/main/resources/neo4j-spark-connector.properties",
    "content": "version=${project.version}"
  },
  {
    "path": "spark-3/src/main/scala/org/neo4j/spark/DataSource.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark\n\nimport org.apache.spark.sql.SparkSession\nimport org.apache.spark.sql.connector.catalog.Table\nimport org.apache.spark.sql.connector.catalog.TableProvider\nimport org.apache.spark.sql.connector.expressions.Transform\nimport org.apache.spark.sql.sources.DataSourceRegister\nimport org.apache.spark.sql.sources.Filter\nimport org.apache.spark.sql.types.StructType\nimport org.apache.spark.sql.util.CaseInsensitiveStringMap\nimport org.neo4j.caniuse.Neo4j\nimport org.neo4j.caniuse.Neo4jDetector\nimport org.neo4j.spark.util.DriverCache\nimport org.neo4j.spark.util.Neo4jDriverOptions\nimport org.neo4j.spark.util.Neo4jOptions\nimport org.neo4j.spark.util.Neo4jUtil\nimport org.neo4j.spark.util.ValidateConnection\nimport org.neo4j.spark.util.ValidateSparkMinVersion\nimport org.neo4j.spark.util.Validations\n\nimport java.util.UUID\n\nclass DataSource extends TableProvider\n    with DataSourceRegister {\n\n  Validations.validate(ValidateSparkMinVersion(\"3.3.0\"))\n\n  private val jobId: String = UUID.randomUUID().toString\n\n  private var schema: StructType = _\n\n  private var neo4jOptions: Neo4jOptions = _\n\n  private var neo4j: Neo4j = _\n\n  override def supportsExternalMetadata(): Boolean = true\n\n  override def inferSchema(caseInsensitiveStringMap: CaseInsensitiveStringMap): StructType = {\n    if (schema == null) {\n      val neo4jOpts = getNeo4jOptions(caseInsensitiveStringMap)\n      Validations.validate(ValidateConnection(neo4jOpts, jobId))\n      val neo4j = getNeo4jInfo(neo4jOpts.connection)\n      schema =\n        Neo4jUtil.callSchemaService(\n          neo4j,\n          neo4jOpts,\n          jobId,\n          Array.empty[Filter],\n          { schemaService =>\n            schemaService.struct()\n          }\n        )\n    }\n\n    schema\n  }\n\n  private def getNeo4jInfo(options: Neo4jDriverOptions): Neo4j = {\n    if (neo4j == null) {\n      val driver = new DriverCache(options).getOrCreate()\n      neo4j = Neo4jDetector.INSTANCE.detect(driver)\n    }\n    neo4j\n  }\n\n  private def getNeo4jOptions(caseInsensitiveStringMap: CaseInsensitiveStringMap) = {\n    if (neo4jOptions == null) {\n      neo4jOptions =\n        Neo4jOptions.fromSession(SparkSession.getActiveSession, caseInsensitiveStringMap.asCaseSensitiveMap())\n    }\n\n    neo4jOptions\n  }\n\n  override def getTable(\n    structType: StructType,\n    transforms: Array[Transform],\n    map: java.util.Map[String, String]\n  ): Table = {\n    val caseInsensitiveStringMapNeo4jOptions = new CaseInsensitiveStringMap(map)\n    val schema = if (structType != null) {\n      structType\n    } else {\n      inferSchema(caseInsensitiveStringMapNeo4jOptions)\n    }\n    val neo4jOpts = getNeo4jOptions(caseInsensitiveStringMapNeo4jOptions)\n    val neo4jInfo = getNeo4jInfo(neo4jOpts.connection)\n    new Neo4jTable(neo4jInfo, schema, neo4jOpts, jobId)\n  }\n\n  override def shortName(): String = \"neo4j\"\n}\n"
  },
  {
    "path": "spark-3/src/main/scala/org/neo4j/spark/Neo4jTable.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark\n\nimport org.apache.spark.internal.Logging\nimport org.apache.spark.sql.SaveMode\nimport org.apache.spark.sql.connector.catalog.SupportsRead\nimport org.apache.spark.sql.connector.catalog.SupportsWrite\nimport org.apache.spark.sql.connector.catalog.Table\nimport org.apache.spark.sql.connector.catalog.TableCapability\nimport org.apache.spark.sql.connector.write.LogicalWriteInfo\nimport org.apache.spark.sql.connector.write.WriteBuilder\nimport org.apache.spark.sql.types.StructType\nimport org.apache.spark.sql.util.CaseInsensitiveStringMap\nimport org.neo4j.caniuse.Neo4j\nimport org.neo4j.driver.AccessMode\nimport org.neo4j.spark.reader.Neo4jScanBuilder\nimport org.neo4j.spark.util.Neo4jOptions\nimport org.neo4j.spark.util.ValidateRead\nimport org.neo4j.spark.util.Validations\nimport org.neo4j.spark.writer.Neo4jWriterBuilder\n\nimport scala.collection.JavaConverters._\n\nclass Neo4jTable(neo4j: Neo4j, schema: StructType, neo4jOptions: Neo4jOptions, jobId: String)\n    extends Table\n    with SupportsRead\n    with SupportsWrite\n    with Logging {\n\n  override def name(): String = neo4jOptions.getTableName\n\n  override def schema(): StructType = schema\n\n  override def capabilities(): java.util.Set[TableCapability] = Set(\n    TableCapability.BATCH_READ,\n    TableCapability.BATCH_WRITE,\n    TableCapability.ACCEPT_ANY_SCHEMA,\n    TableCapability.OVERWRITE_BY_FILTER,\n    TableCapability.OVERWRITE_DYNAMIC,\n    TableCapability.STREAMING_WRITE,\n    TableCapability.MICRO_BATCH_READ\n  ).asJava\n\n  override def newScanBuilder(options: CaseInsensitiveStringMap): Neo4jScanBuilder = {\n    Validations.validate(ValidateRead(neo4j, neo4jOptions, jobId))\n    new Neo4jScanBuilder(neo4j, neo4jOptions, jobId, schema())\n  }\n\n  override def newWriteBuilder(info: LogicalWriteInfo): WriteBuilder = {\n    val mapOptions = neo4jOptions.asMap()\n    mapOptions.put(Neo4jOptions.ACCESS_MODE, AccessMode.WRITE.toString)\n    val writeNeo4jOptions = new Neo4jOptions(mapOptions)\n    new Neo4jWriterBuilder(neo4j, info.queryId(), info.schema(), SaveMode.Append, writeNeo4jOptions)\n  }\n}\n"
  },
  {
    "path": "spark-3/src/main/scala/org/neo4j/spark/reader/Neo4jPartitionReader.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark.reader\n\nimport org.apache.spark.sql.catalyst.InternalRow\nimport org.apache.spark.sql.connector.expressions.aggregate.AggregateFunc\nimport org.apache.spark.sql.connector.read.PartitionReader\nimport org.apache.spark.sql.sources.Filter\nimport org.apache.spark.sql.types.StructType\nimport org.neo4j.caniuse.Neo4j\nimport org.neo4j.spark.service.PartitionPagination\nimport org.neo4j.spark.util.Neo4jOptions\n\nclass Neo4jPartitionReader(\n  private val neo4j: Neo4j,\n  private val options: Neo4jOptions,\n  private val filters: Array[Filter],\n  private val schema: StructType,\n  private val jobId: String,\n  private val partitionSkipLimit: PartitionPagination,\n  private val scriptResult: java.util.List[java.util.Map[String, AnyRef]],\n  private val requiredColumns: StructType,\n  private val aggregateColumns: Array[AggregateFunc]\n) extends BasePartitionReader(\n      neo4j,\n      options,\n      filters,\n      schema,\n      jobId,\n      partitionSkipLimit,\n      scriptResult,\n      requiredColumns,\n      aggregateColumns\n    )\n    with PartitionReader[InternalRow]\n"
  },
  {
    "path": "spark-3/src/main/scala/org/neo4j/spark/reader/Neo4jPartitionReaderFactory.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark.reader\n\nimport org.apache.spark.sql.catalyst.InternalRow\nimport org.apache.spark.sql.connector.expressions.aggregate.AggregateFunc\nimport org.apache.spark.sql.connector.read.InputPartition\nimport org.apache.spark.sql.connector.read.PartitionReader\nimport org.apache.spark.sql.connector.read.PartitionReaderFactory\nimport org.apache.spark.sql.sources.Filter\nimport org.apache.spark.sql.types.StructType\nimport org.neo4j.caniuse.Neo4j\nimport org.neo4j.spark.service.PartitionPagination\nimport org.neo4j.spark.util.Neo4jOptions\n\nclass Neo4jPartitionReaderFactory(\n  private val neo4j: Neo4j,\n  private val neo4jOptions: Neo4jOptions,\n  private val filters: Array[Filter],\n  private val schema: StructType,\n  private val jobId: String,\n  private val scriptResult: java.util.List[java.util.Map[String, AnyRef]],\n  private val requiredColumns: StructType,\n  private val aggregateColumns: Array[AggregateFunc]\n) extends PartitionReaderFactory {\n\n  override def createReader(partition: InputPartition): PartitionReader[InternalRow] = new Neo4jPartitionReader(\n    neo4j,\n    neo4jOptions,\n    filters,\n    schema,\n    jobId,\n    partition.asInstanceOf[Neo4jPartition].partitionSkipLimit,\n    scriptResult,\n    requiredColumns,\n    aggregateColumns\n  )\n}\n"
  },
  {
    "path": "spark-3/src/main/scala/org/neo4j/spark/reader/Neo4jScan.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark.reader\n\nimport org.apache.spark.sql.connector.expressions.aggregate.AggregateFunc\nimport org.apache.spark.sql.connector.read.Batch\nimport org.apache.spark.sql.connector.read.InputPartition\nimport org.apache.spark.sql.connector.read.PartitionReaderFactory\nimport org.apache.spark.sql.connector.read.Scan\nimport org.apache.spark.sql.connector.read.streaming.MicroBatchStream\nimport org.apache.spark.sql.sources.Filter\nimport org.apache.spark.sql.types.StructType\nimport org.neo4j.caniuse.Neo4j\nimport org.neo4j.spark.config.TopN\nimport org.neo4j.spark.service.PartitionPagination\nimport org.neo4j.spark.streaming.Neo4jMicroBatchReader\nimport org.neo4j.spark.util.Neo4jOptions\nimport org.neo4j.spark.util.Neo4jUtil\nimport org.neo4j.spark.util.ValidateReadNotStreaming\nimport org.neo4j.spark.util.ValidateReadStreaming\nimport org.neo4j.spark.util.Validations\n\ncase class Neo4jPartition(partitionSkipLimit: PartitionPagination) extends InputPartition\n\nclass Neo4jScan(\n  neo4j: Neo4j,\n  neo4jOptions: Neo4jOptions,\n  jobId: String,\n  schema: StructType,\n  filters: Array[Filter],\n  requiredColumns: StructType,\n  aggregateColumns: Array[AggregateFunc],\n  topN: Option[TopN]\n) extends Scan with Batch {\n\n  override def toBatch: Batch = this\n\n  var scriptResult: java.util.List[java.util.Map[String, AnyRef]] = _\n\n  private def createPartitions() = {\n    Validations.validate(ValidateReadNotStreaming(neo4jOptions, jobId))\n    // we get the skip/limit for each partition and execute the \"script\"\n    val (partitionSkipLimitList, scriptResult) = Neo4jUtil.callSchemaService(\n      neo4j,\n      neo4jOptions,\n      jobId,\n      filters,\n      { schemaService =>\n        (schemaService.skipLimitFromPartition(topN), schemaService.execute(neo4jOptions.script))\n      }\n    )\n    // we generate a partition for each element\n    this.scriptResult = scriptResult\n    partitionSkipLimitList\n      .map(partitionSkipLimit => Neo4jPartition(partitionSkipLimit))\n  }\n\n  override def planInputPartitions(): Array[InputPartition] = {\n    val neo4jPartitions: Seq[Neo4jPartition] = createPartitions()\n    neo4jPartitions.toArray\n  }\n\n  override def createReaderFactory(): PartitionReaderFactory = {\n    new Neo4jPartitionReaderFactory(\n      neo4j,\n      neo4jOptions,\n      filters,\n      schema,\n      jobId,\n      scriptResult,\n      requiredColumns,\n      aggregateColumns\n    )\n  }\n\n  override def readSchema(): StructType = schema\n\n  override def toMicroBatchStream(checkpointLocation: String): MicroBatchStream = {\n    Validations.validate(ValidateReadStreaming(neo4j, neo4jOptions, jobId))\n    new Neo4jMicroBatchReader(neo4j, schema, neo4jOptions, jobId, aggregateColumns)\n  }\n}\n"
  },
  {
    "path": "spark-3/src/main/scala/org/neo4j/spark/reader/Neo4jScanBuilder.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark.reader\n\nimport org.apache.spark.internal.Logging\nimport org.apache.spark.sql.connector.expressions.Expression\nimport org.apache.spark.sql.connector.expressions.SortOrder\nimport org.apache.spark.sql.connector.expressions.aggregate.AggregateFunc\nimport org.apache.spark.sql.connector.expressions.aggregate.Aggregation\nimport org.apache.spark.sql.connector.expressions.filter.Predicate\nimport org.apache.spark.sql.connector.read.Scan\nimport org.apache.spark.sql.connector.read.SupportsPushDownAggregates\nimport org.apache.spark.sql.connector.read.SupportsPushDownLimit\nimport org.apache.spark.sql.connector.read.SupportsPushDownRequiredColumns\nimport org.apache.spark.sql.connector.read.SupportsPushDownTopN\nimport org.apache.spark.sql.connector.read.SupportsPushDownV2Filters\nimport org.apache.spark.sql.types.LongType\nimport org.apache.spark.sql.types.StructField\nimport org.apache.spark.sql.types.StructType\nimport org.neo4j.caniuse.Neo4j\nimport org.neo4j.spark.config.TopN\nimport org.neo4j.spark.util.Neo4jImplicits.AggregationImplicit\nimport org.neo4j.spark.util.Neo4jImplicits.CypherImplicits\nimport org.neo4j.spark.util.Neo4jImplicits.PredicateImplicit\nimport org.neo4j.spark.util.Neo4jOptions\nimport org.neo4j.spark.util.QueryType\n\nclass Neo4jScanBuilder(neo4jInfo: Neo4j, neo4jOptions: Neo4jOptions, jobId: String, schema: StructType)\n    extends SupportsPushDownV2Filters\n    with SupportsPushDownAggregates\n    with SupportsPushDownRequiredColumns\n    with SupportsPushDownLimit\n    with SupportsPushDownTopN\n    with Logging {\n\n  private var predicates: Array[Predicate] = Array.empty\n\n  private var requiredSchema: StructType = schema\n  private var requiredColumns: StructType = new StructType()\n\n  private var aggregateColumns: Array[AggregateFunc] = Array.empty[AggregateFunc]\n  private var limit: Option[Int] = None\n  private var topN: Option[TopN] = None\n\n  override def build(): Scan = {\n    new Neo4jScan(\n      neo4jInfo,\n      neo4jOptions,\n      jobId,\n      requiredSchema,\n      predicates.flatMap(_.toFilter(neo4jOptions)),\n      requiredColumns,\n      aggregateColumns,\n      topN.orElse(limit.map((limit: Int) => TopN(limit)))\n    )\n  }\n\n  override def pushPredicates(predicatesArray: Array[Predicate]): Array[Predicate] = {\n    if (neo4jOptions.pushdownFiltersEnabled) {\n      predicates = predicatesArray\n    }\n\n    predicatesArray\n  }\n\n  override def pushedPredicates(): Array[Predicate] = predicates\n\n  override def pruneColumns(newSchema: StructType): Unit = {\n    if (!neo4jOptions.pushdownColumnsEnabled || neo4jOptions.relationshipMetadata.nodeMap) {\n      new StructType()\n    } else {\n      requiredColumns = StructType(requiredSchema.filter(sf => newSchema.contains(sf)))\n    }\n  }\n\n  override def pushAggregation(aggregation: Aggregation): Boolean = {\n    if (\n      !neo4jOptions.pushdownAggregateEnabled\n      || aggregation.aggregateExpressions().isEmpty\n      || neo4jOptions.query.queryType == QueryType.QUERY\n    ) {\n      return false\n    }\n    aggregateColumns = aggregation.aggregateExpressions()\n    val groupByColumns: Set[String] = aggregation.groupByCols()\n      .map(_.describe().unquote())\n      .toSet\n    requiredColumns = StructType(requiredSchema.filter(field => groupByColumns.contains(field.name)))\n\n    aggregateColumns.foreach(af => {\n      val fields =\n        try {\n          af.children()\n            .toSet[Expression]\n            .map(_.describe())\n            .map(_.unquote())\n        } catch {\n          // for making it compatible with Spark 3.2\n          case noSuchMethodException: NoSuchMethodError => Set(af.describe().unquote())\n        }\n      val dt = if (fields.nonEmpty) {\n        requiredSchema.filter(field => fields.contains(field.name))\n          .map(_.dataType)\n          .toSet\n          .headOption\n          .getOrElse(LongType)\n      } else {\n        LongType\n      }\n      requiredColumns = requiredColumns.add(StructField(af.toString, dt))\n    })\n    requiredSchema = requiredColumns\n    true\n  }\n\n  override def pushLimit(pushedLimit: Int): Boolean = {\n    if (!neo4jOptions.pushdownLimitEnabled) {\n      return false\n    }\n    if (neo4jOptions.partitions > 1) {\n      logWarning(\n        s\"\"\"Disabling pushed down limit support since it conflicts with partitioning.\n           |Set the `${Neo4jOptions.PARTITIONS}` parameter value to 1\n           | or set `${Neo4jOptions.PUSHDOWN_LIMIT_ENABLED}` to false to remove this warning.\n           |\"\"\".stripMargin\n      )\n      return false\n    }\n    if (pushedLimit <= 0) {\n      logWarning(s\"Ignoring negative pushed down limit $pushedLimit.\")\n      return false\n    }\n    limit = Some(pushedLimit)\n    true\n  }\n\n  override def pushTopN(orders: Array[SortOrder], limit: Int): Boolean = {\n    if (!neo4jOptions.pushdownTopNEnabled) {\n      return false\n    }\n    if (limit > 0 && neo4jOptions.partitions > 1) {\n      logWarning(\"disabling pushed down top N support since it conflicts with partitioning.\" +\n        \"set the partition count to 1 or disable the pushdown limit support to remove this warning\")\n      return false\n    }\n    topN = Some(TopN(limit, orders))\n    true\n  }\n\n  // otherwise doesn't compile in Scala 2.12\n  override def isPartiallyPushed: Boolean = true\n}\n"
  },
  {
    "path": "spark-3/src/main/scala/org/neo4j/spark/streaming/Neo4jMicroBatchReader.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark.streaming\n\nimport org.apache.spark.internal.Logging\nimport org.apache.spark.sql.connector.expressions.aggregate.AggregateFunc\nimport org.apache.spark.sql.connector.read.InputPartition\nimport org.apache.spark.sql.connector.read.PartitionReaderFactory\nimport org.apache.spark.sql.connector.read.streaming.MicroBatchStream\nimport org.apache.spark.sql.connector.read.streaming.Offset\nimport org.apache.spark.sql.sources.Filter\nimport org.apache.spark.sql.sources.GreaterThan\nimport org.apache.spark.sql.sources.LessThanOrEqual\nimport org.apache.spark.sql.types.StructType\nimport org.neo4j.caniuse.Neo4j\nimport org.neo4j.spark.service.SchemaService\nimport org.neo4j.spark.util._\n\nclass Neo4jMicroBatchReader(\n  private val neo4j: Neo4j,\n  private val schema: StructType,\n  private val neo4jOptions: Neo4jOptions,\n  private val jobId: String,\n  private val aggregateColumns: Array[AggregateFunc]\n) extends MicroBatchStream\n    with Logging {\n\n  private val driverCache = new DriverCache(neo4jOptions.connection)\n\n  private lazy val scriptResult = {\n    val schemaService = new SchemaService(neo4j, neo4jOptions, driverCache)\n    schemaService.createOptimizations(schema)\n    val scriptResult = schemaService.execute(neo4jOptions.script)\n    schemaService.close()\n    scriptResult\n  }\n\n  private var filters: Array[Filter] = Array.empty[Filter]\n\n  override def deserializeOffset(json: String): Offset = Neo4jOffset(json.toLong)\n\n  override def commit(end: Offset): Unit = {}\n\n  override def planInputPartitions(start: Offset, end: Offset): Array[InputPartition] = {\n    logDebug(s\"start and end offset: $start - $end\")\n\n    val prop = Neo4jUtil.getStreamingPropertyName(neo4jOptions)\n    this.filters =\n      Array(\n        GreaterThan(prop, start.asInstanceOf[Neo4jOffset].offset),\n        LessThanOrEqual(prop, end.asInstanceOf[Neo4jOffset].offset)\n      )\n\n    val partitions = Neo4jUtil.callSchemaService(\n      neo4j,\n      neo4jOptions,\n      jobId,\n      filters,\n      { schemaService => schemaService.skipLimitFromPartition(None) }\n    )\n\n    partitions\n      .map(p => Neo4jStreamingPartition(p, filters))\n      .toArray\n  }\n\n  override def stop(): Unit = {\n    driverCache.close()\n  }\n\n  override def latestOffset(): Offset = {\n    val offsetValue = Neo4jUtil.callSchemaService[Option[Long]](\n      neo4j,\n      neo4jOptions,\n      jobId,\n      filters,\n      {\n        schemaService =>\n          try {\n            schemaService.lastOffset()\n          } catch {\n            case _: Throwable => null\n          }\n      }\n    )\n    offsetValue.map(value => Neo4jOffset(value)).orNull\n  }\n\n  override def initialOffset(): Offset = Neo4jOffset(neo4jOptions.streamingOptions.from.value())\n\n  override def createReaderFactory(): PartitionReaderFactory = {\n    new Neo4jStreamingPartitionReaderFactory(\n      neo4j,\n      neo4jOptions,\n      schema,\n      jobId,\n      scriptResult,\n      aggregateColumns\n    )\n  }\n}\n"
  },
  {
    "path": "spark-3/src/main/scala/org/neo4j/spark/streaming/Neo4jOffset.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark.streaming\n\nimport org.apache.spark.sql.connector.read.streaming.Offset\n\ncase class Neo4jOffset(offset: Long) extends Offset {\n  override def json(): String = offset.toString\n}\n"
  },
  {
    "path": "spark-3/src/main/scala/org/neo4j/spark/streaming/Neo4jStreamingDataWriterFactory.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark.streaming\n\nimport org.apache.spark.sql.SaveMode\nimport org.apache.spark.sql.catalyst.InternalRow\nimport org.apache.spark.sql.connector.write.DataWriter\nimport org.apache.spark.sql.connector.write.streaming.StreamingDataWriterFactory\nimport org.apache.spark.sql.types.StructType\nimport org.neo4j.caniuse.Neo4j\nimport org.neo4j.spark.util.Neo4jOptions\nimport org.neo4j.spark.writer.Neo4jDataWriter\n\nclass Neo4jStreamingDataWriterFactory(\n  neo4j: Neo4j,\n  jobId: String,\n  schema: StructType,\n  saveMode: SaveMode,\n  options: Neo4jOptions,\n  scriptResult: java.util.List[java.util.Map[String, AnyRef]]\n) extends StreamingDataWriterFactory {\n\n  override def createWriter(partitionId: Int, taskId: Long, epochId: Long): DataWriter[InternalRow] =\n    new Neo4jDataWriter(\n      neo4j,\n      jobId,\n      partitionId,\n      schema,\n      saveMode,\n      options,\n      scriptResult\n    )\n}\n"
  },
  {
    "path": "spark-3/src/main/scala/org/neo4j/spark/streaming/Neo4jStreamingPartitionReader.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark.streaming\n\nimport org.apache.spark.sql.catalyst.InternalRow\nimport org.apache.spark.sql.connector.expressions.aggregate.AggregateFunc\nimport org.apache.spark.sql.connector.read.PartitionReader\nimport org.apache.spark.sql.sources.Filter\nimport org.apache.spark.sql.types.StructType\nimport org.apache.spark.util.AccumulatorV2\nimport org.apache.spark.util.LongAccumulator\nimport org.neo4j.caniuse.Neo4j\nimport org.neo4j.spark.service.PartitionPagination\nimport org.neo4j.spark.util.Neo4jOptions\n\nclass Neo4jStreamingPartitionReader(\n  private val neo4j: Neo4j,\n  private val options: Neo4jOptions,\n  private val filters: Array[Filter],\n  private val schema: StructType,\n  private val jobId: String,\n  private val partitionSkipLimit: PartitionPagination,\n  private val scriptResult: java.util.List[java.util.Map[String, AnyRef]],\n  private val requiredColumns: StructType,\n  private val aggregateColumns: Array[AggregateFunc]\n) extends BaseStreamingPartitionReader(\n      neo4j,\n      options,\n      filters,\n      schema,\n      jobId,\n      partitionSkipLimit,\n      scriptResult,\n      requiredColumns,\n      aggregateColumns\n    )\n    with PartitionReader[InternalRow] {}\n"
  },
  {
    "path": "spark-3/src/main/scala/org/neo4j/spark/streaming/Neo4jStreamingPartitionReaderFactory.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark.streaming\n\nimport org.apache.spark.sql.catalyst.InternalRow\nimport org.apache.spark.sql.connector.expressions.aggregate.AggregateFunc\nimport org.apache.spark.sql.connector.read.InputPartition\nimport org.apache.spark.sql.connector.read.PartitionReader\nimport org.apache.spark.sql.connector.read.PartitionReaderFactory\nimport org.apache.spark.sql.sources.Filter\nimport org.apache.spark.sql.types.StructType\nimport org.apache.spark.util.AccumulatorV2\nimport org.apache.spark.util.LongAccumulator\nimport org.neo4j.caniuse.Neo4j\nimport org.neo4j.spark.service.PartitionPagination\nimport org.neo4j.spark.util.Neo4jOptions\n\ncase class Neo4jStreamingPartition(partitionSkipLimit: PartitionPagination, filters: Array[Filter])\n    extends InputPartition\n\nclass Neo4jStreamingPartitionReaderFactory(\n  private val neo4j: Neo4j,\n  private val neo4jOptions: Neo4jOptions,\n  private val schema: StructType,\n  private val jobId: String,\n  private val scriptResult: java.util.List[java.util.Map[String, AnyRef]],\n  private val aggregateColumns: Array[AggregateFunc]\n) extends PartitionReaderFactory {\n\n  override def createReader(partition: InputPartition): PartitionReader[InternalRow] =\n    new Neo4jStreamingPartitionReader(\n      neo4j,\n      neo4jOptions,\n      partition.asInstanceOf[Neo4jStreamingPartition].filters,\n      schema,\n      jobId,\n      partition.asInstanceOf[Neo4jStreamingPartition].partitionSkipLimit,\n      scriptResult,\n      new StructType(),\n      aggregateColumns\n    )\n}\n"
  },
  {
    "path": "spark-3/src/main/scala/org/neo4j/spark/streaming/Neo4jStreamingWriter.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark.streaming\n\nimport org.apache.spark.sql.SaveMode\nimport org.apache.spark.sql.SparkSession\nimport org.apache.spark.sql.connector.write.PhysicalWriteInfo\nimport org.apache.spark.sql.connector.write.WriterCommitMessage\nimport org.apache.spark.sql.connector.write.streaming.StreamingDataWriterFactory\nimport org.apache.spark.sql.connector.write.streaming.StreamingWrite\nimport org.apache.spark.sql.streaming.StreamingQueryListener\nimport org.apache.spark.sql.types.StructType\nimport org.neo4j.caniuse.Neo4j\nimport org.neo4j.spark.service.SchemaService\nimport org.neo4j.spark.util.DriverCache\nimport org.neo4j.spark.util.Neo4jOptions\nimport org.neo4j.spark.util.Neo4jUtil\n\nimport java.util.Optional\n\nclass Neo4jStreamingWriter(\n  val neo4j: Neo4j,\n  val queryId: String,\n  val schema: StructType,\n  saveMode: SaveMode,\n  val neo4jOptions: Neo4jOptions\n) extends StreamingWrite {\n\n  private val self = this\n\n  private val listener = new StreamingQueryListener {\n    override def onQueryStarted(event: StreamingQueryListener.QueryStartedEvent): Unit = ()\n\n    override def onQueryProgress(event: StreamingQueryListener.QueryProgressEvent): Unit = ()\n\n    override def onQueryTerminated(event: StreamingQueryListener.QueryTerminatedEvent): Unit = {\n      if (event.id.toString == queryId) {\n        self.close()\n        SparkSession.getDefaultSession.get.streams.removeListener(this)\n      }\n    }\n  }\n  SparkSession.getDefaultSession.get.streams.addListener(listener)\n\n  private val driverCache = new DriverCache(neo4jOptions.connection)\n\n  private lazy val scriptResult = {\n    val schemaService = new SchemaService(neo4j, neo4jOptions, driverCache)\n    schemaService.createOptimizations(schema)\n    val scriptResult = schemaService.execute(neo4jOptions.script)\n    schemaService.close()\n    scriptResult\n  }\n\n  override def createStreamingWriterFactory(info: PhysicalWriteInfo): StreamingDataWriterFactory = {\n    new Neo4jStreamingDataWriterFactory(\n      neo4j,\n      queryId,\n      schema,\n      saveMode,\n      neo4jOptions,\n      scriptResult\n    )\n  }\n\n  override def commit(epochId: Long, messages: Array[WriterCommitMessage]): Unit = {}\n\n  override def abort(epochId: Long, messages: Array[WriterCommitMessage]): Unit = {}\n\n  def close(): Unit = Neo4jUtil.closeSafely(driverCache)\n}\n"
  },
  {
    "path": "spark-3/src/main/scala/org/neo4j/spark/writer/Neo4jBatchWriter.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark.writer\n\nimport org.apache.spark.sql.SaveMode\nimport org.apache.spark.sql.connector.write.BatchWrite\nimport org.apache.spark.sql.connector.write.DataWriterFactory\nimport org.apache.spark.sql.connector.write.PhysicalWriteInfo\nimport org.apache.spark.sql.connector.write.WriterCommitMessage\nimport org.apache.spark.sql.types.StructType\nimport org.neo4j.caniuse.Neo4j\nimport org.neo4j.spark.service.SchemaService\nimport org.neo4j.spark.util.DriverCache\nimport org.neo4j.spark.util.Neo4jOptions\n\nimport java.util.Optional\n\nclass Neo4jBatchWriter(\n  neo4j: Neo4j,\n  jobId: String,\n  structType: StructType,\n  saveMode: SaveMode,\n  neo4jOptions: Neo4jOptions\n) extends BatchWrite {\n\n  override def createBatchWriterFactory(physicalWriteInfo: PhysicalWriteInfo): DataWriterFactory = {\n    val schemaService = new SchemaService(neo4j, neo4jOptions, driverCache)\n    schemaService.createOptimizations(structType)\n    val scriptResult = schemaService.execute(neo4jOptions.script)\n    schemaService.close()\n\n    if (neo4jOptions.indexAwait > 0) {\n      val session = driverCache.getOrCreate().session(neo4jOptions.session.toNeo4jSession())\n      session.run(s\"CALL db.awaitIndexes(${neo4jOptions.indexAwait})\").consume()\n    }\n\n    new Neo4jDataWriterFactory(\n      neo4j,\n      jobId,\n      structType,\n      saveMode,\n      neo4jOptions,\n      scriptResult\n    )\n  }\n\n  private val driverCache = new DriverCache(neo4jOptions.connection)\n\n  override def commit(messages: Array[WriterCommitMessage]): Unit = {\n    driverCache.close()\n  }\n\n  override def abort(messages: Array[WriterCommitMessage]): Unit = {\n    driverCache.close()\n  }\n}\n"
  },
  {
    "path": "spark-3/src/main/scala/org/neo4j/spark/writer/Neo4jDataWriter.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark.writer\n\nimport org.apache.spark.sql.SaveMode\nimport org.apache.spark.sql.catalyst.InternalRow\nimport org.apache.spark.sql.connector.write.DataWriter\nimport org.apache.spark.sql.types.StructType\nimport org.neo4j.caniuse.Neo4j\nimport org.neo4j.spark.util.Neo4jOptions\n\nclass Neo4jDataWriter(\n  neo4j: Neo4j,\n  jobId: String,\n  partitionId: Int,\n  schema: StructType,\n  saveMode: SaveMode,\n  options: Neo4jOptions,\n  scriptResult: java.util.List[java.util.Map[String, AnyRef]]\n) extends BaseDataWriter(neo4j, jobId, partitionId, schema, saveMode, options, scriptResult)\n    with DataWriter[InternalRow] {}\n"
  },
  {
    "path": "spark-3/src/main/scala/org/neo4j/spark/writer/Neo4jDataWriterFactory.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark.writer\n\nimport org.apache.spark.sql.SaveMode\nimport org.apache.spark.sql.catalyst.InternalRow\nimport org.apache.spark.sql.connector.write.DataWriter\nimport org.apache.spark.sql.connector.write.DataWriterFactory\nimport org.apache.spark.sql.connector.write.PhysicalWriteInfo\nimport org.apache.spark.sql.types.StructType\nimport org.neo4j.caniuse.Neo4j\nimport org.neo4j.spark.util.Neo4jOptions\n\nclass Neo4jDataWriterFactory(\n  neo4j: Neo4j,\n  jobId: String,\n  structType: StructType,\n  saveMode: SaveMode,\n  options: Neo4jOptions,\n  scriptResult: java.util.List[java.util.Map[String, AnyRef]]\n) extends DataWriterFactory {\n\n  override def createWriter(partitionId: Int, taskId: Long): DataWriter[InternalRow] = new Neo4jDataWriter(\n    neo4j,\n    jobId,\n    partitionId,\n    structType,\n    saveMode,\n    options,\n    scriptResult\n  )\n}\n"
  },
  {
    "path": "spark-3/src/main/scala/org/neo4j/spark/writer/Neo4jWriterBuilder.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark.writer\n\nimport org.apache.spark.sql.SaveMode\nimport org.apache.spark.sql.connector.metric.CustomMetric\nimport org.apache.spark.sql.connector.write.BatchWrite\nimport org.apache.spark.sql.connector.write.SupportsOverwrite\nimport org.apache.spark.sql.connector.write.SupportsTruncate\nimport org.apache.spark.sql.connector.write.Write\nimport org.apache.spark.sql.connector.write.WriteBuilder\nimport org.apache.spark.sql.connector.write.streaming.StreamingWrite\nimport org.apache.spark.sql.sources.Filter\nimport org.apache.spark.sql.types.StructType\nimport org.neo4j.caniuse.Neo4j\nimport org.neo4j.spark.streaming.Neo4jStreamingWriter\nimport org.neo4j.spark.util.Neo4jOptions\nimport org.neo4j.spark.util.NodeSaveMode\nimport org.neo4j.spark.util.ValidateSaveMode\nimport org.neo4j.spark.util.ValidateWrite\nimport org.neo4j.spark.util.ValidationUtil\nimport org.neo4j.spark.util.Validations\n\nclass Neo4jWriterBuilder(\n  neo4j: Neo4j,\n  queryId: String,\n  schema: StructType,\n  saveMode: SaveMode,\n  neo4jOptions: Neo4jOptions\n) extends WriteBuilder\n    with SupportsOverwrite\n    with SupportsTruncate {\n\n  override def build(): Write = new Write {\n    override def description(): String = \"Neo4j Writer\"\n\n    override def toBatch: BatchWrite = buildForBatch()\n\n    override def toStreaming: StreamingWrite = buildForStreaming()\n\n    override def supportedCustomMetrics(): Array[CustomMetric] = DataWriterMetrics.metricDeclarations()\n  }\n\n  def validOptions(actualSaveMode: SaveMode): Neo4jOptions = {\n    Validations.validate(ValidateWrite(\n      neo4j,\n      neo4jOptions,\n      queryId,\n      actualSaveMode,\n      (o: Neo4jOptions) => {\n        ValidationUtil.isFalse(\n          o.relationshipMetadata.sourceSaveMode.equals(NodeSaveMode.ErrorIfExists)\n            && o.relationshipMetadata.targetSaveMode.equals(NodeSaveMode.ErrorIfExists),\n          \"Save mode 'ErrorIfExists' is not supported on Spark 3.0, use 'Append' instead.\"\n        )\n      }\n    ))\n    neo4jOptions\n  }\n\n  override def buildForBatch(): BatchWrite =\n    new Neo4jBatchWriter(neo4j, queryId, schema, saveMode, validOptions(saveMode))\n\n  @volatile\n  private var streamWriter: Neo4jStreamingWriter = _\n\n  def isNewInstance(queryId: String, schema: StructType, options: Neo4jOptions): Boolean =\n    streamWriter == null ||\n      streamWriter.queryId != queryId ||\n      streamWriter.schema != schema ||\n      streamWriter.neo4jOptions != options\n\n  override def buildForStreaming(): StreamingWrite = {\n    if (isNewInstance(queryId, schema, neo4jOptions)) {\n      val streamingSaveMode = neo4jOptions.saveMode\n      Validations.validate(ValidateSaveMode(streamingSaveMode))\n\n      val saveMode = SaveMode.valueOf(streamingSaveMode)\n      streamWriter = new Neo4jStreamingWriter(\n        neo4j,\n        queryId,\n        schema,\n        saveMode,\n        validOptions(saveMode)\n      )\n    }\n\n    streamWriter\n  }\n\n  override def overwrite(filters: Array[Filter]): WriteBuilder = {\n    new Neo4jWriterBuilder(neo4j, queryId, schema, SaveMode.Overwrite, neo4jOptions)\n  }\n}\n"
  },
  {
    "path": "spark-3/src/test/java/org/neo4j/spark/DataSourceReaderTypesTSE.java",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark;\n\nimport org.apache.spark.sql.Dataset;\nimport org.apache.spark.sql.Row;\nimport org.apache.spark.sql.catalyst.expressions.GenericRowWithSchema;\nimport org.junit.Test;\nimport org.neo4j.driver.Session;\n\nimport java.sql.Timestamp;\nimport java.time.*;\nimport java.sql.Date;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.TimeZone;\n\nimport static org.junit.Assert.assertEquals;\n\npublic class DataSourceReaderTypesTSE extends SparkConnectorScalaBaseTSE {\n\n    @Test\n    public void testReadNodeWithString() {\n        String name = \"Foobar\";\n        Dataset<Row> df = initTest(\"CREATE (p:Person {name: '\" + name + \"'})\");\n\n        assertEquals(name, df.select(\"name\").collectAsList().get(0).getString(0));\n    }\n\n    @Test\n    public void testReadNodeWithLong() {\n        long age = 42L;\n        Dataset<Row> df = initTest(\"CREATE (p:Person {age: \" + age + \"})\");\n\n        assertEquals(age, df.select(\"age\").collectAsList().get(0).getLong(0));\n    }\n\n    @Test\n    public void testReadNodeWithDouble() {\n        double score = 4.2;\n        Dataset<Row> df = initTest(\"CREATE (p:Person {score: \" + score + \"})\");\n\n        assertEquals(score, df.select(\"score\").collectAsList().get(0).getDouble(0), 0);\n    }\n\n    @Test\n    public void testReadNodeWithLocalTime() {\n        Dataset<Row> df = initTest(\"CREATE (p:Person {aTime: localtime({hour:12, minute: 23, second: 0, millisecond: 294})})\");\n\n        GenericRowWithSchema result = df.select(\"aTime\").collectAsList().get(0).getAs(0);\n\n        assertEquals(\"local-time\", result.get(0));\n        assertEquals(\"12:23:00.294\", result.get(1));\n    }\n\n    @Test\n    public void testReadNodeWithTime() {\n        TimeZone timezone = TimeZone.getDefault();\n        Dataset<Row> df = initTest(\"CREATE (p:Person {aTime: time({hour:12, minute: 23, second: 0, millisecond: 294, timezone: '\" + timezone.getID() + \"'})})\");\n\n        GenericRowWithSchema result = df.select(\"aTime\").collectAsList().get(0).getAs(0);\n\n        LocalTime localTime = LocalTime.of(12, 23, 0, 294000000);\n        OffsetTime expectedTime = OffsetTime.of(localTime, timezone.toZoneId().getRules().getOffset(Instant.now()));\n\n        assertEquals(\"offset-time\", result.get(0));\n        assertEquals(expectedTime.toString(), result.get(1));\n    }\n\n    @Test\n    public void testReadNodeWithLocalDateTime() {\n        String localDateTime = \"2007-12-03T10:15:30\";\n        Dataset<Row> df = initTest(\"CREATE (p:Person {aTime: localdatetime('\" + localDateTime + \"')})\");\n\n        Row row = df.select(\"aTime\").collectAsList().get(0);\n        LocalDateTime result = row.getAs(0);\n        assertEquals(LocalDateTime.parse(localDateTime), result);\n    }\n\n    @Test\n    public void testReadNodeWithZonedDateTime() {\n        String dateTime = \"2015-06-24T12:50:35.556+01:00\";\n        Dataset<Row> df = initTest(\"CREATE (p:Person {aTime: datetime('\" + dateTime + \"')})\");\n\n        Timestamp result = df.select(\"aTime\").collectAsList().get(0).getTimestamp(0);\n        assertEquals(Timestamp.from(OffsetDateTime.parse(dateTime).toInstant()), result);\n    }\n\n    @Test\n    public void testReadNodeWithPoint() {\n        Dataset<Row> df = initTest(\"CREATE (p:Person {location: point({x: 12.12, y: 13.13})})\");\n\n        GenericRowWithSchema res = df.select(\"location\").collectAsList().get(0).getAs(0);\n        assertEquals(\"point-2d\", res.get(0));\n        assertEquals(7203, res.get(1));\n        assertEquals(12.12, res.get(2));\n        assertEquals(13.13, res.get(3));\n    }\n\n    @Test\n    public void testReadNodeWithGeoPoint() {\n        Dataset<Row> df = initTest(\"CREATE (p:Person {location: point({longitude: 12.12, latitude: 13.13})})\");\n\n        GenericRowWithSchema res = df.select(\"location\").collectAsList().get(0).getAs(0);\n        assertEquals(\"point-2d\", res.get(0));\n        assertEquals(4326, res.get(1));\n        assertEquals(12.12, res.get(2));\n        assertEquals(13.13, res.get(3));\n    }\n\n    @Test\n    public void testReadNodeWithPoint3D() {\n        Dataset<Row> df = initTest(\"CREATE (p:Person {location: point({x: 12.12, y: 13.13, z: 1})})\");\n\n        GenericRowWithSchema res = df.select(\"location\").collectAsList().get(0).getAs(0);\n        assertEquals(\"point-3d\", res.get(0));\n        assertEquals(9157, res.get(1));\n        assertEquals(12.12, res.get(2));\n        assertEquals(13.13, res.get(3));\n        assertEquals(1.0, res.get(4));\n    }\n\n    @Test\n    public void testReadNodeWithDate() {\n        Dataset<Row> df = initTest(\"CREATE (p:Person {born: date('2009-10-10')})\");\n\n        Date res = df.select(\"born\").collectAsList().get(0).getDate(0);\n        assertEquals(Date.valueOf(\"2009-10-10\"), res);\n    }\n\n    @Test\n    public void testReadNodeWithDuration() {\n        Dataset<Row> df = initTest(\"CREATE (p:Person {range: duration({days: 14, hours:16, minutes: 12})})\");\n\n        GenericRowWithSchema res = df.select(\"range\").collectAsList().get(0).getAs(0);\n        assertEquals(\"duration\", res.get(0));\n        assertEquals(0L, res.get(1));\n        assertEquals(14L, res.get(2));\n        assertEquals(58320L, res.get(3));\n        assertEquals(0, res.get(4));\n        assertEquals(\"P0M14DT58320S\", res.get(5));\n    }\n\n    @Test\n    public void testReadNodeWithStringArray() {\n        Dataset<Row> df = initTest(\"CREATE (p:Person {names: ['John', 'Doe']})\");\n\n        List<String> res = df.select(\"names\").collectAsList().get(0).getList(0);\n        assertEquals(\"John\", res.get(0));\n        assertEquals(\"Doe\", res.get(1));\n    }\n\n    @Test\n    public void testReadNodeWithLongArray() {\n        Dataset<Row> df = initTest(\"CREATE (p:Person {ages: [22, 23]})\");\n\n        List<Long> res = df.select(\"ages\").collectAsList().get(0).getList(0);\n        assertEquals(22L, res.get(0).longValue());\n        assertEquals(23L, res.get(1).longValue());\n    }\n\n    @Test\n    public void testReadNodeWithDoubleArray() {\n        Dataset<Row> df = initTest(\"CREATE (p:Person {scores: [22.33, 44.55]})\");\n\n        List<Double> res = df.select(\"scores\").collectAsList().get(0).getList(0);\n        assertEquals(22.33, res.get(0), 0);\n        assertEquals(44.55, res.get(1), 0);\n    }\n\n    @Test\n    public void testReadNodeWithLocalTimeArray() {\n        Dataset<Row> df = initTest(\"CREATE (p:Person {someTimes: [localtime({hour:12}), localtime({hour:1, minute: 3})]})\");\n\n        List<GenericRowWithSchema> res = df.select(\"someTimes\").collectAsList().get(0).getList(0);\n        assertEquals(\"local-time\", res.get(0).get(0));\n        assertEquals(\"12:00:00\", res.get(0).get(1));\n        assertEquals(\"local-time\", res.get(1).get(0));\n        assertEquals(\"01:03:00\", res.get(1).get(1));\n    }\n\n    @Test\n    public void testReadNodeWithBooleanArray() {\n        Dataset<Row> df = initTest(\"CREATE (p:Person {bools: [true, false]})\");\n\n        List<Boolean> res = df.select(\"bools\").collectAsList().get(0).getList(0);\n        assertEquals(true, res.get(0));\n        assertEquals(false, res.get(1));\n    }\n\n    @Test\n    public void testReadNodeWithArrayDate() {\n        Dataset<Row> df = initTest(\"CREATE (p:Person {dates: [date('2009-10-10'), date('2009-10-11')]})\");\n\n        List<Date> res = df.select(\"dates\").collectAsList().get(0).getList(0);\n        assertEquals(Date.valueOf(\"2009-10-10\"), res.get(0));\n        assertEquals(Date.valueOf(\"2009-10-11\"), res.get(1));\n    }\n\n    @Test\n    public void testReadNodeWithArrayZonedDateTime() {\n        String datetime1 = \"2015-06-24T12:50:35.556+01:00\";\n        String datetime2 = \"2015-06-23T12:50:35.556+01:00\";\n        Dataset<Row> df = initTest(\"CREATE (p:Person {dates: [datetime('\" + datetime1 + \"'), datetime('\" + datetime2 + \"')]})\");\n\n        List<Timestamp> res = df.select(\"dates\").collectAsList().get(0).getList(0);\n        assertEquals(Timestamp.from(OffsetDateTime.parse(datetime1).toInstant()), res.get(0));\n        assertEquals(Timestamp.from(OffsetDateTime.parse(datetime2).toInstant()), res.get(1));\n    }\n\n    @Test\n    public void testReadNodeWithArrayDurations() {\n        Dataset<Row> df = initTest(\"CREATE (p:Person {durations: [duration({months: 0.75}), duration({weeks: 2.5})]})\");\n\n        List<GenericRowWithSchema> res = df.select(\"durations\").collectAsList().get(0).getList(0);\n        assertEquals(\"duration\", res.get(0).get(0));\n        assertEquals(0L, res.get(0).get(1));\n        assertEquals(22L, res.get(0).get(2));\n        assertEquals(71509L, res.get(0).get(3));\n        assertEquals(500000000, res.get(0).get(4));\n        assertEquals(\"P0M22DT71509.500000000S\", res.get(0).get(5));\n\n        assertEquals(\"duration\", res.get(1).get(0));\n        assertEquals(0L, res.get(1).get(1));\n        assertEquals(17L, res.get(1).get(2));\n        assertEquals(43200L, res.get(1).get(3));\n        assertEquals(0, res.get(1).get(4));\n        assertEquals(\"P0M17DT43200S\", res.get(1).get(5));\n    }\n\n    @Test\n    public void testReadNodeWithPointArray() {\n        Dataset<Row> df = initTest(\"CREATE (p:Person {locations: [point({x: 11, y: 33.111}), point({x: 22, y: 44.222})]})\");\n\n        List<GenericRowWithSchema> res = df.select(\"locations\").collectAsList().get(0).getList(0);\n        assertEquals(\"point-2d\", res.get(0).get(0));\n        assertEquals(7203, res.get(0).get(1));\n        assertEquals(11.0, res.get(0).get(2));\n        assertEquals(33.111, res.get(0).get(3));\n\n        assertEquals(\"point-2d\", res.get(1).get(0));\n        assertEquals(7203, res.get(1).get(1));\n        assertEquals(22.0, res.get(1).get(2));\n        assertEquals(44.222, res.get(1).get(3));\n    }\n\n    @Test\n    public void testReadNodeWithGeoPointArray() {\n        Dataset<Row> df = initTest(\"CREATE (p:Person {locations: [point({longitude: 11, latitude: 33.111}), point({longitude: 22, latitude: 44.222})]})\");\n\n        List<GenericRowWithSchema> res = df.select(\"locations\").collectAsList().get(0).getList(0);\n        assertEquals(\"point-2d\", res.get(0).get(0));\n        assertEquals(4326, res.get(0).get(1));\n        assertEquals(11.0, res.get(0).get(2));\n        assertEquals(33.111, res.get(0).get(3));\n\n        assertEquals(\"point-2d\", res.get(1).get(0));\n        assertEquals(4326, res.get(1).get(1));\n        assertEquals(22.0, res.get(1).get(2));\n        assertEquals(44.222, res.get(1).get(3));\n    }\n\n    @Test\n    public void testReadNodeWithPoint3DArray() {\n        Dataset<Row> df = initTest(\"CREATE (p:Person {locations: [point({x: 11, y: 33.111, z: 12}), point({x: 22, y: 44.222, z: 99.1})]})\");\n\n        List<GenericRowWithSchema> res = df.select(\"locations\").collectAsList().get(0).getList(0);\n        assertEquals(\"point-3d\", res.get(0).get(0));\n        assertEquals(9157, res.get(0).get(1));\n        assertEquals(11.0, res.get(0).get(2));\n        assertEquals(33.111, res.get(0).get(3));\n\n        assertEquals(\"point-3d\", res.get(1).get(0));\n        assertEquals(9157, res.get(1).get(1));\n        assertEquals(22.0, res.get(1).get(2));\n        assertEquals(44.222, res.get(1).get(3));\n    }\n\n    @Test\n    public void testReadNodeWithMap() {\n        Dataset<Row> df = ss().read().format(DataSource.class.getName())\n                .option(\"url\", SparkConnectorScalaSuiteIT.server().getBoltUrl())\n                .option(\"query\", \"RETURN {a: 1, b: '3'} AS map\")\n                .load();\n\n        Map<Object, Object> map = df.select(\"map\").collectAsList().get(0).getJavaMap(0);\n        Map<String, String> expectedMap = new HashMap<>();\n        expectedMap.put(\"a\", \"1\");\n        expectedMap.put(\"b\", \"3\");\n\n        assertEquals(expectedMap, map);\n    }\n\n    Dataset<Row> initTest(String query) {\n        try (Session session = SparkConnectorScalaSuiteIT.session(\"\")) {\n            session.writeTransaction(transaction -> transaction.run(query).consume());\n        }\n\n        return ss().read().format(DataSource.class.getName())\n                .option(\"url\", SparkConnectorScalaSuiteIT.server().getBoltUrl())\n                .option(\"labels\", \"Person\")\n                .load();\n    }\n}\n"
  },
  {
    "path": "spark-3/src/test/java/org/neo4j/spark/SparkConnectorSuiteIT.java",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark;\n\nimport org.junit.runner.RunWith;\nimport org.junit.runners.Suite;\n\n@RunWith(Suite.class)\n@Suite.SuiteClasses({\n    DataSourceReaderTypesTSE.class\n})\npublic class SparkConnectorSuiteIT extends SparkConnectorScalaSuiteIT {\n}\n"
  },
  {
    "path": "spark-3/src/test/resources/log4j2.properties",
    "content": "appender.console.type=Console\nappender.console.name=STDOUT_TXT\nappender.console.target=SYSTEM_OUT\nappender.console.layout.type=PatternLayout\nappender.console.layout.pattern=%d{HH:mm:ss.SSS} [%t] %-5level %logger %X{source_type} - %msg%n\n\nlogger.neo4j.name=org.neo4j\nlogger.neo4j.level=debug\n\nrootLogger.level=info\nrootLogger.appenderRefs=stdout\nrootLogger.appenderRef.stdout.ref=STDOUT_TXT"
  },
  {
    "path": "spark-3/src/test/resources/neo4j-sso-test-realm.json",
    "content": "{\n  \"id\": \"7d10aebd-a60d-45a9-bce3-bb3a0a372ae9\",\n  \"realm\": \"neo4j-sso-test\",\n  \"notBefore\": 0,\n  \"defaultSignatureAlgorithm\": \"RS256\",\n  \"revokeRefreshToken\": false,\n  \"refreshTokenMaxReuse\": 0,\n  \"accessTokenLifespan\": 300,\n  \"accessTokenLifespanForImplicitFlow\": 900,\n  \"ssoSessionIdleTimeout\": 1800,\n  \"ssoSessionMaxLifespan\": 36000,\n  \"ssoSessionIdleTimeoutRememberMe\": 0,\n  \"ssoSessionMaxLifespanRememberMe\": 0,\n  \"offlineSessionIdleTimeout\": 2592000,\n  \"offlineSessionMaxLifespanEnabled\": false,\n  \"offlineSessionMaxLifespan\": 5184000,\n  \"clientSessionIdleTimeout\": 0,\n  \"clientSessionMaxLifespan\": 0,\n  \"clientOfflineSessionIdleTimeout\": 0,\n  \"clientOfflineSessionMaxLifespan\": 0,\n  \"accessCodeLifespan\": 60,\n  \"accessCodeLifespanUserAction\": 300,\n  \"accessCodeLifespanLogin\": 1800,\n  \"actionTokenGeneratedByAdminLifespan\": 43200,\n  \"actionTokenGeneratedByUserLifespan\": 300,\n  \"oauth2DeviceCodeLifespan\": 600,\n  \"oauth2DevicePollingInterval\": 5,\n  \"enabled\": true,\n  \"sslRequired\": \"external\",\n  \"registrationAllowed\": false,\n  \"registrationEmailAsUsername\": false,\n  \"rememberMe\": false,\n  \"verifyEmail\": false,\n  \"loginWithEmailAllowed\": true,\n  \"duplicateEmailsAllowed\": false,\n  \"resetPasswordAllowed\": false,\n  \"editUsernameAllowed\": false,\n  \"bruteForceProtected\": false,\n  \"permanentLockout\": false,\n  \"maxTemporaryLockouts\": 0,\n  \"bruteForceStrategy\": \"MULTIPLE\",\n  \"maxFailureWaitSeconds\": 900,\n  \"minimumQuickLoginWaitSeconds\": 60,\n  \"waitIncrementSeconds\": 60,\n  \"quickLoginCheckMilliSeconds\": 1000,\n  \"maxDeltaTimeSeconds\": 43200,\n  \"failureFactor\": 30,\n  \"roles\": {\n    \"realm\": [\n      {\n        \"id\": \"4d08fd99-cc5d-45d6-9a49-cdd4fcd6448e\",\n        \"name\": \"uma_authorization\",\n        \"description\": \"${role_uma_authorization}\",\n        \"composite\": false,\n        \"clientRole\": false,\n        \"containerId\": \"7d10aebd-a60d-45a9-bce3-bb3a0a372ae9\",\n        \"attributes\": {}\n      },\n      {\n        \"id\": \"49ad4e27-73f3-48ea-adf1-ff56880176d9\",\n        \"name\": \"offline_access\",\n        \"description\": \"${role_offline-access}\",\n        \"composite\": false,\n        \"clientRole\": false,\n        \"containerId\": \"7d10aebd-a60d-45a9-bce3-bb3a0a372ae9\",\n        \"attributes\": {}\n      },\n      {\n        \"id\": \"1c26e8ea-3815-4364-b254-39280413343b\",\n        \"name\": \"default-roles-neo4j-sso-test\",\n        \"description\": \"${role_default-roles}\",\n        \"composite\": true,\n        \"composites\": {\n          \"realm\": [\n            \"offline_access\",\n            \"uma_authorization\"\n          ],\n          \"client\": {\n            \"account\": [\n              \"manage-account\",\n              \"view-profile\"\n            ]\n          }\n        },\n        \"clientRole\": false,\n        \"containerId\": \"7d10aebd-a60d-45a9-bce3-bb3a0a372ae9\",\n        \"attributes\": {}\n      }\n    ],\n    \"client\": {\n      \"realm-management\": [\n        {\n          \"id\": \"02f4e601-c963-4fdd-9246-f732ceb7ff40\",\n          \"name\": \"manage-users\",\n          \"description\": \"${role_manage-users}\",\n          \"composite\": false,\n          \"clientRole\": true,\n          \"containerId\": \"ff825411-d253-459a-93b9-71b9f00b1276\",\n          \"attributes\": {}\n        },\n        {\n          \"id\": \"860945bd-3a1b-4f1d-91e4-6506ed427e72\",\n          \"name\": \"query-clients\",\n          \"description\": \"${role_query-clients}\",\n          \"composite\": false,\n          \"clientRole\": true,\n          \"containerId\": \"ff825411-d253-459a-93b9-71b9f00b1276\",\n          \"attributes\": {}\n        },\n        {\n          \"id\": \"0b3a6477-57be-4ebe-88d0-473f9bbcaa43\",\n          \"name\": \"query-realms\",\n          \"description\": \"${role_query-realms}\",\n          \"composite\": false,\n          \"clientRole\": true,\n          \"containerId\": \"ff825411-d253-459a-93b9-71b9f00b1276\",\n          \"attributes\": {}\n        },\n        {\n          \"id\": \"07e63113-153b-4ca1-95c7-a0c161b6107a\",\n          \"name\": \"realm-admin\",\n          \"description\": \"${role_realm-admin}\",\n          \"composite\": true,\n          \"composites\": {\n            \"client\": {\n              \"realm-management\": [\n                \"manage-users\",\n                \"query-clients\",\n                \"query-realms\",\n                \"view-clients\",\n                \"query-users\",\n                \"view-users\",\n                \"manage-clients\",\n                \"view-events\",\n                \"query-groups\",\n                \"manage-realm\",\n                \"manage-authorization\",\n                \"create-client\",\n                \"manage-events\",\n                \"view-realm\",\n                \"manage-identity-providers\",\n                \"impersonation\",\n                \"view-authorization\",\n                \"view-identity-providers\"\n              ]\n            }\n          },\n          \"clientRole\": true,\n          \"containerId\": \"ff825411-d253-459a-93b9-71b9f00b1276\",\n          \"attributes\": {}\n        },\n        {\n          \"id\": \"89500893-787c-47a0-8e54-917d54508cff\",\n          \"name\": \"query-users\",\n          \"description\": \"${role_query-users}\",\n          \"composite\": false,\n          \"clientRole\": true,\n          \"containerId\": \"ff825411-d253-459a-93b9-71b9f00b1276\",\n          \"attributes\": {}\n        },\n        {\n          \"id\": \"29194689-d523-40ef-9340-88eb86c6c4bb\",\n          \"name\": \"view-clients\",\n          \"description\": \"${role_view-clients}\",\n          \"composite\": true,\n          \"composites\": {\n            \"client\": {\n              \"realm-management\": [\n                \"query-clients\"\n              ]\n            }\n          },\n          \"clientRole\": true,\n          \"containerId\": \"ff825411-d253-459a-93b9-71b9f00b1276\",\n          \"attributes\": {}\n        },\n        {\n          \"id\": \"e871e84c-d6d2-4c3f-bd7b-b9a5aeac32be\",\n          \"name\": \"manage-clients\",\n          \"description\": \"${role_manage-clients}\",\n          \"composite\": false,\n          \"clientRole\": true,\n          \"containerId\": \"ff825411-d253-459a-93b9-71b9f00b1276\",\n          \"attributes\": {}\n        },\n        {\n          \"id\": \"8f862a23-e90d-4f92-8acf-fb9adb5121f0\",\n          \"name\": \"view-users\",\n          \"description\": \"${role_view-users}\",\n          \"composite\": true,\n          \"composites\": {\n            \"client\": {\n              \"realm-management\": [\n                \"query-groups\",\n                \"query-users\"\n              ]\n            }\n          },\n          \"clientRole\": true,\n          \"containerId\": \"ff825411-d253-459a-93b9-71b9f00b1276\",\n          \"attributes\": {}\n        },\n        {\n          \"id\": \"f36e6ae9-043d-47ee-b294-2f450d0f34a9\",\n          \"name\": \"manage-realm\",\n          \"description\": \"${role_manage-realm}\",\n          \"composite\": false,\n          \"clientRole\": true,\n          \"containerId\": \"ff825411-d253-459a-93b9-71b9f00b1276\",\n          \"attributes\": {}\n        },\n        {\n          \"id\": \"802b1f48-95cc-4af5-bc96-76d8a701ec24\",\n          \"name\": \"query-groups\",\n          \"description\": \"${role_query-groups}\",\n          \"composite\": false,\n          \"clientRole\": true,\n          \"containerId\": \"ff825411-d253-459a-93b9-71b9f00b1276\",\n          \"attributes\": {}\n        },\n        {\n          \"id\": \"743ede07-a12d-4d6b-bec2-0231450a28f9\",\n          \"name\": \"view-events\",\n          \"description\": \"${role_view-events}\",\n          \"composite\": false,\n          \"clientRole\": true,\n          \"containerId\": \"ff825411-d253-459a-93b9-71b9f00b1276\",\n          \"attributes\": {}\n        },\n        {\n          \"id\": \"7252234e-695b-47a2-bfa9-7c50b5bedd35\",\n          \"name\": \"manage-authorization\",\n          \"description\": \"${role_manage-authorization}\",\n          \"composite\": false,\n          \"clientRole\": true,\n          \"containerId\": \"ff825411-d253-459a-93b9-71b9f00b1276\",\n          \"attributes\": {}\n        },\n        {\n          \"id\": \"3d5a003d-3c0d-4193-9048-40179baa1f5f\",\n          \"name\": \"create-client\",\n          \"description\": \"${role_create-client}\",\n          \"composite\": false,\n          \"clientRole\": true,\n          \"containerId\": \"ff825411-d253-459a-93b9-71b9f00b1276\",\n          \"attributes\": {}\n        },\n        {\n          \"id\": \"174cb3a3-b04a-446b-88d8-d5225a658757\",\n          \"name\": \"manage-events\",\n          \"description\": \"${role_manage-events}\",\n          \"composite\": false,\n          \"clientRole\": true,\n          \"containerId\": \"ff825411-d253-459a-93b9-71b9f00b1276\",\n          \"attributes\": {}\n        },\n        {\n          \"id\": \"1596f494-4617-4794-ba44-d7add890691e\",\n          \"name\": \"view-realm\",\n          \"description\": \"${role_view-realm}\",\n          \"composite\": false,\n          \"clientRole\": true,\n          \"containerId\": \"ff825411-d253-459a-93b9-71b9f00b1276\",\n          \"attributes\": {}\n        },\n        {\n          \"id\": \"daf38dba-70c6-4a38-9a56-92d42bcc4731\",\n          \"name\": \"impersonation\",\n          \"description\": \"${role_impersonation}\",\n          \"composite\": false,\n          \"clientRole\": true,\n          \"containerId\": \"ff825411-d253-459a-93b9-71b9f00b1276\",\n          \"attributes\": {}\n        },\n        {\n          \"id\": \"64ea62ef-c69c-400f-af0d-f63f410a5801\",\n          \"name\": \"manage-identity-providers\",\n          \"description\": \"${role_manage-identity-providers}\",\n          \"composite\": false,\n          \"clientRole\": true,\n          \"containerId\": \"ff825411-d253-459a-93b9-71b9f00b1276\",\n          \"attributes\": {}\n        },\n        {\n          \"id\": \"f6189b24-7b3b-4acf-8240-5297b60a82e5\",\n          \"name\": \"view-authorization\",\n          \"description\": \"${role_view-authorization}\",\n          \"composite\": false,\n          \"clientRole\": true,\n          \"containerId\": \"ff825411-d253-459a-93b9-71b9f00b1276\",\n          \"attributes\": {}\n        },\n        {\n          \"id\": \"ef2dea85-dd33-4aed-932b-a8e8bd2355ca\",\n          \"name\": \"view-identity-providers\",\n          \"description\": \"${role_view-identity-providers}\",\n          \"composite\": false,\n          \"clientRole\": true,\n          \"containerId\": \"ff825411-d253-459a-93b9-71b9f00b1276\",\n          \"attributes\": {}\n        }\n      ],\n      \"security-admin-console\": [],\n      \"admin-cli\": [],\n      \"neo4j-commons-client\": [\n        {\n          \"id\": \"9a142f12-99da-442c-bdaa-9f8a59171404\",\n          \"name\": \"uma_protection\",\n          \"composite\": false,\n          \"clientRole\": true,\n          \"containerId\": \"004fd711-5103-47bc-9c93-bfcf38b3a10a\",\n          \"attributes\": {}\n        }\n      ],\n      \"account-console\": [],\n      \"broker\": [\n        {\n          \"id\": \"06e885bf-8d8f-4a7b-afde-4bf4a87959d3\",\n          \"name\": \"read-token\",\n          \"description\": \"${role_read-token}\",\n          \"composite\": false,\n          \"clientRole\": true,\n          \"containerId\": \"7c1f30ad-9cfd-4817-9f02-7f914b125de7\",\n          \"attributes\": {}\n        }\n      ],\n      \"account\": [\n        {\n          \"id\": \"1f367fdb-6d7a-4c7f-af5b-a0ed66b1c289\",\n          \"name\": \"delete-account\",\n          \"description\": \"${role_delete-account}\",\n          \"composite\": false,\n          \"clientRole\": true,\n          \"containerId\": \"f78d45f3-369c-457e-ab92-4e1e5a97f54c\",\n          \"attributes\": {}\n        },\n        {\n          \"id\": \"3fad9c59-832e-48d4-abc8-82a621a66ce9\",\n          \"name\": \"manage-account\",\n          \"description\": \"${role_manage-account}\",\n          \"composite\": true,\n          \"composites\": {\n            \"client\": {\n              \"account\": [\n                \"manage-account-links\"\n              ]\n            }\n          },\n          \"clientRole\": true,\n          \"containerId\": \"f78d45f3-369c-457e-ab92-4e1e5a97f54c\",\n          \"attributes\": {}\n        },\n        {\n          \"id\": \"1d0cc167-ae58-4950-97e8-9f709ee118a6\",\n          \"name\": \"view-consent\",\n          \"description\": \"${role_view-consent}\",\n          \"composite\": false,\n          \"clientRole\": true,\n          \"containerId\": \"f78d45f3-369c-457e-ab92-4e1e5a97f54c\",\n          \"attributes\": {}\n        },\n        {\n          \"id\": \"1d83e541-8475-48e1-afd4-6fa17429275c\",\n          \"name\": \"manage-account-links\",\n          \"description\": \"${role_manage-account-links}\",\n          \"composite\": false,\n          \"clientRole\": true,\n          \"containerId\": \"f78d45f3-369c-457e-ab92-4e1e5a97f54c\",\n          \"attributes\": {}\n        },\n        {\n          \"id\": \"4e1703b0-d6f2-4504-aa4e-8670b14e88fe\",\n          \"name\": \"view-applications\",\n          \"description\": \"${role_view-applications}\",\n          \"composite\": false,\n          \"clientRole\": true,\n          \"containerId\": \"f78d45f3-369c-457e-ab92-4e1e5a97f54c\",\n          \"attributes\": {}\n        },\n        {\n          \"id\": \"cd8d0800-a6b3-43fc-bd15-0c7ce40c9183\",\n          \"name\": \"view-profile\",\n          \"description\": \"${role_view-profile}\",\n          \"composite\": false,\n          \"clientRole\": true,\n          \"containerId\": \"f78d45f3-369c-457e-ab92-4e1e5a97f54c\",\n          \"attributes\": {}\n        },\n        {\n          \"id\": \"62439512-e52e-41ef-9123-66d79931f45b\",\n          \"name\": \"manage-consent\",\n          \"description\": \"${role_manage-consent}\",\n          \"composite\": true,\n          \"composites\": {\n            \"client\": {\n              \"account\": [\n                \"view-consent\"\n              ]\n            }\n          },\n          \"clientRole\": true,\n          \"containerId\": \"f78d45f3-369c-457e-ab92-4e1e5a97f54c\",\n          \"attributes\": {}\n        },\n        {\n          \"id\": \"d67ceb33-f9d2-482f-99c4-09a29210ee78\",\n          \"name\": \"view-groups\",\n          \"description\": \"${role_view-groups}\",\n          \"composite\": false,\n          \"clientRole\": true,\n          \"containerId\": \"f78d45f3-369c-457e-ab92-4e1e5a97f54c\",\n          \"attributes\": {}\n        }\n      ]\n    }\n  },\n  \"groups\": [\n    {\n      \"id\": \"667caafa-3dbe-4604-a427-6c61ecac5c3f\",\n      \"name\": \"admin\",\n      \"path\": \"/admin\",\n      \"subGroups\": [],\n      \"attributes\": {},\n      \"realmRoles\": [],\n      \"clientRoles\": {}\n    }\n  ],\n  \"defaultRole\": {\n    \"id\": \"1c26e8ea-3815-4364-b254-39280413343b\",\n    \"name\": \"default-roles-neo4j-sso-test\",\n    \"description\": \"${role_default-roles}\",\n    \"composite\": true,\n    \"clientRole\": false,\n    \"containerId\": \"7d10aebd-a60d-45a9-bce3-bb3a0a372ae9\"\n  },\n  \"requiredCredentials\": [\n    \"password\"\n  ],\n  \"otpPolicyType\": \"totp\",\n  \"otpPolicyAlgorithm\": \"HmacSHA1\",\n  \"otpPolicyInitialCounter\": 0,\n  \"otpPolicyDigits\": 6,\n  \"otpPolicyLookAheadWindow\": 1,\n  \"otpPolicyPeriod\": 30,\n  \"otpPolicyCodeReusable\": false,\n  \"otpSupportedApplications\": [\n    \"totpAppFreeOTPName\",\n    \"totpAppGoogleName\",\n    \"totpAppMicrosoftAuthenticatorName\"\n  ],\n  \"localizationTexts\": {},\n  \"webAuthnPolicyRpEntityName\": \"keycloak\",\n  \"webAuthnPolicySignatureAlgorithms\": [\n    \"ES256\",\n    \"RS256\"\n  ],\n  \"webAuthnPolicyRpId\": \"\",\n  \"webAuthnPolicyAttestationConveyancePreference\": \"not specified\",\n  \"webAuthnPolicyAuthenticatorAttachment\": \"not specified\",\n  \"webAuthnPolicyRequireResidentKey\": \"not specified\",\n  \"webAuthnPolicyUserVerificationRequirement\": \"not specified\",\n  \"webAuthnPolicyCreateTimeout\": 0,\n  \"webAuthnPolicyAvoidSameAuthenticatorRegister\": false,\n  \"webAuthnPolicyAcceptableAaguids\": [],\n  \"webAuthnPolicyExtraOrigins\": [],\n  \"webAuthnPolicyPasswordlessRpEntityName\": \"keycloak\",\n  \"webAuthnPolicyPasswordlessSignatureAlgorithms\": [\n    \"ES256\",\n    \"RS256\"\n  ],\n  \"webAuthnPolicyPasswordlessRpId\": \"\",\n  \"webAuthnPolicyPasswordlessAttestationConveyancePreference\": \"not specified\",\n  \"webAuthnPolicyPasswordlessAuthenticatorAttachment\": \"not specified\",\n  \"webAuthnPolicyPasswordlessRequireResidentKey\": \"not specified\",\n  \"webAuthnPolicyPasswordlessUserVerificationRequirement\": \"not specified\",\n  \"webAuthnPolicyPasswordlessCreateTimeout\": 0,\n  \"webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister\": false,\n  \"webAuthnPolicyPasswordlessAcceptableAaguids\": [],\n  \"webAuthnPolicyPasswordlessExtraOrigins\": [],\n  \"users\" : [\n    {\n    \"id\" : \"14236e67-7ec2-490f-9f25-9e14af69e52a\",\n    \"username\" : \"john-tester\",\n    \"firstName\" : \"John\",\n    \"lastName\" : \"Tester\",\n    \"email\" : \"john.tester@test.com\",\n    \"emailVerified\" : false,\n    \"createdTimestamp\" : 1753905058600,\n    \"enabled\" : true,\n    \"totp\" : false,\n    \"credentials\" : [ {\n      \"id\" : \"d0fa2175-584f-45ec-a242-283b54a84feb\",\n      \"type\" : \"password\",\n      \"userLabel\" : \"My password\",\n      \"createdDate\" : 1753905074445,\n      \"secretData\" : \"{\\\"value\\\":\\\"XvUWimFjFwz3KoXoChpHcbypIlm/I1K/s4nYHNHQfMU=\\\",\\\"salt\\\":\\\"yEQApqyMC2yQCdU/7uLJzQ==\\\",\\\"additionalParameters\\\":{}}\",\n      \"credentialData\" : \"{\\\"hashIterations\\\":5,\\\"algorithm\\\":\\\"argon2\\\",\\\"additionalParameters\\\":{\\\"hashLength\\\":[\\\"32\\\"],\\\"memory\\\":[\\\"7168\\\"],\\\"type\\\":[\\\"id\\\"],\\\"version\\\":[\\\"1.3\\\"],\\\"parallelism\\\":[\\\"1\\\"]}}\"\n    } ],\n    \"disableableCredentialTypes\" : [ ],\n    \"requiredActions\" : [ ],\n    \"realmRoles\" : [ \"default-roles-neo4j-sso-test\" ],\n    \"notBefore\" : 0,\n    \"groups\" : [ \"/admin\" ]\n  }, {\n    \"id\" : \"61144f9e-1bff-4b3e-beeb-a04d3e0cbe1c\",\n    \"username\" : \"service-account-neo4j-commons-client\",\n    \"emailVerified\" : false,\n    \"createdTimestamp\" : 1753904616478,\n    \"enabled\" : true,\n    \"totp\" : false,\n    \"serviceAccountClientId\" : \"neo4j-commons-client\",\n    \"credentials\" : [ ],\n    \"disableableCredentialTypes\" : [ ],\n    \"requiredActions\" : [ ],\n    \"realmRoles\" : [ \"default-roles-neo4j-sso-test\" ],\n    \"clientRoles\" : {\n      \"neo4j-commons-client\" : [ \"uma_protection\" ]\n    },\n    \"notBefore\" : 0,\n    \"groups\" : [ ]\n  } ],\n  \"scopeMappings\": [\n    {\n      \"clientScope\": \"offline_access\",\n      \"roles\": [\n        \"offline_access\"\n      ]\n    }\n  ],\n  \"clientScopeMappings\": {\n    \"account\": [\n      {\n        \"client\": \"account-console\",\n        \"roles\": [\n          \"manage-account\",\n          \"view-groups\"\n        ]\n      }\n    ]\n  },\n  \"clients\": [\n    {\n      \"id\": \"f78d45f3-369c-457e-ab92-4e1e5a97f54c\",\n      \"clientId\": \"account\",\n      \"name\": \"${client_account}\",\n      \"rootUrl\": \"${authBaseUrl}\",\n      \"baseUrl\": \"/realms/neo4j-sso-test/account/\",\n      \"surrogateAuthRequired\": false,\n      \"enabled\": true,\n      \"alwaysDisplayInConsole\": false,\n      \"clientAuthenticatorType\": \"client-secret\",\n      \"redirectUris\": [\n        \"/realms/neo4j-sso-test/account/*\"\n      ],\n      \"webOrigins\": [],\n      \"notBefore\": 0,\n      \"bearerOnly\": false,\n      \"consentRequired\": false,\n      \"standardFlowEnabled\": true,\n      \"implicitFlowEnabled\": false,\n      \"directAccessGrantsEnabled\": false,\n      \"serviceAccountsEnabled\": false,\n      \"publicClient\": true,\n      \"frontchannelLogout\": false,\n      \"protocol\": \"openid-connect\",\n      \"attributes\": {\n        \"realm_client\": \"false\",\n        \"post.logout.redirect.uris\": \"+\"\n      },\n      \"authenticationFlowBindingOverrides\": {},\n      \"fullScopeAllowed\": false,\n      \"nodeReRegistrationTimeout\": 0,\n      \"defaultClientScopes\": [\n        \"web-origins\",\n        \"acr\",\n        \"profile\",\n        \"roles\",\n        \"basic\",\n        \"email\"\n      ],\n      \"optionalClientScopes\": [\n        \"address\",\n        \"phone\",\n        \"organization\",\n        \"offline_access\",\n        \"microprofile-jwt\"\n      ]\n    },\n    {\n      \"id\": \"60b52f12-1c88-418b-8de5-181f69a7f12f\",\n      \"clientId\": \"account-console\",\n      \"name\": \"${client_account-console}\",\n      \"rootUrl\": \"${authBaseUrl}\",\n      \"baseUrl\": \"/realms/neo4j-sso-test/account/\",\n      \"surrogateAuthRequired\": false,\n      \"enabled\": true,\n      \"alwaysDisplayInConsole\": false,\n      \"clientAuthenticatorType\": \"client-secret\",\n      \"redirectUris\": [\n        \"/realms/neo4j-sso-test/account/*\"\n      ],\n      \"webOrigins\": [],\n      \"notBefore\": 0,\n      \"bearerOnly\": false,\n      \"consentRequired\": false,\n      \"standardFlowEnabled\": true,\n      \"implicitFlowEnabled\": false,\n      \"directAccessGrantsEnabled\": false,\n      \"serviceAccountsEnabled\": false,\n      \"publicClient\": true,\n      \"frontchannelLogout\": false,\n      \"protocol\": \"openid-connect\",\n      \"attributes\": {\n        \"realm_client\": \"false\",\n        \"post.logout.redirect.uris\": \"+\",\n        \"pkce.code.challenge.method\": \"S256\"\n      },\n      \"authenticationFlowBindingOverrides\": {},\n      \"fullScopeAllowed\": false,\n      \"nodeReRegistrationTimeout\": 0,\n      \"protocolMappers\": [\n        {\n          \"id\": \"7281166b-a81b-485d-a227-b47299ea7a10\",\n          \"name\": \"audience resolve\",\n          \"protocol\": \"openid-connect\",\n          \"protocolMapper\": \"oidc-audience-resolve-mapper\",\n          \"consentRequired\": false,\n          \"config\": {}\n        }\n      ],\n      \"defaultClientScopes\": [\n        \"web-origins\",\n        \"acr\",\n        \"profile\",\n        \"roles\",\n        \"basic\",\n        \"email\"\n      ],\n      \"optionalClientScopes\": [\n        \"address\",\n        \"phone\",\n        \"organization\",\n        \"offline_access\",\n        \"microprofile-jwt\"\n      ]\n    },\n    {\n      \"id\": \"2c20b6a9-7bb6-4d41-b1bb-1375de214d5a\",\n      \"clientId\": \"admin-cli\",\n      \"name\": \"${client_admin-cli}\",\n      \"surrogateAuthRequired\": false,\n      \"enabled\": true,\n      \"alwaysDisplayInConsole\": false,\n      \"clientAuthenticatorType\": \"client-secret\",\n      \"redirectUris\": [],\n      \"webOrigins\": [],\n      \"notBefore\": 0,\n      \"bearerOnly\": false,\n      \"consentRequired\": false,\n      \"standardFlowEnabled\": false,\n      \"implicitFlowEnabled\": false,\n      \"directAccessGrantsEnabled\": true,\n      \"serviceAccountsEnabled\": false,\n      \"publicClient\": true,\n      \"frontchannelLogout\": false,\n      \"protocol\": \"openid-connect\",\n      \"attributes\": {\n        \"realm_client\": \"false\",\n        \"client.use.lightweight.access.token.enabled\": \"true\",\n        \"post.logout.redirect.uris\": \"+\"\n      },\n      \"authenticationFlowBindingOverrides\": {},\n      \"fullScopeAllowed\": true,\n      \"nodeReRegistrationTimeout\": 0,\n      \"defaultClientScopes\": [\n        \"web-origins\",\n        \"acr\",\n        \"profile\",\n        \"roles\",\n        \"basic\",\n        \"email\"\n      ],\n      \"optionalClientScopes\": [\n        \"address\",\n        \"phone\",\n        \"organization\",\n        \"offline_access\",\n        \"microprofile-jwt\"\n      ]\n    },\n    {\n      \"id\": \"7c1f30ad-9cfd-4817-9f02-7f914b125de7\",\n      \"clientId\": \"broker\",\n      \"name\": \"${client_broker}\",\n      \"surrogateAuthRequired\": false,\n      \"enabled\": true,\n      \"alwaysDisplayInConsole\": false,\n      \"clientAuthenticatorType\": \"client-secret\",\n      \"redirectUris\": [],\n      \"webOrigins\": [],\n      \"notBefore\": 0,\n      \"bearerOnly\": true,\n      \"consentRequired\": false,\n      \"standardFlowEnabled\": true,\n      \"implicitFlowEnabled\": false,\n      \"directAccessGrantsEnabled\": false,\n      \"serviceAccountsEnabled\": false,\n      \"publicClient\": false,\n      \"frontchannelLogout\": false,\n      \"protocol\": \"openid-connect\",\n      \"attributes\": {\n        \"realm_client\": \"true\",\n        \"post.logout.redirect.uris\": \"+\"\n      },\n      \"authenticationFlowBindingOverrides\": {},\n      \"fullScopeAllowed\": false,\n      \"nodeReRegistrationTimeout\": 0,\n      \"defaultClientScopes\": [\n        \"web-origins\",\n        \"acr\",\n        \"profile\",\n        \"roles\",\n        \"basic\",\n        \"email\"\n      ],\n      \"optionalClientScopes\": [\n        \"address\",\n        \"phone\",\n        \"organization\",\n        \"offline_access\",\n        \"microprofile-jwt\"\n      ]\n    },\n    {\n      \"id\": \"004fd711-5103-47bc-9c93-bfcf38b3a10a\",\n      \"clientId\": \"neo4j-commons-client\",\n      \"name\": \"neo4j-commons-client\",\n      \"description\": \"\",\n      \"rootUrl\": \"\",\n      \"adminUrl\": \"\",\n      \"baseUrl\": \"\",\n      \"surrogateAuthRequired\": false,\n      \"enabled\": true,\n      \"alwaysDisplayInConsole\": false,\n      \"clientAuthenticatorType\": \"client-secret\",\n      \"secret\": \"QNrSpbh0mxhnlYlI21UcBaz3Htb734vi\",\n      \"redirectUris\": [\n        \"/*\"\n      ],\n      \"webOrigins\": [\n        \"/*\"\n      ],\n      \"notBefore\": 0,\n      \"bearerOnly\": false,\n      \"consentRequired\": false,\n      \"standardFlowEnabled\": true,\n      \"implicitFlowEnabled\": false,\n      \"directAccessGrantsEnabled\": true,\n      \"serviceAccountsEnabled\": true,\n      \"authorizationServicesEnabled\": true,\n      \"publicClient\": false,\n      \"frontchannelLogout\": true,\n      \"protocol\": \"openid-connect\",\n      \"attributes\": {\n        \"access.token.lifespan\" : \"3\",\n        \"client.secret.creation.time\" : \"1750236324\",\n        \"request.object.signature.alg\" : \"any\",\n        \"request.object.encryption.alg\" : \"any\",\n        \"client.introspection.response.allow.jwt.claim.enabled\" : \"true\",\n        \"standard.token.exchange.enabled\" : \"false\",\n        \"frontchannel.logout.session.required\" : \"true\",\n        \"oauth2.device.authorization.grant.enabled\" : \"true\",\n        \"use.jwks.url\" : \"false\",\n        \"backchannel.logout.revoke.offline.tokens\" : \"false\",\n        \"use.refresh.tokens\" : \"true\",\n        \"realm_client\" : \"false\",\n        \"oidc.ciba.grant.enabled\" : \"false\",\n        \"client.use.lightweight.access.token.enabled\" : \"false\",\n        \"backchannel.logout.session.required\" : \"true\",\n        \"request.object.required\" : \"not required\",\n        \"client_credentials.use_refresh_token\" : \"true\",\n        \"access.token.header.type.rfc9068\" : \"false\",\n        \"tls.client.certificate.bound.access.tokens\" : \"false\",\n        \"require.pushed.authorization.requests\" : \"false\",\n        \"acr.loa.map\" : \"{}\",\n        \"display.on.consent.screen\" : \"false\",\n        \"request.object.encryption.enc\" : \"any\",\n        \"token.response.type.bearer.lower-case\" : \"false\"\n      },\n      \"authenticationFlowBindingOverrides\": {},\n      \"fullScopeAllowed\": true,\n      \"nodeReRegistrationTimeout\": -1,\n      \"protocolMappers\" : [ {\n        \"id\" : \"ac56f3e2-8898-4040-a4ed-b1a4e3a20e52\",\n        \"name\" : \"groups\",\n        \"protocol\" : \"openid-connect\",\n        \"protocolMapper\" : \"oidc-group-membership-mapper\",\n        \"consentRequired\" : false,\n        \"config\" : {\n          \"full.path\" : \"false\",\n          \"introspection.token.claim\" : \"true\",\n          \"userinfo.token.claim\" : \"false\",\n          \"multivalued\" : \"true\",\n          \"id.token.claim\" : \"false\",\n          \"lightweight.claim\" : \"false\",\n          \"access.token.claim\" : \"true\",\n          \"claim.name\" : \"groups\"\n        }\n      } ],\n      \"defaultClientScopes\": [\n        \"service_account\",\n        \"web-origins\",\n        \"acr\",\n        \"profile\",\n        \"roles\",\n        \"basic\",\n        \"email\"\n      ],\n      \"optionalClientScopes\": [\n        \"address\",\n        \"phone\",\n        \"organization\",\n        \"offline_access\",\n        \"microprofile-jwt\"\n      ]\n    },\n    {\n      \"id\": \"ff825411-d253-459a-93b9-71b9f00b1276\",\n      \"clientId\": \"realm-management\",\n      \"name\": \"${client_realm-management}\",\n      \"surrogateAuthRequired\": false,\n      \"enabled\": true,\n      \"alwaysDisplayInConsole\": false,\n      \"clientAuthenticatorType\": \"client-secret\",\n      \"redirectUris\": [],\n      \"webOrigins\": [],\n      \"notBefore\": 0,\n      \"bearerOnly\": true,\n      \"consentRequired\": false,\n      \"standardFlowEnabled\": true,\n      \"implicitFlowEnabled\": false,\n      \"directAccessGrantsEnabled\": false,\n      \"serviceAccountsEnabled\": false,\n      \"publicClient\": false,\n      \"frontchannelLogout\": false,\n      \"protocol\": \"openid-connect\",\n      \"attributes\": {\n        \"realm_client\": \"true\",\n        \"post.logout.redirect.uris\": \"+\"\n      },\n      \"authenticationFlowBindingOverrides\": {},\n      \"fullScopeAllowed\": false,\n      \"nodeReRegistrationTimeout\": 0,\n      \"defaultClientScopes\": [\n        \"web-origins\",\n        \"acr\",\n        \"profile\",\n        \"roles\",\n        \"basic\",\n        \"email\"\n      ],\n      \"optionalClientScopes\": [\n        \"address\",\n        \"phone\",\n        \"organization\",\n        \"offline_access\",\n        \"microprofile-jwt\"\n      ]\n    },\n    {\n      \"id\": \"e45c1497-2c8f-47f2-8c11-42ad8c088e23\",\n      \"clientId\": \"security-admin-console\",\n      \"name\": \"${client_security-admin-console}\",\n      \"rootUrl\": \"${authAdminUrl}\",\n      \"baseUrl\": \"/admin/neo4j-sso-test/console/\",\n      \"surrogateAuthRequired\": false,\n      \"enabled\": true,\n      \"alwaysDisplayInConsole\": false,\n      \"clientAuthenticatorType\": \"client-secret\",\n      \"redirectUris\": [\n        \"/admin/neo4j-sso-test/console/*\"\n      ],\n      \"webOrigins\": [\n        \"+\"\n      ],\n      \"notBefore\": 0,\n      \"bearerOnly\": false,\n      \"consentRequired\": false,\n      \"standardFlowEnabled\": true,\n      \"implicitFlowEnabled\": false,\n      \"directAccessGrantsEnabled\": false,\n      \"serviceAccountsEnabled\": false,\n      \"publicClient\": true,\n      \"frontchannelLogout\": false,\n      \"protocol\": \"openid-connect\",\n      \"attributes\": {\n        \"realm_client\": \"false\",\n        \"client.use.lightweight.access.token.enabled\": \"true\",\n        \"post.logout.redirect.uris\": \"+\",\n        \"pkce.code.challenge.method\": \"S256\"\n      },\n      \"authenticationFlowBindingOverrides\": {},\n      \"fullScopeAllowed\": true,\n      \"nodeReRegistrationTimeout\": 0,\n      \"protocolMappers\": [\n        {\n          \"id\": \"eb064310-4c24-4c0f-bf39-27d5767a2f21\",\n          \"name\": \"locale\",\n          \"protocol\": \"openid-connect\",\n          \"protocolMapper\": \"oidc-usermodel-attribute-mapper\",\n          \"consentRequired\": false,\n          \"config\": {\n            \"introspection.token.claim\": \"true\",\n            \"userinfo.token.claim\": \"true\",\n            \"user.attribute\": \"locale\",\n            \"id.token.claim\": \"true\",\n            \"access.token.claim\": \"true\",\n            \"claim.name\": \"locale\",\n            \"jsonType.label\": \"String\"\n          }\n        }\n      ],\n      \"defaultClientScopes\": [\n        \"web-origins\",\n        \"acr\",\n        \"profile\",\n        \"roles\",\n        \"basic\",\n        \"email\"\n      ],\n      \"optionalClientScopes\": [\n        \"address\",\n        \"phone\",\n        \"organization\",\n        \"offline_access\",\n        \"microprofile-jwt\"\n      ]\n    }\n  ],\n  \"clientScopes\": [\n    {\n      \"id\": \"6daac52d-0f54-4cbb-b159-93cae1188e26\",\n      \"name\": \"service_account\",\n      \"description\": \"Specific scope for a client enabled for service accounts\",\n      \"protocol\": \"openid-connect\",\n      \"attributes\": {\n        \"include.in.token.scope\": \"false\",\n        \"display.on.consent.screen\": \"false\"\n      },\n      \"protocolMappers\": [\n        {\n          \"id\": \"a7d31bbd-ca7b-4d61-ae3a-7d901eb84039\",\n          \"name\": \"Client Host\",\n          \"protocol\": \"openid-connect\",\n          \"protocolMapper\": \"oidc-usersessionmodel-note-mapper\",\n          \"consentRequired\": false,\n          \"config\": {\n            \"user.session.note\": \"clientHost\",\n            \"introspection.token.claim\": \"true\",\n            \"userinfo.token.claim\": \"true\",\n            \"id.token.claim\": \"true\",\n            \"access.token.claim\": \"true\",\n            \"claim.name\": \"clientHost\",\n            \"jsonType.label\": \"String\"\n          }\n        },\n        {\n          \"id\": \"8c417a42-c005-46ff-8e30-834ca3170169\",\n          \"name\": \"Client ID\",\n          \"protocol\": \"openid-connect\",\n          \"protocolMapper\": \"oidc-usersessionmodel-note-mapper\",\n          \"consentRequired\": false,\n          \"config\": {\n            \"user.session.note\": \"client_id\",\n            \"introspection.token.claim\": \"true\",\n            \"userinfo.token.claim\": \"true\",\n            \"id.token.claim\": \"true\",\n            \"access.token.claim\": \"true\",\n            \"claim.name\": \"client_id\",\n            \"jsonType.label\": \"String\"\n          }\n        },\n        {\n          \"id\": \"3d484d15-8210-417d-af09-5cdedab9c6da\",\n          \"name\": \"Client IP Address\",\n          \"protocol\": \"openid-connect\",\n          \"protocolMapper\": \"oidc-usersessionmodel-note-mapper\",\n          \"consentRequired\": false,\n          \"config\": {\n            \"user.session.note\": \"clientAddress\",\n            \"introspection.token.claim\": \"true\",\n            \"userinfo.token.claim\": \"true\",\n            \"id.token.claim\": \"true\",\n            \"access.token.claim\": \"true\",\n            \"claim.name\": \"clientAddress\",\n            \"jsonType.label\": \"String\"\n          }\n        }\n      ]\n    },\n    {\n      \"id\": \"93bbac6c-0437-46ad-8917-29b8f9a03376\",\n      \"name\": \"phone\",\n      \"description\": \"OpenID Connect built-in scope: phone\",\n      \"protocol\": \"openid-connect\",\n      \"attributes\": {\n        \"include.in.token.scope\": \"true\",\n        \"consent.screen.text\": \"${phoneScopeConsentText}\",\n        \"display.on.consent.screen\": \"true\"\n      },\n      \"protocolMappers\": [\n        {\n          \"id\": \"6695fac9-a5a7-4705-aadb-c57a09626042\",\n          \"name\": \"phone number verified\",\n          \"protocol\": \"openid-connect\",\n          \"protocolMapper\": \"oidc-usermodel-attribute-mapper\",\n          \"consentRequired\": false,\n          \"config\": {\n            \"introspection.token.claim\": \"true\",\n            \"userinfo.token.claim\": \"true\",\n            \"user.attribute\": \"phoneNumberVerified\",\n            \"id.token.claim\": \"true\",\n            \"access.token.claim\": \"true\",\n            \"claim.name\": \"phone_number_verified\",\n            \"jsonType.label\": \"boolean\"\n          }\n        },\n        {\n          \"id\": \"c5f8b96f-7586-4468-837a-d94f2eff1f37\",\n          \"name\": \"phone number\",\n          \"protocol\": \"openid-connect\",\n          \"protocolMapper\": \"oidc-usermodel-attribute-mapper\",\n          \"consentRequired\": false,\n          \"config\": {\n            \"introspection.token.claim\": \"true\",\n            \"userinfo.token.claim\": \"true\",\n            \"user.attribute\": \"phoneNumber\",\n            \"id.token.claim\": \"true\",\n            \"access.token.claim\": \"true\",\n            \"claim.name\": \"phone_number\",\n            \"jsonType.label\": \"String\"\n          }\n        }\n      ]\n    },\n    {\n      \"id\": \"0430729b-4f3e-44ce-8d2c-1eec8e077357\",\n      \"name\": \"saml_organization\",\n      \"description\": \"Organization Membership\",\n      \"protocol\": \"saml\",\n      \"attributes\": {\n        \"display.on.consent.screen\": \"false\"\n      },\n      \"protocolMappers\": [\n        {\n          \"id\": \"d5918bc9-1660-402f-8952-92571a955835\",\n          \"name\": \"organization\",\n          \"protocol\": \"saml\",\n          \"protocolMapper\": \"saml-organization-membership-mapper\",\n          \"consentRequired\": false,\n          \"config\": {}\n        }\n      ]\n    },\n    {\n      \"id\": \"aab0e3e4-5f85-4015-802d-d5286e9ad947\",\n      \"name\": \"profile\",\n      \"description\": \"OpenID Connect built-in scope: profile\",\n      \"protocol\": \"openid-connect\",\n      \"attributes\": {\n        \"include.in.token.scope\": \"true\",\n        \"consent.screen.text\": \"${profileScopeConsentText}\",\n        \"display.on.consent.screen\": \"true\"\n      },\n      \"protocolMappers\": [\n        {\n          \"id\": \"75f3fd4d-04b6-4bc0-876b-07f598dbb669\",\n          \"name\": \"family name\",\n          \"protocol\": \"openid-connect\",\n          \"protocolMapper\": \"oidc-usermodel-attribute-mapper\",\n          \"consentRequired\": false,\n          \"config\": {\n            \"introspection.token.claim\": \"true\",\n            \"userinfo.token.claim\": \"true\",\n            \"user.attribute\": \"lastName\",\n            \"id.token.claim\": \"true\",\n            \"access.token.claim\": \"true\",\n            \"claim.name\": \"family_name\",\n            \"jsonType.label\": \"String\"\n          }\n        },\n        {\n          \"id\": \"7e619c16-d618-4f7f-bc46-4ba4fc0d8f7b\",\n          \"name\": \"full name\",\n          \"protocol\": \"openid-connect\",\n          \"protocolMapper\": \"oidc-full-name-mapper\",\n          \"consentRequired\": false,\n          \"config\": {\n            \"id.token.claim\": \"true\",\n            \"introspection.token.claim\": \"true\",\n            \"access.token.claim\": \"true\",\n            \"userinfo.token.claim\": \"true\"\n          }\n        },\n        {\n          \"id\": \"8476d1e0-9dcc-4318-9a58-6f52d82a8b46\",\n          \"name\": \"locale\",\n          \"protocol\": \"openid-connect\",\n          \"protocolMapper\": \"oidc-usermodel-attribute-mapper\",\n          \"consentRequired\": false,\n          \"config\": {\n            \"introspection.token.claim\": \"true\",\n            \"userinfo.token.claim\": \"true\",\n            \"user.attribute\": \"locale\",\n            \"id.token.claim\": \"true\",\n            \"access.token.claim\": \"true\",\n            \"claim.name\": \"locale\",\n            \"jsonType.label\": \"String\"\n          }\n        },\n        {\n          \"id\": \"09e15aea-9ce2-420f-baac-76f358b8ac5b\",\n          \"name\": \"username\",\n          \"protocol\": \"openid-connect\",\n          \"protocolMapper\": \"oidc-usermodel-attribute-mapper\",\n          \"consentRequired\": false,\n          \"config\": {\n            \"introspection.token.claim\": \"true\",\n            \"userinfo.token.claim\": \"true\",\n            \"user.attribute\": \"username\",\n            \"id.token.claim\": \"true\",\n            \"access.token.claim\": \"true\",\n            \"claim.name\": \"preferred_username\",\n            \"jsonType.label\": \"String\"\n          }\n        },\n        {\n          \"id\": \"faf6d7d0-3418-44b4-ba41-5b6bfd105fdb\",\n          \"name\": \"gender\",\n          \"protocol\": \"openid-connect\",\n          \"protocolMapper\": \"oidc-usermodel-attribute-mapper\",\n          \"consentRequired\": false,\n          \"config\": {\n            \"introspection.token.claim\": \"true\",\n            \"userinfo.token.claim\": \"true\",\n            \"user.attribute\": \"gender\",\n            \"id.token.claim\": \"true\",\n            \"access.token.claim\": \"true\",\n            \"claim.name\": \"gender\",\n            \"jsonType.label\": \"String\"\n          }\n        },\n        {\n          \"id\": \"710d18f8-2c62-4909-b0ea-99975876e2ae\",\n          \"name\": \"middle name\",\n          \"protocol\": \"openid-connect\",\n          \"protocolMapper\": \"oidc-usermodel-attribute-mapper\",\n          \"consentRequired\": false,\n          \"config\": {\n            \"introspection.token.claim\": \"true\",\n            \"userinfo.token.claim\": \"true\",\n            \"user.attribute\": \"middleName\",\n            \"id.token.claim\": \"true\",\n            \"access.token.claim\": \"true\",\n            \"claim.name\": \"middle_name\",\n            \"jsonType.label\": \"String\"\n          }\n        },\n        {\n          \"id\": \"1871201c-4d1e-4893-8775-3bd4ee6ee4ab\",\n          \"name\": \"picture\",\n          \"protocol\": \"openid-connect\",\n          \"protocolMapper\": \"oidc-usermodel-attribute-mapper\",\n          \"consentRequired\": false,\n          \"config\": {\n            \"introspection.token.claim\": \"true\",\n            \"userinfo.token.claim\": \"true\",\n            \"user.attribute\": \"picture\",\n            \"id.token.claim\": \"true\",\n            \"access.token.claim\": \"true\",\n            \"claim.name\": \"picture\",\n            \"jsonType.label\": \"String\"\n          }\n        },\n        {\n          \"id\": \"66d85a48-55c0-491d-b05a-9ba75093a6ab\",\n          \"name\": \"updated at\",\n          \"protocol\": \"openid-connect\",\n          \"protocolMapper\": \"oidc-usermodel-attribute-mapper\",\n          \"consentRequired\": false,\n          \"config\": {\n            \"introspection.token.claim\": \"true\",\n            \"userinfo.token.claim\": \"true\",\n            \"user.attribute\": \"updatedAt\",\n            \"id.token.claim\": \"true\",\n            \"access.token.claim\": \"true\",\n            \"claim.name\": \"updated_at\",\n            \"jsonType.label\": \"long\"\n          }\n        },\n        {\n          \"id\": \"130c0094-a76b-4235-a6a1-45fdae43b2ba\",\n          \"name\": \"nickname\",\n          \"protocol\": \"openid-connect\",\n          \"protocolMapper\": \"oidc-usermodel-attribute-mapper\",\n          \"consentRequired\": false,\n          \"config\": {\n            \"introspection.token.claim\": \"true\",\n            \"userinfo.token.claim\": \"true\",\n            \"user.attribute\": \"nickname\",\n            \"id.token.claim\": \"true\",\n            \"access.token.claim\": \"true\",\n            \"claim.name\": \"nickname\",\n            \"jsonType.label\": \"String\"\n          }\n        },\n        {\n          \"id\": \"8100f44e-0052-4568-8c8c-3964c2da1cfd\",\n          \"name\": \"profile\",\n          \"protocol\": \"openid-connect\",\n          \"protocolMapper\": \"oidc-usermodel-attribute-mapper\",\n          \"consentRequired\": false,\n          \"config\": {\n            \"introspection.token.claim\": \"true\",\n            \"userinfo.token.claim\": \"true\",\n            \"user.attribute\": \"profile\",\n            \"id.token.claim\": \"true\",\n            \"access.token.claim\": \"true\",\n            \"claim.name\": \"profile\",\n            \"jsonType.label\": \"String\"\n          }\n        },\n        {\n          \"id\": \"c7d9c5e2-8b82-4337-853a-b079c4d40cd4\",\n          \"name\": \"given name\",\n          \"protocol\": \"openid-connect\",\n          \"protocolMapper\": \"oidc-usermodel-attribute-mapper\",\n          \"consentRequired\": false,\n          \"config\": {\n            \"introspection.token.claim\": \"true\",\n            \"userinfo.token.claim\": \"true\",\n            \"user.attribute\": \"firstName\",\n            \"id.token.claim\": \"true\",\n            \"access.token.claim\": \"true\",\n            \"claim.name\": \"given_name\",\n            \"jsonType.label\": \"String\"\n          }\n        },\n        {\n          \"id\": \"cb9bb72d-3cfd-4ae7-98d1-567a132afbeb\",\n          \"name\": \"birthdate\",\n          \"protocol\": \"openid-connect\",\n          \"protocolMapper\": \"oidc-usermodel-attribute-mapper\",\n          \"consentRequired\": false,\n          \"config\": {\n            \"introspection.token.claim\": \"true\",\n            \"userinfo.token.claim\": \"true\",\n            \"user.attribute\": \"birthdate\",\n            \"id.token.claim\": \"true\",\n            \"access.token.claim\": \"true\",\n            \"claim.name\": \"birthdate\",\n            \"jsonType.label\": \"String\"\n          }\n        },\n        {\n          \"id\": \"713625e4-e1cb-4ba0-9339-983e6038fb7d\",\n          \"name\": \"website\",\n          \"protocol\": \"openid-connect\",\n          \"protocolMapper\": \"oidc-usermodel-attribute-mapper\",\n          \"consentRequired\": false,\n          \"config\": {\n            \"introspection.token.claim\": \"true\",\n            \"userinfo.token.claim\": \"true\",\n            \"user.attribute\": \"website\",\n            \"id.token.claim\": \"true\",\n            \"access.token.claim\": \"true\",\n            \"claim.name\": \"website\",\n            \"jsonType.label\": \"String\"\n          }\n        },\n        {\n          \"id\": \"5d44e729-70f0-41a0-b22b-2f51915accae\",\n          \"name\": \"zoneinfo\",\n          \"protocol\": \"openid-connect\",\n          \"protocolMapper\": \"oidc-usermodel-attribute-mapper\",\n          \"consentRequired\": false,\n          \"config\": {\n            \"introspection.token.claim\": \"true\",\n            \"userinfo.token.claim\": \"true\",\n            \"user.attribute\": \"zoneinfo\",\n            \"id.token.claim\": \"true\",\n            \"access.token.claim\": \"true\",\n            \"claim.name\": \"zoneinfo\",\n            \"jsonType.label\": \"String\"\n          }\n        }\n      ]\n    },\n    {\n      \"id\": \"655a4881-b5f1-4844-a60a-e5974b6dede9\",\n      \"name\": \"email\",\n      \"description\": \"OpenID Connect built-in scope: email\",\n      \"protocol\": \"openid-connect\",\n      \"attributes\": {\n        \"include.in.token.scope\": \"true\",\n        \"consent.screen.text\": \"${emailScopeConsentText}\",\n        \"display.on.consent.screen\": \"true\"\n      },\n      \"protocolMappers\": [\n        {\n          \"id\": \"1a203587-27fb-4c64-b1b2-6603bfc29a19\",\n          \"name\": \"email verified\",\n          \"protocol\": \"openid-connect\",\n          \"protocolMapper\": \"oidc-usermodel-property-mapper\",\n          \"consentRequired\": false,\n          \"config\": {\n            \"introspection.token.claim\": \"true\",\n            \"userinfo.token.claim\": \"true\",\n            \"user.attribute\": \"emailVerified\",\n            \"id.token.claim\": \"true\",\n            \"access.token.claim\": \"true\",\n            \"claim.name\": \"email_verified\",\n            \"jsonType.label\": \"boolean\"\n          }\n        },\n        {\n          \"id\": \"db51d38a-be10-40c1-a054-6124b17711c7\",\n          \"name\": \"email\",\n          \"protocol\": \"openid-connect\",\n          \"protocolMapper\": \"oidc-usermodel-attribute-mapper\",\n          \"consentRequired\": false,\n          \"config\": {\n            \"introspection.token.claim\": \"true\",\n            \"userinfo.token.claim\": \"true\",\n            \"user.attribute\": \"email\",\n            \"id.token.claim\": \"true\",\n            \"access.token.claim\": \"true\",\n            \"claim.name\": \"email\",\n            \"jsonType.label\": \"String\"\n          }\n        }\n      ]\n    },\n    {\n      \"id\": \"a2ebcfef-8d3f-493d-9deb-c0bbe0feffb4\",\n      \"name\": \"acr\",\n      \"description\": \"OpenID Connect scope for add acr (authentication context class reference) to the token\",\n      \"protocol\": \"openid-connect\",\n      \"attributes\": {\n        \"include.in.token.scope\": \"false\",\n        \"display.on.consent.screen\": \"false\"\n      },\n      \"protocolMappers\": [\n        {\n          \"id\": \"58b572de-ed96-45d4-8b64-3193c03e8e00\",\n          \"name\": \"acr loa level\",\n          \"protocol\": \"openid-connect\",\n          \"protocolMapper\": \"oidc-acr-mapper\",\n          \"consentRequired\": false,\n          \"config\": {\n            \"id.token.claim\": \"true\",\n            \"introspection.token.claim\": \"true\",\n            \"access.token.claim\": \"true\",\n            \"userinfo.token.claim\": \"true\"\n          }\n        }\n      ]\n    },\n    {\n      \"id\": \"caa43308-3e68-4a0b-866a-ec350687d020\",\n      \"name\": \"roles\",\n      \"description\": \"OpenID Connect scope for add user roles to the access token\",\n      \"protocol\": \"openid-connect\",\n      \"attributes\": {\n        \"include.in.token.scope\": \"false\",\n        \"consent.screen.text\": \"${rolesScopeConsentText}\",\n        \"display.on.consent.screen\": \"true\"\n      },\n      \"protocolMappers\": [\n        {\n          \"id\": \"263ca184-249e-40a5-88e6-e7062ffc416d\",\n          \"name\": \"realm roles\",\n          \"protocol\": \"openid-connect\",\n          \"protocolMapper\": \"oidc-usermodel-realm-role-mapper\",\n          \"consentRequired\": false,\n          \"config\": {\n            \"user.attribute\": \"foo\",\n            \"introspection.token.claim\": \"true\",\n            \"access.token.claim\": \"true\",\n            \"claim.name\": \"realm_access.roles\",\n            \"jsonType.label\": \"String\",\n            \"multivalued\": \"true\"\n          }\n        },\n        {\n          \"id\": \"e08c2804-bae8-4622-892f-bf002894d804\",\n          \"name\": \"client roles\",\n          \"protocol\": \"openid-connect\",\n          \"protocolMapper\": \"oidc-usermodel-client-role-mapper\",\n          \"consentRequired\": false,\n          \"config\": {\n            \"user.attribute\": \"foo\",\n            \"introspection.token.claim\": \"true\",\n            \"access.token.claim\": \"true\",\n            \"claim.name\": \"resource_access.${client_id}.roles\",\n            \"jsonType.label\": \"String\",\n            \"multivalued\": \"true\"\n          }\n        },\n        {\n          \"id\": \"ae8f0f35-d7a1-4f4d-94b9-a167c231d75b\",\n          \"name\": \"audience resolve\",\n          \"protocol\": \"openid-connect\",\n          \"protocolMapper\": \"oidc-audience-resolve-mapper\",\n          \"consentRequired\": false,\n          \"config\": {\n            \"introspection.token.claim\": \"true\",\n            \"access.token.claim\": \"true\"\n          }\n        }\n      ]\n    },\n    {\n      \"id\": \"22c7fd6a-a90d-4482-85d3-dc5a51062bd4\",\n      \"name\": \"organization\",\n      \"description\": \"Additional claims about the organization a subject belongs to\",\n      \"protocol\": \"openid-connect\",\n      \"attributes\": {\n        \"include.in.token.scope\": \"true\",\n        \"consent.screen.text\": \"${organizationScopeConsentText}\",\n        \"display.on.consent.screen\": \"true\"\n      },\n      \"protocolMappers\": [\n        {\n          \"id\": \"79e6ae6c-c710-4ccf-a9d7-c1e8e8836d6a\",\n          \"name\": \"organization\",\n          \"protocol\": \"openid-connect\",\n          \"protocolMapper\": \"oidc-organization-membership-mapper\",\n          \"consentRequired\": false,\n          \"config\": {\n            \"introspection.token.claim\": \"true\",\n            \"multivalued\": \"true\",\n            \"userinfo.token.claim\": \"true\",\n            \"id.token.claim\": \"true\",\n            \"access.token.claim\": \"true\",\n            \"claim.name\": \"organization\",\n            \"jsonType.label\": \"String\"\n          }\n        }\n      ]\n    },\n    {\n      \"id\": \"c85b8ffe-1a80-4012-9642-ddf25d112c89\",\n      \"name\": \"basic\",\n      \"description\": \"OpenID Connect scope for add all basic claims to the token\",\n      \"protocol\": \"openid-connect\",\n      \"attributes\": {\n        \"include.in.token.scope\": \"false\",\n        \"display.on.consent.screen\": \"false\"\n      },\n      \"protocolMappers\": [\n        {\n          \"id\": \"d7f80a87-6368-47de-b8af-9fec687114fa\",\n          \"name\": \"auth_time\",\n          \"protocol\": \"openid-connect\",\n          \"protocolMapper\": \"oidc-usersessionmodel-note-mapper\",\n          \"consentRequired\": false,\n          \"config\": {\n            \"user.session.note\": \"AUTH_TIME\",\n            \"introspection.token.claim\": \"true\",\n            \"userinfo.token.claim\": \"true\",\n            \"id.token.claim\": \"true\",\n            \"access.token.claim\": \"true\",\n            \"claim.name\": \"auth_time\",\n            \"jsonType.label\": \"long\"\n          }\n        },\n        {\n          \"id\": \"2b319ed3-d20f-407c-9cbd-c5478ef4a9d1\",\n          \"name\": \"sub\",\n          \"protocol\": \"openid-connect\",\n          \"protocolMapper\": \"oidc-sub-mapper\",\n          \"consentRequired\": false,\n          \"config\": {\n            \"introspection.token.claim\": \"true\",\n            \"access.token.claim\": \"true\"\n          }\n        }\n      ]\n    },\n    {\n      \"id\": \"2942a349-f522-43cc-b983-e1b2119af9db\",\n      \"name\": \"role_list\",\n      \"description\": \"SAML role list\",\n      \"protocol\": \"saml\",\n      \"attributes\": {\n        \"consent.screen.text\": \"${samlRoleListScopeConsentText}\",\n        \"display.on.consent.screen\": \"true\"\n      },\n      \"protocolMappers\": [\n        {\n          \"id\": \"40a89e81-e9eb-463d-b5dc-b124e64ffa57\",\n          \"name\": \"role list\",\n          \"protocol\": \"saml\",\n          \"protocolMapper\": \"saml-role-list-mapper\",\n          \"consentRequired\": false,\n          \"config\": {\n            \"single\": \"false\",\n            \"attribute.nameformat\": \"Basic\",\n            \"attribute.name\": \"Role\"\n          }\n        }\n      ]\n    },\n    {\n      \"id\": \"0af3471d-ddde-4e01-9f64-137725d70416\",\n      \"name\": \"offline_access\",\n      \"description\": \"OpenID Connect built-in scope: offline_access\",\n      \"protocol\": \"openid-connect\",\n      \"attributes\": {\n        \"consent.screen.text\": \"${offlineAccessScopeConsentText}\",\n        \"display.on.consent.screen\": \"true\"\n      }\n    },\n    {\n      \"id\": \"a600ed15-1dc0-4c45-8262-1bd34bba9ca5\",\n      \"name\": \"microprofile-jwt\",\n      \"description\": \"Microprofile - JWT built-in scope\",\n      \"protocol\": \"openid-connect\",\n      \"attributes\": {\n        \"include.in.token.scope\": \"true\",\n        \"display.on.consent.screen\": \"false\"\n      },\n      \"protocolMappers\": [\n        {\n          \"id\": \"095068ea-7f54-4bf6-9cf2-331ea30368dc\",\n          \"name\": \"upn\",\n          \"protocol\": \"openid-connect\",\n          \"protocolMapper\": \"oidc-usermodel-attribute-mapper\",\n          \"consentRequired\": false,\n          \"config\": {\n            \"introspection.token.claim\": \"true\",\n            \"userinfo.token.claim\": \"true\",\n            \"user.attribute\": \"username\",\n            \"id.token.claim\": \"true\",\n            \"access.token.claim\": \"true\",\n            \"claim.name\": \"upn\",\n            \"jsonType.label\": \"String\"\n          }\n        },\n        {\n          \"id\": \"0e12f986-9b38-475c-a18a-2da1e95f4831\",\n          \"name\": \"groups\",\n          \"protocol\": \"openid-connect\",\n          \"protocolMapper\": \"oidc-usermodel-realm-role-mapper\",\n          \"consentRequired\": false,\n          \"config\": {\n            \"introspection.token.claim\": \"true\",\n            \"multivalued\": \"true\",\n            \"userinfo.token.claim\": \"true\",\n            \"user.attribute\": \"foo\",\n            \"id.token.claim\": \"true\",\n            \"access.token.claim\": \"true\",\n            \"claim.name\": \"groups\",\n            \"jsonType.label\": \"String\"\n          }\n        }\n      ]\n    },\n    {\n      \"id\": \"6235a6e8-21ee-4498-9c95-b3816efe0dfc\",\n      \"name\": \"address\",\n      \"description\": \"OpenID Connect built-in scope: address\",\n      \"protocol\": \"openid-connect\",\n      \"attributes\": {\n        \"include.in.token.scope\": \"true\",\n        \"consent.screen.text\": \"${addressScopeConsentText}\",\n        \"display.on.consent.screen\": \"true\"\n      },\n      \"protocolMappers\": [\n        {\n          \"id\": \"1b5f1955-723a-4ec5-a8eb-578fb9e9ebb0\",\n          \"name\": \"address\",\n          \"protocol\": \"openid-connect\",\n          \"protocolMapper\": \"oidc-address-mapper\",\n          \"consentRequired\": false,\n          \"config\": {\n            \"user.attribute.formatted\": \"formatted\",\n            \"user.attribute.country\": \"country\",\n            \"introspection.token.claim\": \"true\",\n            \"user.attribute.postal_code\": \"postal_code\",\n            \"userinfo.token.claim\": \"true\",\n            \"user.attribute.street\": \"street\",\n            \"id.token.claim\": \"true\",\n            \"user.attribute.region\": \"region\",\n            \"access.token.claim\": \"true\",\n            \"user.attribute.locality\": \"locality\"\n          }\n        }\n      ]\n    },\n    {\n      \"id\": \"a9966629-729a-4d02-931c-cdbccc2ef6e1\",\n      \"name\": \"web-origins\",\n      \"description\": \"OpenID Connect scope for add allowed web origins to the access token\",\n      \"protocol\": \"openid-connect\",\n      \"attributes\": {\n        \"include.in.token.scope\": \"false\",\n        \"consent.screen.text\": \"\",\n        \"display.on.consent.screen\": \"false\"\n      },\n      \"protocolMappers\": [\n        {\n          \"id\": \"2038278c-eb80-42eb-828a-ce1a700bcf5d\",\n          \"name\": \"allowed web origins\",\n          \"protocol\": \"openid-connect\",\n          \"protocolMapper\": \"oidc-allowed-origins-mapper\",\n          \"consentRequired\": false,\n          \"config\": {\n            \"introspection.token.claim\": \"true\",\n            \"access.token.claim\": \"true\"\n          }\n        }\n      ]\n    }\n  ],\n  \"defaultDefaultClientScopes\": [\n    \"role_list\",\n    \"saml_organization\",\n    \"profile\",\n    \"email\",\n    \"roles\",\n    \"web-origins\",\n    \"acr\",\n    \"basic\"\n  ],\n  \"defaultOptionalClientScopes\": [\n    \"offline_access\",\n    \"address\",\n    \"phone\",\n    \"microprofile-jwt\",\n    \"organization\"\n  ],\n  \"browserSecurityHeaders\": {\n    \"contentSecurityPolicyReportOnly\": \"\",\n    \"xContentTypeOptions\": \"nosniff\",\n    \"referrerPolicy\": \"no-referrer\",\n    \"xRobotsTag\": \"none\",\n    \"xFrameOptions\": \"SAMEORIGIN\",\n    \"contentSecurityPolicy\": \"frame-src 'self'; frame-ancestors 'self'; object-src 'none';\",\n    \"strictTransportSecurity\": \"max-age=31536000; includeSubDomains\"\n  },\n  \"smtpServer\": {},\n  \"eventsEnabled\": false,\n  \"eventsListeners\": [\n    \"jboss-logging\"\n  ],\n  \"enabledEventTypes\": [],\n  \"adminEventsEnabled\": false,\n  \"adminEventsDetailsEnabled\": false,\n  \"identityProviders\": [],\n  \"identityProviderMappers\": [],\n  \"components\": {\n    \"org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy\": [\n      {\n        \"id\": \"816e3705-90b1-4aba-988e-100ff1effac8\",\n        \"name\": \"Allowed Client Scopes\",\n        \"providerId\": \"allowed-client-templates\",\n        \"subType\": \"authenticated\",\n        \"subComponents\": {},\n        \"config\": {\n          \"allow-default-scopes\": [\n            \"true\"\n          ]\n        }\n      },\n      {\n        \"id\": \"d17f76e9-3fc9-4e0b-ba62-1787cfaacf21\",\n        \"name\": \"Trusted Hosts\",\n        \"providerId\": \"trusted-hosts\",\n        \"subType\": \"anonymous\",\n        \"subComponents\": {},\n        \"config\": {\n          \"host-sending-registration-request-must-match\": [\n            \"true\"\n          ],\n          \"client-uris-must-match\": [\n            \"true\"\n          ]\n        }\n      },\n      {\n        \"id\": \"de42e33e-cf5f-40c6-8c0d-7bb4fd7cb91b\",\n        \"name\": \"Allowed Client Scopes\",\n        \"providerId\": \"allowed-client-templates\",\n        \"subType\": \"anonymous\",\n        \"subComponents\": {},\n        \"config\": {\n          \"allow-default-scopes\": [\n            \"true\"\n          ]\n        }\n      },\n      {\n        \"id\": \"a5989451-aad7-4b75-85cf-29340c3508d6\",\n        \"name\": \"Allowed Protocol Mapper Types\",\n        \"providerId\": \"allowed-protocol-mappers\",\n        \"subType\": \"authenticated\",\n        \"subComponents\": {},\n        \"config\": {\n          \"allowed-protocol-mapper-types\": [\n            \"saml-user-property-mapper\",\n            \"oidc-full-name-mapper\",\n            \"oidc-address-mapper\",\n            \"oidc-usermodel-property-mapper\",\n            \"oidc-usermodel-attribute-mapper\",\n            \"saml-user-attribute-mapper\",\n            \"saml-role-list-mapper\",\n            \"oidc-sha256-pairwise-sub-mapper\"\n          ]\n        }\n      },\n      {\n        \"id\": \"871c280c-5f17-4ec4-9fd6-f36171d56553\",\n        \"name\": \"Max Clients Limit\",\n        \"providerId\": \"max-clients\",\n        \"subType\": \"anonymous\",\n        \"subComponents\": {},\n        \"config\": {\n          \"max-clients\": [\n            \"200\"\n          ]\n        }\n      },\n      {\n        \"id\": \"fbf6f1c2-aabf-40ef-b764-8a677603d2cc\",\n        \"name\": \"Consent Required\",\n        \"providerId\": \"consent-required\",\n        \"subType\": \"anonymous\",\n        \"subComponents\": {},\n        \"config\": {}\n      },\n      {\n        \"id\": \"a6dc5c32-28cd-424f-b8ec-db381d5a8fdd\",\n        \"name\": \"Allowed Protocol Mapper Types\",\n        \"providerId\": \"allowed-protocol-mappers\",\n        \"subType\": \"anonymous\",\n        \"subComponents\": {},\n        \"config\": {\n          \"allowed-protocol-mapper-types\": [\n            \"oidc-address-mapper\",\n            \"saml-user-attribute-mapper\",\n            \"oidc-usermodel-attribute-mapper\",\n            \"oidc-full-name-mapper\",\n            \"saml-user-property-mapper\",\n            \"oidc-sha256-pairwise-sub-mapper\",\n            \"oidc-usermodel-property-mapper\",\n            \"saml-role-list-mapper\"\n          ]\n        }\n      },\n      {\n        \"id\": \"798a0205-2a20-436d-b15f-ec19ee70a277\",\n        \"name\": \"Full Scope Disabled\",\n        \"providerId\": \"scope\",\n        \"subType\": \"anonymous\",\n        \"subComponents\": {},\n        \"config\": {}\n      }\n    ],\n    \"org.keycloak.keys.KeyProvider\": [\n      {\n        \"id\": \"702a660b-9d47-4d4e-b0eb-326775910293\",\n        \"name\": \"aes-generated\",\n        \"providerId\": \"aes-generated\",\n        \"subComponents\": {},\n        \"config\": {\n          \"priority\": [\n            \"100\"\n          ]\n        }\n      },\n      {\n        \"id\": \"025d31ab-f248-4358-87d0-ec0e27bee344\",\n        \"name\": \"rsa-generated\",\n        \"providerId\": \"rsa-generated\",\n        \"subComponents\": {},\n        \"config\": {\n          \"priority\": [\n            \"100\"\n          ]\n        }\n      },\n      {\n        \"id\": \"efec8cce-6c75-4e89-9017-f553468e2811\",\n        \"name\": \"rsa-enc-generated\",\n        \"providerId\": \"rsa-enc-generated\",\n        \"subComponents\": {},\n        \"config\": {\n          \"priority\": [\n            \"100\"\n          ],\n          \"algorithm\": [\n            \"RSA-OAEP\"\n          ]\n        }\n      },\n      {\n        \"id\": \"40d62ca1-93bc-4110-b2dc-7d7079c45774\",\n        \"name\": \"hmac-generated-hs512\",\n        \"providerId\": \"hmac-generated\",\n        \"subComponents\": {},\n        \"config\": {\n          \"priority\": [\n            \"100\"\n          ],\n          \"algorithm\": [\n            \"HS512\"\n          ]\n        }\n      }\n    ]\n  },\n  \"internationalizationEnabled\": false,\n  \"supportedLocales\": [],\n  \"authenticationFlows\": [\n    {\n      \"id\": \"3ce2ce6d-7743-4e1b-8a31-291fcc7ae06f\",\n      \"alias\": \"Account verification options\",\n      \"description\": \"Method with which to verity the existing account\",\n      \"providerId\": \"basic-flow\",\n      \"topLevel\": false,\n      \"builtIn\": true,\n      \"authenticationExecutions\": [\n        {\n          \"authenticator\": \"idp-email-verification\",\n          \"authenticatorFlow\": false,\n          \"requirement\": \"ALTERNATIVE\",\n          \"priority\": 10,\n          \"autheticatorFlow\": false,\n          \"userSetupAllowed\": false\n        },\n        {\n          \"authenticatorFlow\": true,\n          \"requirement\": \"ALTERNATIVE\",\n          \"priority\": 20,\n          \"autheticatorFlow\": true,\n          \"flowAlias\": \"Verify Existing Account by Re-authentication\",\n          \"userSetupAllowed\": false\n        }\n      ]\n    },\n    {\n      \"id\": \"8267719e-7856-4694-a9eb-f405eca2aca5\",\n      \"alias\": \"Browser - Conditional OTP\",\n      \"description\": \"Flow to determine if the OTP is required for the authentication\",\n      \"providerId\": \"basic-flow\",\n      \"topLevel\": false,\n      \"builtIn\": true,\n      \"authenticationExecutions\": [\n        {\n          \"authenticator\": \"conditional-user-configured\",\n          \"authenticatorFlow\": false,\n          \"requirement\": \"REQUIRED\",\n          \"priority\": 10,\n          \"autheticatorFlow\": false,\n          \"userSetupAllowed\": false\n        },\n        {\n          \"authenticator\": \"auth-otp-form\",\n          \"authenticatorFlow\": false,\n          \"requirement\": \"REQUIRED\",\n          \"priority\": 20,\n          \"autheticatorFlow\": false,\n          \"userSetupAllowed\": false\n        }\n      ]\n    },\n    {\n      \"id\": \"596aae9f-ae33-415a-b9e8-de70ee954ac5\",\n      \"alias\": \"Browser - Conditional Organization\",\n      \"description\": \"Flow to determine if the organization identity-first login is to be used\",\n      \"providerId\": \"basic-flow\",\n      \"topLevel\": false,\n      \"builtIn\": true,\n      \"authenticationExecutions\": [\n        {\n          \"authenticator\": \"conditional-user-configured\",\n          \"authenticatorFlow\": false,\n          \"requirement\": \"REQUIRED\",\n          \"priority\": 10,\n          \"autheticatorFlow\": false,\n          \"userSetupAllowed\": false\n        },\n        {\n          \"authenticator\": \"organization\",\n          \"authenticatorFlow\": false,\n          \"requirement\": \"ALTERNATIVE\",\n          \"priority\": 20,\n          \"autheticatorFlow\": false,\n          \"userSetupAllowed\": false\n        }\n      ]\n    },\n    {\n      \"id\": \"068702f9-b6d9-489e-af34-8b9f325a361b\",\n      \"alias\": \"Direct Grant - Conditional OTP\",\n      \"description\": \"Flow to determine if the OTP is required for the authentication\",\n      \"providerId\": \"basic-flow\",\n      \"topLevel\": false,\n      \"builtIn\": true,\n      \"authenticationExecutions\": [\n        {\n          \"authenticator\": \"conditional-user-configured\",\n          \"authenticatorFlow\": false,\n          \"requirement\": \"REQUIRED\",\n          \"priority\": 10,\n          \"autheticatorFlow\": false,\n          \"userSetupAllowed\": false\n        },\n        {\n          \"authenticator\": \"direct-grant-validate-otp\",\n          \"authenticatorFlow\": false,\n          \"requirement\": \"REQUIRED\",\n          \"priority\": 20,\n          \"autheticatorFlow\": false,\n          \"userSetupAllowed\": false\n        }\n      ]\n    },\n    {\n      \"id\": \"0459a690-8543-422c-bc83-94e8c62c8bdd\",\n      \"alias\": \"First Broker Login - Conditional Organization\",\n      \"description\": \"Flow to determine if the authenticator that adds organization members is to be used\",\n      \"providerId\": \"basic-flow\",\n      \"topLevel\": false,\n      \"builtIn\": true,\n      \"authenticationExecutions\": [\n        {\n          \"authenticator\": \"conditional-user-configured\",\n          \"authenticatorFlow\": false,\n          \"requirement\": \"REQUIRED\",\n          \"priority\": 10,\n          \"autheticatorFlow\": false,\n          \"userSetupAllowed\": false\n        },\n        {\n          \"authenticator\": \"idp-add-organization-member\",\n          \"authenticatorFlow\": false,\n          \"requirement\": \"REQUIRED\",\n          \"priority\": 20,\n          \"autheticatorFlow\": false,\n          \"userSetupAllowed\": false\n        }\n      ]\n    },\n    {\n      \"id\": \"31cb5a9b-b319-45d7-980d-cc6cd8a9e579\",\n      \"alias\": \"First broker login - Conditional OTP\",\n      \"description\": \"Flow to determine if the OTP is required for the authentication\",\n      \"providerId\": \"basic-flow\",\n      \"topLevel\": false,\n      \"builtIn\": true,\n      \"authenticationExecutions\": [\n        {\n          \"authenticator\": \"conditional-user-configured\",\n          \"authenticatorFlow\": false,\n          \"requirement\": \"REQUIRED\",\n          \"priority\": 10,\n          \"autheticatorFlow\": false,\n          \"userSetupAllowed\": false\n        },\n        {\n          \"authenticator\": \"auth-otp-form\",\n          \"authenticatorFlow\": false,\n          \"requirement\": \"REQUIRED\",\n          \"priority\": 20,\n          \"autheticatorFlow\": false,\n          \"userSetupAllowed\": false\n        }\n      ]\n    },\n    {\n      \"id\": \"7448795c-59cf-4a43-9af8-a988cdc1e7b6\",\n      \"alias\": \"Handle Existing Account\",\n      \"description\": \"Handle what to do if there is existing account with same email/username like authenticated identity provider\",\n      \"providerId\": \"basic-flow\",\n      \"topLevel\": false,\n      \"builtIn\": true,\n      \"authenticationExecutions\": [\n        {\n          \"authenticator\": \"idp-confirm-link\",\n          \"authenticatorFlow\": false,\n          \"requirement\": \"REQUIRED\",\n          \"priority\": 10,\n          \"autheticatorFlow\": false,\n          \"userSetupAllowed\": false\n        },\n        {\n          \"authenticatorFlow\": true,\n          \"requirement\": \"REQUIRED\",\n          \"priority\": 20,\n          \"autheticatorFlow\": true,\n          \"flowAlias\": \"Account verification options\",\n          \"userSetupAllowed\": false\n        }\n      ]\n    },\n    {\n      \"id\": \"c18be560-2806-4c78-942d-00d4e32b0339\",\n      \"alias\": \"Organization\",\n      \"providerId\": \"basic-flow\",\n      \"topLevel\": false,\n      \"builtIn\": true,\n      \"authenticationExecutions\": [\n        {\n          \"authenticatorFlow\": true,\n          \"requirement\": \"CONDITIONAL\",\n          \"priority\": 10,\n          \"autheticatorFlow\": true,\n          \"flowAlias\": \"Browser - Conditional Organization\",\n          \"userSetupAllowed\": false\n        }\n      ]\n    },\n    {\n      \"id\": \"498a92fe-00bb-4419-a9e1-c08dcc55c0b9\",\n      \"alias\": \"Reset - Conditional OTP\",\n      \"description\": \"Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.\",\n      \"providerId\": \"basic-flow\",\n      \"topLevel\": false,\n      \"builtIn\": true,\n      \"authenticationExecutions\": [\n        {\n          \"authenticator\": \"conditional-user-configured\",\n          \"authenticatorFlow\": false,\n          \"requirement\": \"REQUIRED\",\n          \"priority\": 10,\n          \"autheticatorFlow\": false,\n          \"userSetupAllowed\": false\n        },\n        {\n          \"authenticator\": \"reset-otp\",\n          \"authenticatorFlow\": false,\n          \"requirement\": \"REQUIRED\",\n          \"priority\": 20,\n          \"autheticatorFlow\": false,\n          \"userSetupAllowed\": false\n        }\n      ]\n    },\n    {\n      \"id\": \"f19dc4c2-1167-41f7-8573-ecf19f285c9e\",\n      \"alias\": \"User creation or linking\",\n      \"description\": \"Flow for the existing/non-existing user alternatives\",\n      \"providerId\": \"basic-flow\",\n      \"topLevel\": false,\n      \"builtIn\": true,\n      \"authenticationExecutions\": [\n        {\n          \"authenticatorConfig\": \"create unique user config\",\n          \"authenticator\": \"idp-create-user-if-unique\",\n          \"authenticatorFlow\": false,\n          \"requirement\": \"ALTERNATIVE\",\n          \"priority\": 10,\n          \"autheticatorFlow\": false,\n          \"userSetupAllowed\": false\n        },\n        {\n          \"authenticatorFlow\": true,\n          \"requirement\": \"ALTERNATIVE\",\n          \"priority\": 20,\n          \"autheticatorFlow\": true,\n          \"flowAlias\": \"Handle Existing Account\",\n          \"userSetupAllowed\": false\n        }\n      ]\n    },\n    {\n      \"id\": \"fb78126b-7892-4da6-adc0-58a9b74e0a0d\",\n      \"alias\": \"Verify Existing Account by Re-authentication\",\n      \"description\": \"Reauthentication of existing account\",\n      \"providerId\": \"basic-flow\",\n      \"topLevel\": false,\n      \"builtIn\": true,\n      \"authenticationExecutions\": [\n        {\n          \"authenticator\": \"idp-username-password-form\",\n          \"authenticatorFlow\": false,\n          \"requirement\": \"REQUIRED\",\n          \"priority\": 10,\n          \"autheticatorFlow\": false,\n          \"userSetupAllowed\": false\n        },\n        {\n          \"authenticatorFlow\": true,\n          \"requirement\": \"CONDITIONAL\",\n          \"priority\": 20,\n          \"autheticatorFlow\": true,\n          \"flowAlias\": \"First broker login - Conditional OTP\",\n          \"userSetupAllowed\": false\n        }\n      ]\n    },\n    {\n      \"id\": \"2a393886-1bea-48bd-823b-485d4ae4a6a6\",\n      \"alias\": \"browser\",\n      \"description\": \"Browser based authentication\",\n      \"providerId\": \"basic-flow\",\n      \"topLevel\": true,\n      \"builtIn\": true,\n      \"authenticationExecutions\": [\n        {\n          \"authenticator\": \"auth-cookie\",\n          \"authenticatorFlow\": false,\n          \"requirement\": \"ALTERNATIVE\",\n          \"priority\": 10,\n          \"autheticatorFlow\": false,\n          \"userSetupAllowed\": false\n        },\n        {\n          \"authenticator\": \"auth-spnego\",\n          \"authenticatorFlow\": false,\n          \"requirement\": \"DISABLED\",\n          \"priority\": 20,\n          \"autheticatorFlow\": false,\n          \"userSetupAllowed\": false\n        },\n        {\n          \"authenticator\": \"identity-provider-redirector\",\n          \"authenticatorFlow\": false,\n          \"requirement\": \"ALTERNATIVE\",\n          \"priority\": 25,\n          \"autheticatorFlow\": false,\n          \"userSetupAllowed\": false\n        },\n        {\n          \"authenticatorFlow\": true,\n          \"requirement\": \"ALTERNATIVE\",\n          \"priority\": 26,\n          \"autheticatorFlow\": true,\n          \"flowAlias\": \"Organization\",\n          \"userSetupAllowed\": false\n        },\n        {\n          \"authenticatorFlow\": true,\n          \"requirement\": \"ALTERNATIVE\",\n          \"priority\": 30,\n          \"autheticatorFlow\": true,\n          \"flowAlias\": \"forms\",\n          \"userSetupAllowed\": false\n        }\n      ]\n    },\n    {\n      \"id\": \"8df87113-974a-43b0-80cc-4a86a8eb907a\",\n      \"alias\": \"clients\",\n      \"description\": \"Base authentication for clients\",\n      \"providerId\": \"client-flow\",\n      \"topLevel\": true,\n      \"builtIn\": true,\n      \"authenticationExecutions\": [\n        {\n          \"authenticator\": \"client-secret\",\n          \"authenticatorFlow\": false,\n          \"requirement\": \"ALTERNATIVE\",\n          \"priority\": 10,\n          \"autheticatorFlow\": false,\n          \"userSetupAllowed\": false\n        },\n        {\n          \"authenticator\": \"client-jwt\",\n          \"authenticatorFlow\": false,\n          \"requirement\": \"ALTERNATIVE\",\n          \"priority\": 20,\n          \"autheticatorFlow\": false,\n          \"userSetupAllowed\": false\n        },\n        {\n          \"authenticator\": \"client-secret-jwt\",\n          \"authenticatorFlow\": false,\n          \"requirement\": \"ALTERNATIVE\",\n          \"priority\": 30,\n          \"autheticatorFlow\": false,\n          \"userSetupAllowed\": false\n        },\n        {\n          \"authenticator\": \"client-x509\",\n          \"authenticatorFlow\": false,\n          \"requirement\": \"ALTERNATIVE\",\n          \"priority\": 40,\n          \"autheticatorFlow\": false,\n          \"userSetupAllowed\": false\n        }\n      ]\n    },\n    {\n      \"id\": \"f3116f33-e9e1-439d-8997-5496b244640e\",\n      \"alias\": \"direct grant\",\n      \"description\": \"OpenID Connect Resource Owner Grant\",\n      \"providerId\": \"basic-flow\",\n      \"topLevel\": true,\n      \"builtIn\": true,\n      \"authenticationExecutions\": [\n        {\n          \"authenticator\": \"direct-grant-validate-username\",\n          \"authenticatorFlow\": false,\n          \"requirement\": \"REQUIRED\",\n          \"priority\": 10,\n          \"autheticatorFlow\": false,\n          \"userSetupAllowed\": false\n        },\n        {\n          \"authenticator\": \"direct-grant-validate-password\",\n          \"authenticatorFlow\": false,\n          \"requirement\": \"REQUIRED\",\n          \"priority\": 20,\n          \"autheticatorFlow\": false,\n          \"userSetupAllowed\": false\n        },\n        {\n          \"authenticatorFlow\": true,\n          \"requirement\": \"CONDITIONAL\",\n          \"priority\": 30,\n          \"autheticatorFlow\": true,\n          \"flowAlias\": \"Direct Grant - Conditional OTP\",\n          \"userSetupAllowed\": false\n        }\n      ]\n    },\n    {\n      \"id\": \"05f713a9-caaf-4f5f-8df0-3423ee1d3b2e\",\n      \"alias\": \"docker auth\",\n      \"description\": \"Used by Docker clients to authenticate against the IDP\",\n      \"providerId\": \"basic-flow\",\n      \"topLevel\": true,\n      \"builtIn\": true,\n      \"authenticationExecutions\": [\n        {\n          \"authenticator\": \"docker-http-basic-authenticator\",\n          \"authenticatorFlow\": false,\n          \"requirement\": \"REQUIRED\",\n          \"priority\": 10,\n          \"autheticatorFlow\": false,\n          \"userSetupAllowed\": false\n        }\n      ]\n    },\n    {\n      \"id\": \"caa3d932-2aad-42c4-9e63-de8d32c8858c\",\n      \"alias\": \"first broker login\",\n      \"description\": \"Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account\",\n      \"providerId\": \"basic-flow\",\n      \"topLevel\": true,\n      \"builtIn\": true,\n      \"authenticationExecutions\": [\n        {\n          \"authenticatorConfig\": \"review profile config\",\n          \"authenticator\": \"idp-review-profile\",\n          \"authenticatorFlow\": false,\n          \"requirement\": \"REQUIRED\",\n          \"priority\": 10,\n          \"autheticatorFlow\": false,\n          \"userSetupAllowed\": false\n        },\n        {\n          \"authenticatorFlow\": true,\n          \"requirement\": \"REQUIRED\",\n          \"priority\": 20,\n          \"autheticatorFlow\": true,\n          \"flowAlias\": \"User creation or linking\",\n          \"userSetupAllowed\": false\n        },\n        {\n          \"authenticatorFlow\": true,\n          \"requirement\": \"CONDITIONAL\",\n          \"priority\": 50,\n          \"autheticatorFlow\": true,\n          \"flowAlias\": \"First Broker Login - Conditional Organization\",\n          \"userSetupAllowed\": false\n        }\n      ]\n    },\n    {\n      \"id\": \"eba73d10-65cf-4364-8969-92571fe69b72\",\n      \"alias\": \"forms\",\n      \"description\": \"Username, password, otp and other auth forms.\",\n      \"providerId\": \"basic-flow\",\n      \"topLevel\": false,\n      \"builtIn\": true,\n      \"authenticationExecutions\": [\n        {\n          \"authenticator\": \"auth-username-password-form\",\n          \"authenticatorFlow\": false,\n          \"requirement\": \"REQUIRED\",\n          \"priority\": 10,\n          \"autheticatorFlow\": false,\n          \"userSetupAllowed\": false\n        },\n        {\n          \"authenticatorFlow\": true,\n          \"requirement\": \"CONDITIONAL\",\n          \"priority\": 20,\n          \"autheticatorFlow\": true,\n          \"flowAlias\": \"Browser - Conditional OTP\",\n          \"userSetupAllowed\": false\n        }\n      ]\n    },\n    {\n      \"id\": \"e2d23ce6-e37d-46f1-83fd-b18076d81aeb\",\n      \"alias\": \"registration\",\n      \"description\": \"Registration flow\",\n      \"providerId\": \"basic-flow\",\n      \"topLevel\": true,\n      \"builtIn\": true,\n      \"authenticationExecutions\": [\n        {\n          \"authenticator\": \"registration-page-form\",\n          \"authenticatorFlow\": true,\n          \"requirement\": \"REQUIRED\",\n          \"priority\": 10,\n          \"autheticatorFlow\": true,\n          \"flowAlias\": \"registration form\",\n          \"userSetupAllowed\": false\n        }\n      ]\n    },\n    {\n      \"id\": \"00d69e38-630a-4215-a635-e71849ae2abc\",\n      \"alias\": \"registration form\",\n      \"description\": \"Registration form\",\n      \"providerId\": \"form-flow\",\n      \"topLevel\": false,\n      \"builtIn\": true,\n      \"authenticationExecutions\": [\n        {\n          \"authenticator\": \"registration-user-creation\",\n          \"authenticatorFlow\": false,\n          \"requirement\": \"REQUIRED\",\n          \"priority\": 20,\n          \"autheticatorFlow\": false,\n          \"userSetupAllowed\": false\n        },\n        {\n          \"authenticator\": \"registration-password-action\",\n          \"authenticatorFlow\": false,\n          \"requirement\": \"REQUIRED\",\n          \"priority\": 50,\n          \"autheticatorFlow\": false,\n          \"userSetupAllowed\": false\n        },\n        {\n          \"authenticator\": \"registration-recaptcha-action\",\n          \"authenticatorFlow\": false,\n          \"requirement\": \"DISABLED\",\n          \"priority\": 60,\n          \"autheticatorFlow\": false,\n          \"userSetupAllowed\": false\n        },\n        {\n          \"authenticator\": \"registration-terms-and-conditions\",\n          \"authenticatorFlow\": false,\n          \"requirement\": \"DISABLED\",\n          \"priority\": 70,\n          \"autheticatorFlow\": false,\n          \"userSetupAllowed\": false\n        }\n      ]\n    },\n    {\n      \"id\": \"fe3aae15-d563-4576-a709-4ba3a40c540e\",\n      \"alias\": \"reset credentials\",\n      \"description\": \"Reset credentials for a user if they forgot their password or something\",\n      \"providerId\": \"basic-flow\",\n      \"topLevel\": true,\n      \"builtIn\": true,\n      \"authenticationExecutions\": [\n        {\n          \"authenticator\": \"reset-credentials-choose-user\",\n          \"authenticatorFlow\": false,\n          \"requirement\": \"REQUIRED\",\n          \"priority\": 10,\n          \"autheticatorFlow\": false,\n          \"userSetupAllowed\": false\n        },\n        {\n          \"authenticator\": \"reset-credential-email\",\n          \"authenticatorFlow\": false,\n          \"requirement\": \"REQUIRED\",\n          \"priority\": 20,\n          \"autheticatorFlow\": false,\n          \"userSetupAllowed\": false\n        },\n        {\n          \"authenticator\": \"reset-password\",\n          \"authenticatorFlow\": false,\n          \"requirement\": \"REQUIRED\",\n          \"priority\": 30,\n          \"autheticatorFlow\": false,\n          \"userSetupAllowed\": false\n        },\n        {\n          \"authenticatorFlow\": true,\n          \"requirement\": \"CONDITIONAL\",\n          \"priority\": 40,\n          \"autheticatorFlow\": true,\n          \"flowAlias\": \"Reset - Conditional OTP\",\n          \"userSetupAllowed\": false\n        }\n      ]\n    },\n    {\n      \"id\": \"ffedec01-f274-4b58-ab70-178ff4e8c569\",\n      \"alias\": \"saml ecp\",\n      \"description\": \"SAML ECP Profile Authentication Flow\",\n      \"providerId\": \"basic-flow\",\n      \"topLevel\": true,\n      \"builtIn\": true,\n      \"authenticationExecutions\": [\n        {\n          \"authenticator\": \"http-basic-authenticator\",\n          \"authenticatorFlow\": false,\n          \"requirement\": \"REQUIRED\",\n          \"priority\": 10,\n          \"autheticatorFlow\": false,\n          \"userSetupAllowed\": false\n        }\n      ]\n    }\n  ],\n  \"authenticatorConfig\": [\n    {\n      \"id\": \"3911f29c-6c6a-418c-93a8-72ba806d715b\",\n      \"alias\": \"create unique user config\",\n      \"config\": {\n        \"require.password.update.after.registration\": \"false\"\n      }\n    },\n    {\n      \"id\": \"dc544a68-9478-4679-8a61-76e9afb84757\",\n      \"alias\": \"review profile config\",\n      \"config\": {\n        \"update.profile.on.first.login\": \"missing\"\n      }\n    }\n  ],\n  \"requiredActions\": [\n    {\n      \"alias\": \"CONFIGURE_TOTP\",\n      \"name\": \"Configure OTP\",\n      \"providerId\": \"CONFIGURE_TOTP\",\n      \"enabled\": true,\n      \"defaultAction\": false,\n      \"priority\": 10,\n      \"config\": {}\n    },\n    {\n      \"alias\": \"TERMS_AND_CONDITIONS\",\n      \"name\": \"Terms and Conditions\",\n      \"providerId\": \"TERMS_AND_CONDITIONS\",\n      \"enabled\": false,\n      \"defaultAction\": false,\n      \"priority\": 20,\n      \"config\": {}\n    },\n    {\n      \"alias\": \"UPDATE_PASSWORD\",\n      \"name\": \"Update Password\",\n      \"providerId\": \"UPDATE_PASSWORD\",\n      \"enabled\": true,\n      \"defaultAction\": false,\n      \"priority\": 30,\n      \"config\": {}\n    },\n    {\n      \"alias\": \"UPDATE_PROFILE\",\n      \"name\": \"Update Profile\",\n      \"providerId\": \"UPDATE_PROFILE\",\n      \"enabled\": true,\n      \"defaultAction\": false,\n      \"priority\": 40,\n      \"config\": {}\n    },\n    {\n      \"alias\": \"VERIFY_EMAIL\",\n      \"name\": \"Verify Email\",\n      \"providerId\": \"VERIFY_EMAIL\",\n      \"enabled\": true,\n      \"defaultAction\": false,\n      \"priority\": 50,\n      \"config\": {}\n    },\n    {\n      \"alias\": \"delete_account\",\n      \"name\": \"Delete Account\",\n      \"providerId\": \"delete_account\",\n      \"enabled\": false,\n      \"defaultAction\": false,\n      \"priority\": 60,\n      \"config\": {}\n    },\n    {\n      \"alias\": \"webauthn-register\",\n      \"name\": \"Webauthn Register\",\n      \"providerId\": \"webauthn-register\",\n      \"enabled\": true,\n      \"defaultAction\": false,\n      \"priority\": 70,\n      \"config\": {}\n    },\n    {\n      \"alias\": \"webauthn-register-passwordless\",\n      \"name\": \"Webauthn Register Passwordless\",\n      \"providerId\": \"webauthn-register-passwordless\",\n      \"enabled\": true,\n      \"defaultAction\": false,\n      \"priority\": 80,\n      \"config\": {}\n    },\n    {\n      \"alias\": \"VERIFY_PROFILE\",\n      \"name\": \"Verify Profile\",\n      \"providerId\": \"VERIFY_PROFILE\",\n      \"enabled\": true,\n      \"defaultAction\": false,\n      \"priority\": 90,\n      \"config\": {}\n    },\n    {\n      \"alias\": \"delete_credential\",\n      \"name\": \"Delete Credential\",\n      \"providerId\": \"delete_credential\",\n      \"enabled\": true,\n      \"defaultAction\": false,\n      \"priority\": 100,\n      \"config\": {}\n    },\n    {\n      \"alias\": \"update_user_locale\",\n      \"name\": \"Update User Locale\",\n      \"providerId\": \"update_user_locale\",\n      \"enabled\": true,\n      \"defaultAction\": false,\n      \"priority\": 1000,\n      \"config\": {}\n    }\n  ],\n  \"browserFlow\": \"browser\",\n  \"registrationFlow\": \"registration\",\n  \"directGrantFlow\": \"direct grant\",\n  \"resetCredentialsFlow\": \"reset credentials\",\n  \"clientAuthenticationFlow\": \"clients\",\n  \"dockerAuthenticationFlow\": \"docker auth\",\n  \"firstBrokerLoginFlow\": \"first broker login\",\n  \"attributes\": {\n    \"cibaBackchannelTokenDeliveryMode\": \"poll\",\n    \"cibaExpiresIn\": \"120\",\n    \"cibaAuthRequestedUserHint\": \"login_hint\",\n    \"oauth2DeviceCodeLifespan\": \"600\",\n    \"clientOfflineSessionMaxLifespan\": \"0\",\n    \"oauth2DevicePollingInterval\": \"5\",\n    \"clientSessionIdleTimeout\": \"0\",\n    \"parRequestUriLifespan\": \"60\",\n    \"clientSessionMaxLifespan\": \"0\",\n    \"clientOfflineSessionIdleTimeout\": \"0\",\n    \"cibaInterval\": \"5\",\n    \"realmReusableOtpCode\": \"false\"\n  },\n  \"keycloakVersion\": \"26.2.5\",\n  \"userManagedAccessAllowed\": false,\n  \"organizationsEnabled\": false,\n  \"verifiableCredentialsEnabled\": false,\n  \"adminPermissionsEnabled\": false,\n  \"clientProfiles\": {\n    \"profiles\": []\n  },\n  \"clientPolicies\": {\n    \"policies\": []\n  }\n}"
  },
  {
    "path": "spark-3/src/test/scala/org/neo4j/spark/DataSourceAggregationTSE.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark\n\nimport org.junit.Assert.assertEquals\nimport org.junit.Test\nimport org.neo4j.driver.Transaction\nimport org.neo4j.driver.TransactionWork\nimport org.neo4j.driver.summary.ResultSummary\n\nclass DataSourceReaderAggregationTSE extends SparkConnectorScalaBaseTSE {\n\n  @Test\n  def testShouldDoSumAggregation(): Unit = {\n    val fixtureQuery: String =\n      s\"\"\"CREATE (pe:Person {id: 1, fullName: 'Person'})-[:BOUGHT{when: rand(), quantity: rand() * 1000}]->(pr:Product {id: 0, name: 'Product ' + 0, price: 1})\n         |WITH pe\n         |UNWIND range(1, 10) as id\n         |CREATE (pr:Product {id: id * rand(), name: 'Product ' + id, price: id})\n         |CREATE (pe)-[:BOUGHT{when: rand(), quantity: rand() * 1000}]->(pr)\n         |RETURN *\n    \"\"\".stripMargin\n\n    SparkConnectorScalaSuiteIT.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(fixtureQuery).consume()\n        }\n      )\n\n    ss.read\n      .format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"relationship\", \"BOUGHT\")\n      .option(\"relationship.source.labels\", \"Person\")\n      .option(\"relationship.target.labels\", \"Product\")\n      .load\n      .createTempView(\"BOUGHT\")\n\n    val df = ss.sql(\n      \"\"\"SELECT `source.fullName`, SUM(DISTINCT(`target.price`)) AS distinctTotal, SUM(`target.price`) AS total\n        |FROM BOUGHT\n        |group by `source.fullName`\"\"\".stripMargin\n    )\n\n    val rows = df.collect().toList\n    assertEquals(1, rows.length)\n    val row = rows(0)\n    assertEquals(\"Person\", row.getAs[String](\"source.fullName\"))\n    assertEquals(55L, row.getAs[Long](\"distinctTotal\"))\n    assertEquals(56L, row.getAs[Long](\"total\"))\n  }\n\n  @Test\n  def testShouldDoMaxMinAggregation(): Unit = {\n    val fixtureQuery: String =\n      s\"\"\"CREATE (pe:Person {id: 1, fullName: 'Person'})\n         |WITH pe\n         |UNWIND range(1, 10) as id\n         |CREATE (pr:Product {id: id * rand(), name: 'Product ' + id, price: id})\n         |CREATE (pe)-[:BOUGHT{when: rand(), quantity: rand() * 1000}]->(pr)\n         |RETURN *\n    \"\"\".stripMargin\n\n    SparkConnectorScalaSuiteIT.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(fixtureQuery).consume()\n        }\n      )\n\n    ss.read\n      .format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"relationship\", \"BOUGHT\")\n      .option(\"relationship.source.labels\", \"Person\")\n      .option(\"relationship.target.labels\", \"Product\")\n      .load\n      .createTempView(\"BOUGHT\")\n\n    val df = ss.sql(\n      \"\"\"SELECT `source.fullName`, MAX(`target.price`) AS max, MIN(`target.price`) AS min\n        |FROM BOUGHT\n        |GROUP BY `source.fullName`\"\"\".stripMargin\n    )\n\n    val rows = df.collect().toList\n    assertEquals(1, rows.length)\n    val row = rows(0)\n    assertEquals(\"Person\", row.getAs[String](\"source.fullName\"))\n    assertEquals(10L, row.getAs[Long](\"max\"))\n    assertEquals(1L, row.getAs[Long](\"min\"))\n  }\n\n  @Test\n  def testShouldDoCountAggregation(): Unit = {\n    val fixtureQuery: String =\n      s\"\"\"CREATE (pe:Person {id: 1, fullName: 'Person'})-[:BOUGHT{when: rand(), quantity: rand() * 1000}]->(pr:Product {id: 1, name: 'Product 1', price: 1})\n         |WITH pe\n         |UNWIND range(1, 10) as id\n         |MERGE (pr:Product {id: id, name: 'Product ' + id, price: id})\n         |CREATE (pe)-[:BOUGHT{when: rand(), quantity: rand() * 1000}]->(pr)\n         |RETURN *\n    \"\"\".stripMargin\n\n    SparkConnectorScalaSuiteIT.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(fixtureQuery).consume()\n        }\n      )\n\n    ss.read\n      .format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"relationship\", \"BOUGHT\")\n      .option(\"relationship.source.labels\", \"Person\")\n      .option(\"relationship.target.labels\", \"Product\")\n      .load\n      .createTempView(\"BOUGHT\")\n\n    val df = ss.sql(\n      \"\"\"SELECT `source.fullName`, COUNT(DISTINCT(`target.id`)) AS distinctTotal, COUNT(`target.id`) AS total\n        |FROM BOUGHT\n        |group by `source.fullName`\"\"\".stripMargin\n    )\n\n    val rows = df.collect().toList\n    assertEquals(1, rows.length)\n    val row = rows(0)\n    assertEquals(\"Person\", row.getAs[String](\"source.fullName\"))\n    assertEquals(10L, row.getAs[Long](\"distinctTotal\"))\n    assertEquals(11L, row.getAs[Long](\"total\"))\n\n  }\n}\n"
  },
  {
    "path": "spark-3/src/test/scala/org/neo4j/spark/DataSourceReaderNeo4jTSE.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark\n\nimport org.apache.spark.SparkException\nimport org.apache.spark.sql.DataFrame\nimport org.junit.Assert.assertEquals\nimport org.junit.Assert.assertTrue\nimport org.junit.Assert.fail\nimport org.junit.Assume\nimport org.junit.BeforeClass\nimport org.junit.Test\nimport org.neo4j.Closeables.use\nimport org.neo4j.driver.SessionConfig\nimport org.neo4j.driver.Transaction\nimport org.neo4j.driver.TransactionWork\nimport org.neo4j.driver.exceptions.ClientException\nimport org.neo4j.driver.summary.ResultSummary\n\nclass DataSourceReaderNeo4jTSE extends SparkConnectorScalaBaseTSE {\n\n  @Test\n  def testMultiDbJoin(): Unit = {\n    SparkConnectorScalaSuiteIT.driver.session(SessionConfig.forDatabase(\"db1\"))\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(\n            \"\"\"\n      CREATE (p1:Person:Customer {name: 'John Doe'}),\n       (p2:Person:Customer {name: 'Mark Brown'}),\n       (p3:Person:Customer {name: 'Cindy White'})\n      \"\"\"\n          ).consume()\n        }\n      )\n\n    SparkConnectorScalaSuiteIT.driver.session(SessionConfig.forDatabase(\"db2\"))\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(\n            \"\"\"\n      CREATE (p1:Person:Employee {name: 'Jane Doe'}),\n       (p2:Person:Employee {name: 'John Doe'})\n      \"\"\"\n          ).consume()\n        }\n      )\n\n    val df1 = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"database\", \"db1\")\n      .option(\"labels\", \"Person\")\n      .load()\n\n    val df2 = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"database\", \"db2\")\n      .option(\"labels\", \"Person\")\n      .load()\n\n    assertEquals(3, df1.count())\n    assertEquals(2, df2.count())\n\n    val dfJoin = df1.join(df2, df1(\"name\") === df2(\"name\"))\n    assertEquals(1, dfJoin.count())\n  }\n\n  @Test\n  def testReadQueryCustomPartitions(): Unit = {\n    val fixtureProduct1Query: String =\n      \"\"\"CREATE (pr:Product{id: 1, name: 'Product 1'})\n        |WITH pr\n        |UNWIND range(1,100) as id\n        |CREATE (p:Person {id: id, name: 'Person ' + id})-[:BOUGHT{quantity: ceil(rand() * 100)}]->(pr)\n        |RETURN *\n    \"\"\".stripMargin\n    SparkConnectorScalaSuiteIT.driver.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(fixtureProduct1Query).consume()\n        }\n      )\n    val fixtureProduct2Query: String =\n      \"\"\"CREATE (pr:Product{id: 2, name: 'Product 2'})\n        |WITH pr\n        |UNWIND range(1,50) as id\n        |MATCH (p:Person {id: id})\n        |CREATE (p)-[:BOUGHT{quantity: ceil(rand() * 100)}]->(pr)\n        |RETURN *\n    \"\"\".stripMargin\n    SparkConnectorScalaSuiteIT.driver.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(fixtureProduct2Query).consume()\n        }\n      )\n\n    val partitionedDf = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\n        \"query\",\n        \"\"\"\n          |MATCH (p:Person)-[r:BOUGHT]->(pr:Product)\n          |RETURN p.name AS person, pr.name AS product, r.quantity AS quantity\"\"\".stripMargin\n      )\n      .option(\"partitions\", \"5\")\n      .load()\n\n    assertEquals(5, partitionedDf.rdd.getNumPartitions)\n    val rows = partitionedDf.collect()\n      .map(row => s\"${row.getAs[String](\"person\")}-${row.getAs[String](\"product\")}\")\n    assertEquals(150, rows.size)\n    assertEquals(150, rows.size)\n  }\n\n  @Test\n  def testCallShouldReturnCorrectSchema(): Unit = {\n    val callDf: DataFrame = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"query\", \"CALL db.info() YIELD id, name RETURN *\")\n      .load()\n\n    val res = callDf.select(\"name\")\n      .collectAsList()\n      .get(0)\n\n    assertEquals(res.getString(0), \"neo4j\")\n  }\n\n  @Test\n  def testShouldReturnJustTheSelectedFieldWithNode(): Unit = {\n    val total = 100\n    val fixtureQuery: String =\n      s\"\"\"UNWIND range(1, $total) as id\n         |CREATE (pr:Product {id: id, name: 'Product ' + id})\n         |RETURN *\n    \"\"\".stripMargin\n\n    SparkConnectorScalaSuiteIT.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(fixtureQuery).consume()\n        }\n      )\n\n    val df = ss.read\n      .format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"labels\", \"Product\")\n      .load\n      .select(\"name\")\n\n    df.count()\n\n    assertEquals(Seq(\"name\"), df.columns.toSeq)\n  }\n\n  @Test\n  def testShouldReturnJustTheSelectedFieldWithNodeAndWeirdColumnName(): Unit = {\n    val total = 100\n    val fixtureQuery: String =\n      s\"\"\"UNWIND range(1, $total) as id\n         |CREATE (pr:Product {id: id, `(╯°□°)╯︵ ┻━┻`: 'Product ' + id})\n         |RETURN *\n    \"\"\".stripMargin\n\n    SparkConnectorScalaSuiteIT.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(fixtureQuery).consume()\n        }\n      )\n\n    val df = ss.read\n      .format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"labels\", \"Product\")\n      .load\n      .select(\"`(╯°□°)╯︵ ┻━┻`\")\n\n    df.count()\n\n    assertEquals(Seq(\"(╯°□°)╯︵ ┻━┻\"), df.columns.toSeq)\n  }\n\n  @Test\n  def testShouldReturnJustTheSelectedFieldWithRelationship(): Unit = {\n    val total = 100\n    val fixtureQuery: String =\n      s\"\"\"UNWIND range(1, $total) as id\n         |CREATE (pr:Product {id: id * rand(), name: 'Product ' + id})\n         |CREATE (pe:Person {id: id, fullName: 'Person ' + id})\n         |CREATE (pe)-[:BOUGHT{when: rand(), quantity: rand() * 1000}]->(pr)\n         |RETURN *\n    \"\"\".stripMargin\n\n    SparkConnectorScalaSuiteIT.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(fixtureQuery).consume()\n        }\n      )\n\n    val df = ss.read\n      .format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"relationship\", \"BOUGHT\")\n      .option(\"relationship.source.labels\", \"Product\")\n      .option(\"relationship.target.labels\", \"Person\")\n      .load\n      .select(\"`source.name`\", \"`<source.id>`\")\n\n    df.count()\n\n    assertEquals(Seq(\"source.name\", \"<source.id>\"), df.columns.toSeq)\n  }\n\n  @Test\n  def testShouldReturnJustTheSelectedFieldWithRelationshipAndWeirdColumn(): Unit = {\n    val total = 100\n    val fixtureQuery: String =\n      s\"\"\"UNWIND range(1, $total) as id\n         |CREATE (pr:Product {id: id * rand(), `(╯°□°)╯︵ ┻━┻`: 'Product ' + id})\n         |CREATE (pe:Person {id: id, fullName: 'Person ' + id})\n         |CREATE (pe)-[:BOUGHT{when: rand(), quantity: rand() * 1000}]->(pr)\n         |RETURN *\n    \"\"\".stripMargin\n\n    SparkConnectorScalaSuiteIT.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(fixtureQuery).consume()\n        }\n      )\n\n    val df = ss.read\n      .format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"relationship\", \"BOUGHT\")\n      .option(\"relationship.source.labels\", \"Person\")\n      .option(\"relationship.target.labels\", \"Product\")\n      .load\n      .select(\"`target.(╯°□°)╯︵ ┻━┻`\", \"`<source.id>`\")\n\n    df.count()\n\n    assertEquals(Seq(\"target.(╯°□°)╯︵ ┻━┻\", \"<source.id>\"), df.columns.toSeq)\n  }\n\n  @Test\n  def testShouldReturnJustTheSelectedFieldWithQuery(): Unit = {\n    val total = 100\n    val fixtureQuery: String =\n      s\"\"\"UNWIND range(1, $total) as id\n         |CREATE (pr:Product {id: id * rand(), name: 'Product ' + id})\n         |CREATE (pe:Person {id: id, fullName: 'Person ' + id})\n         |CREATE (pe)-[:BOUGHT{when: rand(), quantity: rand() * 1000}]->(pr)\n         |RETURN *\n    \"\"\".stripMargin\n\n    SparkConnectorScalaSuiteIT.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(fixtureQuery).consume()\n        }\n      )\n\n    val df = ss.read\n      .format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"query\", \"MATCH (p:Product) RETURN p.name as name\")\n      .option(\"partitions\", 2)\n      .option(\"query.count\", 20)\n      .load\n      .select(\"name\")\n\n    df.count()\n\n    assertEquals(Seq(\"name\"), df.columns.toSeq)\n  }\n\n  @Test\n  def testShouldReturnJustTheSelectedFieldWithFilter(): Unit = {\n    val total = 100\n    val fixtureQuery: String =\n      s\"\"\"UNWIND range(1, $total) as id\n         |CREATE (pr:Product {id: id, name: 'Product ' + id})\n         |RETURN *\n    \"\"\".stripMargin\n\n    SparkConnectorScalaSuiteIT.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(fixtureQuery).consume()\n        }\n      )\n\n    val df = ss.read\n      .format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"labels\", \"Product\")\n      .load\n      .filter(\"name = 'Product 1'\")\n\n    df.count()\n\n    assertEquals(Seq(\"<id>\", \"<labels>\", \"name\", \"id\"), df.columns.toSeq)\n  }\n\n  @Test\n  def testShouldReturnJustTheSelectedFieldWithRelationshipWithFilter(): Unit = {\n    val total = 100\n    val fixtureQuery: String =\n      s\"\"\"UNWIND range(1, $total) as id\n         |CREATE (pr:Product {id: id * rand(), name: 'Product ' + id})\n         |CREATE (pe:Person {id: id, fullName: 'Person ' + id})\n         |CREATE (pe)-[:BOUGHT{when: rand(), quantity: rand() * 1000}]->(pr)\n         |RETURN *\n    \"\"\".stripMargin\n\n    SparkConnectorScalaSuiteIT.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(fixtureQuery).consume()\n        }\n      )\n\n    val df = ss.read\n      .format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"relationship\", \"BOUGHT\")\n      .option(\"relationship.source.labels\", \"Person\")\n      .option(\"relationship.target.labels\", \"Product\")\n      .load\n      .filter(\"`target.name` = 'Product 1' AND `target.id` = '16'\")\n      .select(\"`target.name`\", \"`target.id`\")\n\n    df.count()\n\n    assertEquals(Seq(\"target.name\", \"target.id\"), df.columns.toSeq)\n  }\n\n  @Test\n  def testShouldThrowClearErrorIfAWrongDbIsSpecified(): Unit = {\n    try {\n      ss.read.format(classOf[DataSource].getName)\n        .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n        .option(\"database\", \"not_existing_db\")\n        .option(\"labels\", \"MATCH (h:Household) RETURN id(h)\")\n        .load()\n        .show()\n    } catch {\n      case clientException: ClientException => {\n        assertTrue(clientException.getMessage.equals(\n          \"Database does not exist. Database name: 'not_existing_db'.\"\n        ))\n      }\n      case generic: Throwable =>\n        fail(s\"should be thrown a ${classOf[SparkException].getName}, got ${generic.getClass} instead\")\n    }\n  }\n\n  @Test\n  def testEmptyDataset(): Unit = {\n    val df = ss.read\n      .format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"query\", \"MATCH (e:ID_DO_NOT_EXIST) RETURN id(e) as f, 1 as g\")\n      .load\n\n    assertEquals(0, df.count())\n    assertEquals(Seq(\"f\", \"g\"), df.columns.toSeq)\n  }\n\n  @Test\n  def testColumnSorted(): Unit = {\n    SparkConnectorScalaSuiteIT.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary =\n            tx.run(\"CREATE (i1:Instrument{name: 'Drums', id: 1}), (i2:Instrument{name: 'Guitar', id: 2})\").consume()\n        }\n      )\n\n    val df = ss.read\n      .format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"query\", \"MATCH (i:Instrument) RETURN id(i) as internal_id, i.id as id, i.name as name, i.name\")\n      .load\n      .orderBy(\"id\")\n\n    assertEquals(1L, df.collectAsList().get(0).get(1))\n    assertEquals(\"Drums\", df.collectAsList().get(0).get(2))\n    assertEquals(Seq(\"internal_id\", \"id\", \"name\", \"i.name\"), df.columns.toSeq)\n  }\n\n  @Test\n  def testComplexReturnStatement(): Unit = {\n    val total = 100\n    val fixtureQuery: String =\n      s\"\"\"UNWIND range(1, $total) as id\n         |CREATE (pr:Product {id: id * rand(), name: 'Product ' + id})\n         |CREATE (pe:Person {id: id, fullName: 'Person ' + id})\n         |CREATE (pe)-[:BOUGHT{when: rand(), quantity: rand() * 1000}]->(pr)\n         |RETURN *\n    \"\"\".stripMargin\n\n    use(SparkConnectorScalaSuiteIT.session()) { session =>\n      session\n        .writeTransaction(\n          new TransactionWork[ResultSummary] {\n            override def execute(tx: Transaction): ResultSummary = tx.run(fixtureQuery).consume()\n          }\n        )\n    }\n\n    val df = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\n        \"query\",\n        \"\"\"MATCH (p:Person)-[b:BOUGHT]->(pr:Product)\n          |RETURN id(p) AS personId, id(pr) AS productId, {quantity: b.quantity, when: b.when} AS map, \"some string\" as someString, {anotherField: \"201\"} as map2\"\"\".stripMargin\n      )\n      .option(\"schema.strategy\", \"string\")\n      .load()\n\n    assertEquals(Seq(\"personId\", \"productId\", \"map\", \"someString\", \"map2\"), df.columns.toSeq)\n    assertEquals(100, df.count())\n  }\n\n  @Test\n  def testComplexReturnStatementNoValues(): Unit = {\n    val df = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\n        \"query\",\n        \"\"\"MATCH (p:Person)-[b:BOUGHT]->(pr:Product)\n          |RETURN id(p) AS personId, id(pr) AS productId, {quantity: b.quantity, when: b.when} AS map, \"some string\" as someString, {anotherField: \"201\", and: 1} as map2\"\"\".stripMargin\n      )\n      .option(\"schema.strategy\", \"string\")\n      .load()\n\n    assertEquals(Seq(\"personId\", \"productId\", \"map\", \"someString\", \"map2\"), df.columns.toSeq)\n    assertEquals(0, df.count())\n  }\n}\n"
  },
  {
    "path": "spark-3/src/test/scala/org/neo4j/spark/DataSourceReaderNeo4jWithApocTSE.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark\n\nimport org.junit.Assert.assertEquals\nimport org.junit.Assume\nimport org.junit.BeforeClass\nimport org.junit.Test\nimport org.neo4j.driver.SessionConfig\nimport org.neo4j.driver.Transaction\nimport org.neo4j.driver.TransactionWork\nimport org.neo4j.driver.summary.ResultSummary\n\nclass DataSourceReaderNeo4jWithApocTSE extends SparkConnectorScalaBaseWithApocTSE {\n\n  @Test\n  def testMultiDbJoin(): Unit = {\n    SparkConnectorScalaSuiteWithApocIT.driver.session(SessionConfig.forDatabase(\"db1\"))\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(\n            \"\"\"\n      CREATE (p1:Person:Customer {name: 'John Doe'}),\n       (p2:Person:Customer {name: 'Mark Brown'}),\n       (p3:Person:Customer {name: 'Cindy White'})\n      \"\"\"\n          ).consume()\n        }\n      )\n\n    SparkConnectorScalaSuiteWithApocIT.driver.session(SessionConfig.forDatabase(\"db2\"))\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(\n            \"\"\"\n      CREATE (p1:Person:Employee {name: 'Jane Doe'}),\n       (p2:Person:Employee {name: 'John Doe'})\n      \"\"\"\n          ).consume()\n        }\n      )\n\n    val df1 = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteWithApocIT.server.getBoltUrl)\n      .option(\"database\", \"db1\")\n      .option(\"labels\", \"Person\")\n      .load()\n\n    val df2 = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteWithApocIT.server.getBoltUrl)\n      .option(\"database\", \"db2\")\n      .option(\"labels\", \"Person\")\n      .load()\n\n    assertEquals(3, df1.count())\n    assertEquals(2, df2.count())\n\n    val dfJoin = df1.join(df2, df1(\"name\") === df2(\"name\"))\n    assertEquals(1, dfJoin.count())\n  }\n\n  @Test\n  def testReturnProcedure(): Unit = {\n    val query =\n      \"\"\"RETURN apoc.convert.toSet([1,1,3]) AS foo, 'bar' AS bar\n        |\"\"\".stripMargin\n\n    val df = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteWithApocIT.server.getBoltUrl)\n      .option(\"partitions\", 1)\n      .option(\"query\", query)\n      .load\n\n    assertEquals(Seq(\"foo\", \"bar\"), df.columns.toSeq) // ordering should be preserved\n    assertEquals(1, df.count())\n  }\n\n}\n"
  },
  {
    "path": "spark-3/src/test/scala/org/neo4j/spark/DataSourceReaderTSE.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark\n\nimport org.apache.spark.sql.DataFrame\nimport org.apache.spark.sql.Row\nimport org.apache.spark.sql.catalyst.expressions.GenericRowWithSchema\nimport org.apache.spark.sql.functions.col\nimport org.apache.spark.sql.types.DataTypes\nimport org.apache.spark.sql.types.StructField\nimport org.apache.spark.sql.types.StructType\nimport org.junit.Assert._\nimport org.junit.Test\nimport org.neo4j.driver.Transaction\nimport org.neo4j.driver.TransactionWork\nimport org.neo4j.driver.summary.ResultSummary\n\nimport java.sql.Timestamp\nimport java.time._\nimport java.util.TimeZone\n\nimport scala.collection.JavaConverters._\nimport scala.collection.mutable.Seq\n\nclass DataSourceReaderTSE extends SparkConnectorScalaBaseTSE {\n\n  @Test\n  def testThrowsExceptionIfNoValidReadOptionIsSet(): Unit = {\n    try {\n      ss.read.format(classOf[DataSource].getName)\n        .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n        .load()\n        .show() // we need the action to be able to trigger the exception because of the changes in Spark 3\n      org.junit.Assert.fail(\"Expected to throw an exception\")\n    } catch {\n      case e: IllegalArgumentException =>\n        assertEquals(\"No valid option found. One of `GDS`, `LABELS`, `QUERY`, `RELATIONSHIP` is required\", e.getMessage)\n      case _: Throwable => fail(s\"should be thrown a ${classOf[IllegalArgumentException].getName}\")\n    }\n  }\n\n  @Test\n  def testThrowsExceptionIfTwoValidReadOptionAreSet(): Unit = {\n    try {\n      ss.read.format(classOf[DataSource].getName)\n        .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n        .option(\"labels\", \"Person\")\n        .option(\"relationship\", \"KNOWS\")\n        .load()\n        .show() // we need the action to be able to trigger the exception because of the changes in Spark 3\n      org.junit.Assert.fail(\"Expected to throw an exception\")\n    } catch {\n      case e: IllegalArgumentException =>\n        assertEquals(\n          \"You need to specify just one of these options: 'gds', 'labels', 'query', 'relationship'\",\n          e.getMessage\n        )\n      case _: Throwable => fail(s\"should be thrown a ${classOf[IllegalArgumentException].getName}\")\n    }\n  }\n\n  @Test\n  def testThrowsExceptionIfThreeValidReadOptionAreSet(): Unit = {\n    try {\n      ss.read.format(classOf[DataSource].getName)\n        .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n        .option(\"labels\", \"Person\")\n        .option(\"relationship\", \"KNOWS\")\n        .option(\"query\", \"MATCH (n) RETURN n\")\n        .load()\n        .show() // we need the action to be able to trigger the exception because of the changes in Spark 3\n      org.junit.Assert.fail(\"Expected to throw an exception\")\n    } catch {\n      case e: IllegalArgumentException =>\n        assertEquals(\n          \"You need to specify just one of these options: 'gds', 'labels', 'query', 'relationship'\",\n          e.getMessage\n        )\n      case _: Throwable => fail(s\"should be thrown a ${classOf[IllegalArgumentException].getName}\")\n    }\n  }\n\n  @Test\n  def testReadNodeHasIdField(): Unit = {\n    val df: DataFrame = initTest(s\"CREATE (p:Person {name: 'John'})\")\n\n    /**\n     * utnaf: Since we can't be sure we are in total isolation, and the id is generated\n     * internally by org.neo4j.neo4j, we just check that the <id> field is an integer and is greater\n     * than -1\n     */\n    assertTrue(df.select(\"<id>\").collectAsList().get(0).getLong(0) > -1)\n  }\n\n  @Test\n  def testReadNodeHasLabelsField(): Unit = {\n    val df: DataFrame = initTest(s\"CREATE (p:Person:Customer {name: 'John'})\")\n\n    val result = df.select(\"<labels>\").collectAsList().get(0).getAs[Seq[String]](0)\n\n    assertEquals(\"Person\", result.head)\n    assertEquals(\"Customer\", result(1))\n  }\n\n  @Test\n  def testReadNodeHasUnusualLabelsField(): Unit = {\n    val df: DataFrame = initTest(s\"CREATE (p:`Foo Bar`:Person:`(╯°□°）╯︵ ┻━┻`  {name: 'John'})\")\n\n    val result = df.select(\"<labels>\").collectAsList().get(0).getAs[Seq[String]](0)\n\n    assertEquals(Set(\"Person\", \"Foo Bar\", \"(╯°□°）╯︵ ┻━┻\"), result.toSet[String])\n  }\n\n  @Test\n  def testReadNodeWithFieldWithDifferentTypes(): Unit = {\n    val df: DataFrame = initTest(\"CREATE (p1:Person {id: 1, field: [12,34]}), (p2:Person {id: 2, field: 123})\")\n\n    val res = df.orderBy(\"id\").collectAsList()\n\n    assertEquals(\"[12,34]\", res.get(0).get(3))\n    assertEquals(\"123\", res.get(1).get(3))\n  }\n\n  @Test\n  def testReadNodeWithString(): Unit = {\n    val name: String = \"John\"\n    val df: DataFrame = initTest(s\"CREATE (p:Person {name: '$name'})\")\n\n    assertEquals(name, df.select(\"name\").collectAsList().get(0).getString(0))\n  }\n\n  @Test\n  def testReadNodeWithLong(): Unit = {\n    val age: Long = 42\n    val df: DataFrame = initTest(s\"CREATE (p:Person {age: $age})\")\n\n    assertEquals(age, df.select(\"age\").collectAsList().get(0).getLong(0))\n  }\n\n  @Test\n  def testReadNodeWithDouble(): Unit = {\n    val score: Double = 3.14\n    val df: DataFrame = initTest(s\"CREATE (p:Person {score: $score})\")\n\n    assertEquals(score, df.select(\"score\").collectAsList().get(0).getDouble(0), 0)\n  }\n\n  @Test\n  def testReadNodeWithLocalTime(): Unit = {\n    val df: DataFrame =\n      initTest(s\"CREATE (p:Person {aTime: localtime({hour:12, minute: 23, second: 0, millisecond: 294})})\")\n\n    val result = df.select(\"aTime\").collectAsList().get(0).getAs[GenericRowWithSchema](0)\n    assertEquals(\"local-time\", result.get(0))\n    assertEquals(\"12:23:00.294\", result.get(1))\n  }\n\n  @Test\n  def testReadNodeWithTime(): Unit = {\n    val timezone = TimeZone.getDefault\n    val df: DataFrame = initTest(s\"CREATE (p:Person {aTime: time({hour:12, minute: 23, second: 0, millisecond: 294})})\")\n\n    val result = df.select(\"aTime\").collectAsList().get(0).getAs[GenericRowWithSchema](0)\n\n    val localTime = LocalTime.of(12, 23, 0, 294000000)\n    val expectedTime = OffsetTime.of(localTime, timezone.toZoneId.getRules.getOffset(Instant.now))\n\n    assertEquals(\"offset-time\", result.get(0))\n    assertEquals(expectedTime.toString, result.get(1))\n  }\n\n  @Test\n  def testReadNodeWithLocalDateTime(): Unit = {\n    val localDateTime = \"2007-12-03T10:15:30\"\n    val df: DataFrame = initTest(s\"CREATE (p:Person {aTime: localdatetime('$localDateTime')})\")\n    val result = df.select(\"aTime\").collectAsList().get(0).getAs[LocalDateTime](0)\n    assertEquals(LocalDateTime.parse(localDateTime), result)\n  }\n\n  @Test\n  def testReadNodeWithZonedDateTime(): Unit = {\n    val datetime = \"2015-06-24T12:50:35.556+01:00\"\n    val df: DataFrame = initTest(s\"CREATE (p:Person {aTime: datetime('$datetime')})\")\n\n    val result = df.select(\"aTime\").collectAsList().get(0).getTimestamp(0)\n\n    assertEquals(Timestamp.from(OffsetDateTime.parse(datetime).toInstant), result)\n  }\n\n  @Test\n  def testReadNodeWithPoint(): Unit = {\n    val df: DataFrame = initTest(s\"CREATE (p:Person {location: point({x: 12.12, y: 13.13})})\")\n\n    val res = df.select(\"location\").collectAsList().get(0).getAs[GenericRowWithSchema](0);\n\n    assertEquals(\"point-2d\", res.get(0))\n    assertEquals(7203, res.get(1))\n    assertEquals(12.12, res.get(2))\n    assertEquals(13.13, res.get(3))\n  }\n\n  @Test\n  def testReadNodeWithGeoPoint(): Unit = {\n    val df: DataFrame = initTest(s\"CREATE (p:Person {location: point({longitude: 12.12, latitude: 13.13})})\")\n\n    val res = df.select(\"location\").collectAsList().get(0).getAs[GenericRowWithSchema](0);\n\n    assertEquals(\"point-2d\", res.get(0))\n    assertEquals(4326, res.get(1))\n    assertEquals(12.12, res.get(2))\n    assertEquals(13.13, res.get(3))\n  }\n\n  @Test\n  def testReadNodeWithPoint3D(): Unit = {\n    val df: DataFrame = initTest(s\"CREATE (p:Person {location: point({x: 12.12, y: 13.13, z: 1})})\")\n\n    val res = df.select(\"location\").collectAsList().get(0).getAs[GenericRowWithSchema](0)\n\n    assertEquals(\"point-3d\", res.get(0))\n    assertEquals(9157, res.get(1))\n    assertEquals(12.12, res.get(2))\n    assertEquals(13.13, res.get(3))\n    assertEquals(1.0, res.get(4))\n  }\n\n  @Test\n  def testReadNodeWithDate(): Unit = {\n    val df: DataFrame = initTest(s\"CREATE (p:Person {born: date('2009-10-10')})\")\n\n    val list = df.select(\"born\").collectAsList()\n    val res = list.get(0).getDate(0)\n\n    assertEquals(java.sql.Date.valueOf(\"2009-10-10\"), res)\n  }\n\n  @Test\n  def testReadNodeWithDuration(): Unit = {\n    val df: DataFrame = initTest(s\"CREATE (p:Person {range: duration({days: 14, hours:16, minutes: 12})})\")\n\n    val list = df.select(\"range\").collectAsList()\n    val res = list.get(0).getAs[GenericRowWithSchema](0)\n\n    assertEquals(\"duration\", res(0))\n    assertEquals(0L, res(1))\n    assertEquals(14L, res(2))\n    assertEquals(58320L, res(3))\n    assertEquals(0, res(4))\n    assertEquals(\"P0M14DT58320S\", res(5))\n  }\n\n  @Test\n  def testReadNodeWithStringArray(): Unit = {\n    val df: DataFrame = initTest(s\"CREATE (p:Person {names: ['John', 'Doe']})\")\n\n    val res = df.select(\"names\").collectAsList().get(0).getAs[Seq[String]](0)\n\n    assertEquals(\"John\", res.head)\n    assertEquals(\"Doe\", res(1))\n  }\n\n  @Test\n  def testReadNodeWithLongArray(): Unit = {\n    val df: DataFrame = initTest(s\"CREATE (p:Person {ages: [22, 23]})\")\n\n    val res = df.select(\"ages\").collectAsList().get(0).getAs[Seq[Long]](0)\n\n    assertEquals(22, res.head)\n    assertEquals(23, res(1))\n  }\n\n  @Test\n  def testReadNodeWithDoubleArray(): Unit = {\n    val df: DataFrame = initTest(s\"CREATE (p:Person {scores: [22.33, 44.55]})\")\n\n    val res = df.select(\"scores\").collectAsList().get(0).getAs[Seq[Double]](0)\n\n    assertEquals(22.33, res.head, 0)\n    assertEquals(44.55, res(1), 0)\n  }\n\n  @Test\n  def testReadNodeWithTimestampArray(): Unit = {\n    val df: DataFrame =\n      initTest(\n        s\"CREATE (p:Person {someTimes: [datetime('2010-10-10T11:13:37+01:00'), datetime('2011-11-11T10:13:37Z')]})\"\n      )\n\n    val res = df.select(\"someTimes\").collectAsList().get(0).getAs[Seq[Timestamp]](0)\n    assertEquals(\"2010-10-10T10:13:37Z\", res.head.toInstant.atZone(ZoneOffset.UTC).toString)\n    assertEquals(\"2011-11-11T10:13:37Z\", res(1).toInstant.atZone(ZoneOffset.UTC).toString)\n  }\n\n  @Test\n  def testReadNodeWithLocalTimeArray(): Unit = {\n    val df: DataFrame =\n      initTest(s\"CREATE (p:Person {someTimes: [localtime({hour:12}), localtime({hour:1, minute: 3})]})\")\n\n    val res = df.select(\"someTimes\").collectAsList().get(0).getAs[Seq[GenericRowWithSchema]](0)\n    assertEquals(\"local-time\", res.head.get(0))\n    assertEquals(\"12:00:00\", res.head.get(1))\n    assertEquals(\"local-time\", res(1).get(0))\n    assertEquals(\"01:03:00\", res(1).get(1))\n  }\n\n  @Test\n  def testReadNodeWithBooleanArray(): Unit = {\n    val df: DataFrame = initTest(s\"CREATE (p:Person {bools: [true, false]})\")\n\n    val res = df.select(\"bools\").collectAsList().get(0).getAs[Seq[Boolean]](0)\n\n    assertEquals(true, res.head)\n    assertEquals(false, res(1))\n  }\n\n  @Test\n  def testReadNodeWithPointArray(): Unit = {\n    val df: DataFrame =\n      initTest(s\"CREATE (p:Person {locations: [point({x: 11, y: 33.111}), point({x: 22, y: 44.222})]})\")\n\n    val res = df.select(\"locations\").collectAsList().get(0).getAs[Seq[GenericRowWithSchema]](0)\n\n    assertEquals(\"point-2d\", res.head.get(0))\n    assertEquals(7203, res.head.get(1))\n    assertEquals(11.0, res.head.get(2))\n    assertEquals(33.111, res.head.get(3))\n\n    assertEquals(\"point-2d\", res(1).get(0))\n    assertEquals(7203, res(1).get(1))\n    assertEquals(22.0, res(1).get(2))\n    assertEquals(44.222, res(1).get(3))\n  }\n\n  @Test\n  def testReadNodeWithGeoPointArray(): Unit = {\n    val df: DataFrame = initTest(\n      s\"CREATE (p:Person {locations: [point({longitude: 11, latitude: 33.111}), point({longitude: 22, latitude: 44.222})]})\"\n    )\n\n    val res = df.select(\"locations\").collectAsList().get(0).getAs[Seq[GenericRowWithSchema]](0)\n\n    assertEquals(\"point-2d\", res.head.get(0))\n    assertEquals(4326, res.head.get(1))\n    assertEquals(11.0, res.head.get(2))\n    assertEquals(33.111, res.head.get(3))\n\n    assertEquals(\"point-2d\", res(1).get(0))\n    assertEquals(4326, res(1).get(1))\n    assertEquals(22.0, res(1).get(2))\n    assertEquals(44.222, res(1).get(3))\n  }\n\n  @Test\n  def testReadNodeWithPoint3DArray(): Unit = {\n    val df: DataFrame =\n      initTest(s\"CREATE (p:Person {locations: [point({x: 11, y: 33.111, z: 12}), point({x: 22, y: 44.222, z: 99.1})]})\")\n\n    val res = df.select(\"locations\").collectAsList().get(0).getAs[Seq[GenericRowWithSchema]](0)\n\n    assertEquals(\"point-3d\", res.head.get(0))\n    assertEquals(9157, res.head.get(1))\n    assertEquals(11.0, res.head.get(2))\n    assertEquals(33.111, res.head.get(3))\n    assertEquals(12.0, res.head.get(4))\n\n    assertEquals(\"point-3d\", res(1).get(0))\n    assertEquals(9157, res(1).get(1))\n    assertEquals(22.0, res(1).get(2))\n    assertEquals(44.222, res(1).get(3))\n    assertEquals(99.1, res(1).get(4))\n  }\n\n  @Test\n  def testReadNodeWithArrayDate(): Unit = {\n    val df: DataFrame = initTest(s\"CREATE (p:Person {dates: [date('2009-10-10'), date('2009-10-11')]})\")\n\n    val res = df.select(\"dates\").collectAsList().get(0).getAs[Seq[java.sql.Date]](0)\n\n    assertEquals(java.sql.Date.valueOf(\"2009-10-10\"), res.head)\n    assertEquals(java.sql.Date.valueOf(\"2009-10-11\"), res(1))\n  }\n\n  @Test\n  def testReadNodeWithArrayZonedDateTime(): Unit = {\n    val datetime1 = \"2015-06-24T12:50:35.556+01:00\"\n    val datetime2 = \"2015-06-23T12:50:35.556+01:00\"\n    val df: DataFrame = initTest(\n      s\"\"\"\n     CREATE (p:Person {aTime: [\n      datetime('$datetime1'),\n      datetime('$datetime2')\n     ]})\n     \"\"\"\n    )\n\n    val result = df.select(\"aTime\").collectAsList().get(0).getAs[Seq[Timestamp]](0)\n\n    assertEquals(Timestamp.from(OffsetDateTime.parse(datetime1).toInstant), result.head)\n    assertEquals(Timestamp.from(OffsetDateTime.parse(datetime2).toInstant), result(1))\n  }\n\n  @Test\n  def testReadNodeWithArrayDurations(): Unit = {\n    val df: DataFrame = initTest(s\"CREATE (p:Person {durations: [duration({months: 0.75}), duration({weeks: 2.5})]})\")\n\n    val res = df.select(\"durations\").collectAsList().get(0).getAs[Seq[GenericRowWithSchema]](0)\n\n    assertEquals(\"duration\", res.head.get(0))\n    assertEquals(0L, res.head.get(1))\n    assertEquals(22L, res.head.get(2))\n    assertEquals(71509L, res.head.get(3))\n    assertEquals(500000000, res.head.get(4))\n    assertEquals(\"P0M22DT71509.500000000S\", res.head.get(5))\n\n    assertEquals(\"duration\", res(1).get(0))\n    assertEquals(0L, res(1).get(1))\n    assertEquals(17L, res(1).get(2))\n    assertEquals(43200L, res(1).get(3))\n    assertEquals(0, res(1).get(4))\n    assertEquals(\"P0M17DT43200S\", res(1).get(5))\n  }\n\n  @Test\n  def testReadNodeWithBinary(): Unit = {\n    val bytes = \"hello, world!\".map(_.toByte).toArray\n    val parameters = new java.util.HashMap[String, Object]()\n    parameters.put(\"bytes\", bytes)\n\n    SparkConnectorScalaSuiteIT.session()\n      .writeTransaction((tx: Transaction) => tx.run(\"CREATE (h:Hello {b: $bytes})\", parameters).consume())\n\n    val df = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"labels\", \"Hello\")\n      .load()\n\n    val res = df.select(\"b\").collect()\n    assertEquals(1, res.length)\n    val gotBytes = res.head.getAs[Array[Byte]](0)\n\n    for (i <- bytes.indices) {\n      assertEquals(bytes(i), gotBytes(i))\n    }\n  }\n\n  @Test\n  def testReadNodeWithEqualToFilter(): Unit = {\n    val df: DataFrame = initTest(\n      s\"\"\"\n     CREATE (p1:Person {name: 'John Doe'}),\n      (p2:Person {name: 'Jane Doe'})\n     \"\"\"\n    )\n\n    val result = df.select(\"name\").where(\"name = 'John Doe'\").collectAsList()\n\n    assertEquals(1, result.size())\n    assertEquals(\"John Doe\", result.get(0).getString(0))\n  }\n\n  @Test\n  def testReadNodeWithEqualToDateFilter(): Unit = {\n    val df: DataFrame = initTest(\n      s\"\"\"\n     CREATE (p1:Person {birth: date('1998-02-04')}),\n      (p2:Person {birth: date('1988-01-05')})\n     \"\"\"\n    )\n\n    val result = df.select(\"birth\").where(\"birth = '1988-01-05'\").collectAsList()\n\n    assertEquals(1, result.size())\n    assertEquals(java.sql.Date.valueOf(\"1988-01-05\"), result.get(0).getDate(0))\n  }\n\n  @Test\n  def testReadNodeWithTimestampGteFilter(): Unit = {\n    val localDateTime = \"2007-12-03T10:15:30\"\n    val df: DataFrame = initTest(\n      s\"\"\"\n     CREATE (p1:Person {birth: localdatetime('$localDateTime')}),\n      (p2:Person {birth: localdatetime('$localDateTime')})\n     \"\"\"\n    )\n\n    df.printSchema()\n    df.show()\n\n    val result = df.select(\"birth\").where(s\"birth >= '$localDateTime'\").collectAsList()\n    assertEquals(2, result.size())\n  }\n\n  @Test\n  def testReadNodeWithNotEqualToFilter(): Unit = {\n    val df: DataFrame = initTest(\n      s\"\"\"\n     CREATE (p1:Person {name: 'John Doe'}),\n      (p2:Person {name: 'Jane Doe'})\n     \"\"\"\n    )\n\n    val result = df.select(\"name\").where(\"NOT name = 'John Doe'\").collectAsList()\n\n    assertEquals(1, result.size())\n    assertEquals(\"Jane Doe\", result.get(0).getString(0))\n  }\n\n  @Test\n  def testReadNodeWithNotEqualToDateFilter(): Unit = {\n    val df: DataFrame = initTest(\n      s\"\"\"\n     CREATE (p1:Person {birth: date('1998-02-04')}),\n      (p2:Person {birth: date('1988-01-05')})\n     \"\"\"\n    )\n\n    val result = df.select(\"birth\").where(\"NOT birth = '1988-01-05'\").collectAsList()\n\n    assertEquals(1, result.size())\n    assertEquals(java.sql.Date.valueOf(\"1998-02-04\"), result.get(0).getDate(0))\n  }\n\n  @Test\n  def testReadNodeWithDifferentOperatorFilter(): Unit = {\n    val df: DataFrame = initTest(\n      s\"\"\"\n     CREATE (p1:Person {name: 'John Doe'}),\n      (p2:Person {name: 'Jane Doe'})\n     \"\"\"\n    )\n\n    val result = df.select(\"name\").where(\"name != 'John Doe'\").collectAsList()\n\n    assertEquals(1, result.size())\n    assertEquals(\"Jane Doe\", result.get(0).getString(0))\n  }\n\n  @Test\n  def testReadNodeWithGtFilter(): Unit = {\n    val df: DataFrame = initTest(\n      s\"\"\"\n     CREATE (p1:Person {age: 19}),\n      (p2:Person {age: 20}),\n      (p3:Person {age: 21})\n     \"\"\"\n    )\n\n    val result = df.select(\"age\").where(\"age > 20\").collectAsList()\n\n    assertEquals(1, result.size())\n    assertEquals(21, result.get(0).getLong(0))\n  }\n\n  @Test\n  def testReadNodeWithGtDateFilter(): Unit = {\n    val df: DataFrame = initTest(\n      s\"\"\"\n     CREATE (p1:Person {birth: date('1998-02-04')}),\n      (p2:Person {birth: date('1988-01-05')}),\n      (p3:Person {birth: date('1994-10-16')})\n     \"\"\"\n    )\n\n    val result = df.select(\"birth\").orderBy(\"birth\").where(\"birth > '1990-01-01'\").collectAsList()\n\n    assertEquals(2, result.size())\n    assertEquals(java.sql.Date.valueOf(\"1994-10-16\"), result.get(0).getDate(0))\n    assertEquals(java.sql.Date.valueOf(\"1998-02-04\"), result.get(1).getDate(0))\n  }\n\n  @Test\n  def testReadNodeWithGtSpatialFilter(): Unit = {\n    val df: DataFrame = initTest(\n      s\"\"\"\n     CREATE (p:Person {location: point({x: 12, y: 12})}),\n      (p2:Person {location: point({x: -6, y: -6})})\n     \"\"\"\n    )\n\n    val result = df.select(\"location\").where(\"location.x > 0\").collectAsList()\n    val row = result.get(0).getAs[GenericRowWithSchema](0);\n\n    assertEquals(1, result.size())\n\n    assertEquals(\"point-2d\", row.get(0))\n    assertEquals(7203, row.get(1))\n    assertEquals(12.0, row.get(2))\n    assertEquals(12.0, row.get(3))\n  }\n\n  @Test\n  def testReadNodeWithGteFilter(): Unit = {\n    val df: DataFrame = initTest(\n      s\"\"\"\n     CREATE (p1:Person {age: 19}),\n      (p2:Person {age: 20}),\n      (p3:Person {age: 21})\n     \"\"\"\n    )\n\n    val result = df.select(\"age\").orderBy(\"age\").where(\"age >= 20\").collectAsList()\n\n    assertEquals(2, result.size())\n    assertEquals(20, result.get(0).getLong(0))\n    assertEquals(21, result.get(1).getLong(0))\n  }\n\n  @Test\n  def testReadNodeWithGteFilterWithProp(): Unit = {\n    val df: DataFrame = initTest(\n      s\"\"\"\n     CREATE (p1:Person {score: 19, limit: 20}),\n      (p2:Person {score: 20,  limit: 18}),\n      (p3:Person {score: 21,  limit: 12})\n     \"\"\"\n    )\n\n    val result = df.select(\"score\").orderBy(\"score\").where(\"score >= limit\").collectAsList()\n\n    assertEquals(2, result.size())\n    assertEquals(20, result.get(0).getLong(0))\n    assertEquals(21, result.get(1).getLong(0))\n  }\n\n  @Test\n  def testReadNodeWithLtFilter(): Unit = {\n    val df: DataFrame = initTest(\n      s\"\"\"\n     CREATE (p1:Person {age: 39}),\n      (p2:Person {age: 41}),\n      (p3:Person {age: 43})\n     \"\"\"\n    )\n\n    val result = df.select(\"age\").orderBy(\"age\").where(\"age < 40\").collectAsList()\n\n    assertEquals(1, result.size())\n    assertEquals(39, result.get(0).getLong(0))\n  }\n\n  @Test\n  def testReadNodeWithLteFilter(): Unit = {\n    val df: DataFrame = initTest(\n      s\"\"\"\n     CREATE (p1:Person {age: 39}),\n      (p2:Person {age: 41}),\n      (p3:Person {age: 43})\n     \"\"\"\n    )\n\n    val result = df.select(\"age\").orderBy(\"age\").where(\"age <= 41\").collectAsList()\n\n    assertEquals(2, result.size())\n    assertEquals(39, result.get(0).getLong(0))\n    assertEquals(41, result.get(1).getLong(0))\n  }\n\n  @Test\n  def testReadNodeWithInFilter(): Unit = {\n    val df: DataFrame = initTest(\n      s\"\"\"\n     CREATE (p1:Person {age: 39}),\n      (p2:Person {age: 41}),\n      (p3:Person {age: 43})\n     \"\"\"\n    )\n\n    val result = df.select(\"age\").orderBy(\"age\").where(\"age IN(41,43)\").collectAsList()\n\n    assertEquals(2, result.size())\n    assertEquals(41, result.get(0).getLong(0))\n    assertEquals(43, result.get(1).getLong(0))\n  }\n\n  @Test\n  def testReadNodeWithIsNullFilter(): Unit = {\n    val df: DataFrame = initTest(\n      s\"\"\"\n     CREATE (p1:Person {age: 39}),\n      (p2:Person {age: null}),\n      (p3:Person {age: 43})\n     \"\"\"\n    )\n\n    val result = df.select(\"age\").where(\"age IS NULL\").collectAsList()\n\n    assertEquals(1, result.size())\n    assertNull(result.get(0).get(0))\n  }\n\n  @Test\n  def testReadNodeWithIsNotNullFilter(): Unit = {\n    val df: DataFrame = initTest(\n      s\"\"\"\n     CREATE (p1:Person {age: 39}),\n      (p2:Person {age: null}),\n      (p3:Person {age: 43})\n     \"\"\"\n    )\n\n    val result = df.select(\"age\").orderBy(\"age\").where(\"age IS NOT NULL\").collectAsList()\n\n    assertEquals(2, result.size())\n    assertEquals(39, result.get(0).getLong(0))\n    assertEquals(43, result.get(1).getLong(0))\n  }\n\n  @Test\n  def testReadNodeWithOrCondition(): Unit = {\n    val df: DataFrame = initTest(\n      s\"\"\"\n     CREATE (p1:Person {age: 39}),\n      (p2:Person {age: null}),\n      (p3:Person {age: 43})\n     \"\"\"\n    )\n\n    val result = df.select(\"age\").orderBy(\"age\").where(\"age = 43 OR age = 39 OR age = 32\").collectAsList()\n\n    assertEquals(2, result.size())\n    assertEquals(39, result.get(0).getLong(0))\n    assertEquals(43, result.get(1).getLong(0))\n  }\n\n  @Test\n  def testReadNodeWithAndCondition(): Unit = {\n    val df: DataFrame = initTest(\n      s\"\"\"\n     CREATE (p1:Person {age: 39}),\n      (p2:Person {age: null}),\n      (p3:Person {age: 43})\n     \"\"\"\n    )\n\n    val result = df.select(\"age\").orderBy(\"age\").where(\"age >= 39 AND age <= 43\").collectAsList()\n\n    assertEquals(2, result.size())\n    assertEquals(39, result.get(0).getLong(0))\n    assertEquals(43, result.get(1).getLong(0))\n  }\n\n  @Test\n  def testReadNodeWithStartsWith(): Unit = {\n    val df: DataFrame = initTest(\n      s\"\"\"\n     CREATE (p1:Person {name: 'John Mayer'}),\n      (p2:Person {name: 'John Scofield'}),\n      (p3:Person {name: 'John Butler'})\n     \"\"\"\n    )\n\n    val result = df.select(\"name\").orderBy(\"name\").where(\"name LIKE 'John%'\").collectAsList()\n\n    assertEquals(3, result.size())\n    assertEquals(\"John Butler\", result.get(0).getString(0))\n    assertEquals(\"John Mayer\", result.get(1).getString(0))\n    assertEquals(\"John Scofield\", result.get(2).getString(0))\n  }\n\n  @Test\n  def testReadNodeWithEndsWith(): Unit = {\n    val df: DataFrame = initTest(\n      s\"\"\"\n     CREATE (p1:Person {name: 'John Mayer'}),\n      (p2:Person {name: 'John Scofield'}),\n      (p3:Person {name: 'John Butler'})\n     \"\"\"\n    )\n\n    val result = df.select(\"name\").where(\"name LIKE '%Scofield'\").collectAsList()\n\n    assertEquals(1, result.size())\n    assertEquals(\"John Scofield\", result.get(0).getString(0))\n  }\n\n  @Test\n  def testReadNodeWithContains(): Unit = {\n    val df: DataFrame = initTest(\n      s\"\"\"\n     CREATE (p1:Person {name: 'John Mayer'}),\n      (p2:Person {name: 'John Scofield'}),\n      (p3:Person {name: 'John Butler'})\n     \"\"\"\n    )\n\n    val result = df.select(\"name\").where(\"name LIKE '%ay%'\").collectAsList()\n\n    assertEquals(1, result.size())\n    assertEquals(\"John Mayer\", result.get(0).getString(0))\n  }\n\n  @Test\n  def testRelFiltersWithMap(): Unit = {\n    val fixtureQuery: String =\n      \"\"\"UNWIND range(1,100) as id\n        |CREATE (p:Person {id:id,ids:[id,id]}) WITH collect(p) as people\n        |UNWIND people as p1\n        |UNWIND range(1,10) as friend\n        |WITH p1, people[(p1.id + friend) % size(people)] as p2\n        |CREATE (p1)-[:KNOWS]->(p2)\n        |RETURN *\n    \"\"\".stripMargin\n\n    SparkConnectorScalaSuiteIT.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(fixtureQuery).consume()\n        }\n      )\n\n    val df = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"relationship.nodes.map\", \"true\")\n      .option(\"relationship\", \"KNOWS\")\n      .option(\"relationship.source.labels\", \"Person\")\n      .option(\"relationship.target.labels\", \"Person\")\n      .load()\n\n    assertEquals(1, df.filter(\"`<source>`.`id` = '14' AND `<target>`.`id` = '16'\").count)\n  }\n\n  @Test\n  def testRelFiltersWithoutMap(): Unit = {\n    val fixtureQuery: String =\n      \"\"\"UNWIND range(1,100) as id\n        |CREATE (p:Person {id:id,ids:[id,id]}) WITH collect(p) as people\n        |UNWIND people as p1\n        |UNWIND range(1,10) as friend\n        |WITH p1, people[(p1.id + friend) % size(people)] as p2\n        |CREATE (p1)-[:KNOWS]->(p2)\n        |RETURN *\n    \"\"\".stripMargin\n\n    SparkConnectorScalaSuiteIT.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(fixtureQuery).consume()\n        }\n      )\n\n    val df = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"relationship\", \"KNOWS\")\n      .option(\"relationship.nodes.map\", \"false\")\n      .option(\"relationship.source.labels\", \"Person\")\n      .option(\"relationship.target.labels\", \"Person\")\n      .load()\n\n    assertEquals(1, df.filter(\"`source.id` = 14 AND `target.id` = 16\").count)\n  }\n\n  @Test\n  def testReadRelationshipFilters(): Unit = {\n    val fixtureQuery: String =\n      \"\"\"UNWIND range(1,100) as id\n        |CREATE (p:Person {id:id,ids:[id,id]}) WITH collect(p) as people\n        |UNWIND people as p1\n        |UNWIND range(1,10) as friend\n        |WITH p1, people[(p1.id + friend) % size(people)] as p2\n        |CREATE (p1)-[:KNOWS]->(p2)\n        |RETURN *\n    \"\"\".stripMargin\n\n    val df: DataFrame = initTest(fixtureQuery)\n    val repartitionedDf = df.repartition(10)\n\n    assertEquals(10, repartitionedDf.rdd.getNumPartitions)\n    val numNode = repartitionedDf.collect().length\n    assertEquals(100, numNode)\n  }\n\n  @Test\n  def testRelationshipsDifferentFieldValues(): Unit = {\n    val fixtureQuery: String =\n      s\"\"\"CREATE (pr1:Product {id: '1'})\n         |CREATE (pr2:Product {id: 2})\n         |CREATE (pe1:Person {id: '3'})\n         |CREATE (pe2:Person {id: 4})\n         |CREATE (pe1)-[:BOUGHT]->(pr1)\n         |CREATE (pe2)-[:BOUGHT]->(pr2)\n         |RETURN *\n    \"\"\".stripMargin\n\n    SparkConnectorScalaSuiteIT.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(fixtureQuery).consume()\n        }\n      )\n\n    val df: DataFrame = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"relationship.nodes.map\", \"false\")\n      .option(\"relationship\", \"BOUGHT\")\n      .option(\"relationship.source.labels\", \":Person\")\n      .option(\"relationship.target.labels\", \":Product\")\n      .load()\n\n    val res = df.sort(\"`source.id`\").collectAsList()\n\n    assertEquals(\"3\", res.get(0).get(4))\n    assertEquals(\"1\", res.get(0).get(7))\n    assertEquals(\"4\", res.get(1).get(4))\n    assertEquals(\"2\", res.get(1).get(7))\n  }\n\n  @Test\n  def testReadNodesCustomPartitions(): Unit = {\n    val fixtureQuery: String =\n      \"\"\"UNWIND range(1,100) as id\n        |CREATE (p:Person:Customer {id: id, name: 'Person ' + id})\n        |RETURN *\n    \"\"\".stripMargin\n    val fixture2Query: String =\n      \"\"\"UNWIND range(1,100) as id\n        |CREATE (p:Employee:Customer {id: id, name: 'Person ' + id})\n        |RETURN *\n    \"\"\".stripMargin\n    SparkConnectorScalaSuiteIT.driver.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(fixtureQuery).consume()\n        }\n      )\n    SparkConnectorScalaSuiteIT.driver.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(fixture2Query).consume()\n        }\n      )\n\n    val partitionedDf = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"labels\", \":Person:Customer\")\n      .option(\"partitions\", \"5\")\n      .load()\n\n    assertEquals(5, partitionedDf.rdd.getNumPartitions)\n    assertEquals(100, partitionedDf.collect().map(_.getAs[Long](\"id\")).toSet.size)\n    assertEquals(100, partitionedDf.collect().map(_.getAs[Long](\"id\")).size)\n  }\n\n  @Test\n  def testReadRelsCustomPartitions(): Unit = {\n    val fixtureQuery: String =\n      \"\"\"UNWIND range(1,100) as id\n        |CREATE (p:Person {id: id, name: 'Person ' + id})-[:BOUGHT{quantity: ceil(rand() * 100)}]->(:Product{id: id, name: 'Product ' + id})\n        |RETURN *\n    \"\"\".stripMargin\n    SparkConnectorScalaSuiteIT.driver.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(fixtureQuery).consume()\n        }\n      )\n\n    val partitionedDf = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"relationship.nodes.map\", \"true\")\n      .option(\"relationship\", \"BOUGHT\")\n      .option(\"relationship.source.labels\", \":Person\")\n      .option(\"relationship.target.labels\", \":Product\")\n      .option(\"partitions\", \"5\")\n      .load()\n\n    assertEquals(5, partitionedDf.rdd.getNumPartitions)\n    assertEquals(100, partitionedDf.collect().map(_.getAs[Long](\"<rel.id>\")).toSet.size)\n    assertEquals(100, partitionedDf.collect().map(_.getAs[Long](\"<rel.id>\")).size)\n  }\n\n  @Test\n  def testReadQueryCustomPartitions(): Unit = {\n    val fixtureProduct1Query: String =\n      \"\"\"CREATE (pr:Product{id: 1, name: 'Product 1'})\n        |WITH pr\n        |UNWIND range(1,100) as id\n        |CREATE (p:Person {id: id, name: 'Person ' + id})-[:BOUGHT{quantity: ceil(rand() * 100)}]->(pr)\n        |RETURN *\n    \"\"\".stripMargin\n    SparkConnectorScalaSuiteIT.driver.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(fixtureProduct1Query).consume()\n        }\n      )\n    val fixtureProduct2Query: String =\n      \"\"\"CREATE (pr:Product{id: 2, name: 'Product 2'})\n        |WITH pr\n        |UNWIND range(1,50) as id\n        |MATCH (p:Person {id: id})\n        |CREATE (p)-[:BOUGHT{quantity: ceil(rand() * 100)}]->(pr)\n        |RETURN *\n    \"\"\".stripMargin\n    SparkConnectorScalaSuiteIT.driver.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(fixtureProduct2Query).consume()\n        }\n      )\n\n    val partitionedQueryCountDf = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\n        \"query\",\n        \"\"\"\n          |MATCH (p:Person)-[r:BOUGHT]->(pr:Product{name: 'Product 2'})\n          |RETURN p.name AS person, pr.name AS product, r.quantity AS quantity\"\"\".stripMargin\n      )\n      .option(\"partitions\", \"5\")\n      .option(\n        \"query.count\",\n        \"\"\"\n          |MATCH (p:Person)-[r:BOUGHT]->(pr:Product{name: 'Product 2'})\n          |RETURN count(p) AS count\"\"\".stripMargin\n      )\n      .load()\n\n    assertEquals(5, partitionedQueryCountDf.rdd.getNumPartitions)\n    assertEquals(50, partitionedQueryCountDf.collect().map(_.getAs[String](\"person\")).toSet.size)\n    assertEquals(50, partitionedQueryCountDf.collect().map(_.getAs[String](\"person\")).length)\n\n    val partitionedQueryCountLiteralDf = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\n        \"query\",\n        \"\"\"\n          |MATCH (p:Person)-[r:BOUGHT]->(pr:Product{name: 'Product 2'})\n          |RETURN p.name AS person, pr.name AS product, r.quantity AS quantity\"\"\".stripMargin\n      )\n      .option(\"partitions\", \"5\")\n      .option(\"query.count\", \"50\")\n      .load()\n\n    assertEquals(5, partitionedQueryCountLiteralDf.rdd.getNumPartitions)\n    assertEquals(50, partitionedQueryCountLiteralDf.collect().map(_.getAs[String](\"person\")).toSet.size)\n    assertEquals(50, partitionedQueryCountLiteralDf.collect().map(_.getAs[String](\"person\")).length)\n  }\n\n  @Test\n  def testRelationshipsFlatten(): Unit = {\n    val total = 100\n    val fixtureQuery: String =\n      s\"\"\"UNWIND range(1, $total) as id\n         |CREATE (pr:Product {id: id * rand(), name: 'Product ' + id})\n         |CREATE (pe:Person {id: id, fullName: 'Person ' + id})\n         |CREATE (pe)-[:BOUGHT{when: rand(), quantity: rand() * 1000}]->(pr)\n         |RETURN *\n    \"\"\".stripMargin\n\n    SparkConnectorScalaSuiteIT.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(fixtureQuery).consume()\n        }\n      )\n\n    val df: DataFrame = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"relationship\", \"BOUGHT\")\n      .option(\"relationship.nodes.map\", \"false\")\n      .option(\"relationship.source.labels\", \":Person\")\n      .option(\"relationship.target.labels\", \":Product\")\n      .load()\n\n    val count = df.collectAsList()\n      .asScala\n      .filter(row =>\n        row.getAs[Long](\"<rel.id>\") >= 0\n          && row.getAs[String](\"<rel.type>\") != null\n          && row.getAs[Double](\"rel.when\") >= 0\n          && row.getAs[Double](\"rel.quantity\") >= 0\n          && row.getAs[Long](\"<source.id>\") >= 0\n          && row.getAs[Long](\"source.id\") >= 0\n          && !row.getAs[Seq[String]](\"<source.labels>\").isEmpty\n          && row.getAs[String](\"source.fullName\") != null\n          && row.getAs[Long](\"<target.id>\") >= 0\n          && row.getAs[Double](\"target.id\") >= 0\n          && !row.getAs[Seq[String]](\"<target.labels>\").isEmpty\n          && row.getAs[String](\"target.name\") != null\n      )\n      .size\n    assertEquals(total, count)\n  }\n\n  @Test\n  def testRelationshipsMap(): Unit = {\n    val total = 100\n    val fixtureQuery: String =\n      s\"\"\"UNWIND range(1, $total) as id\n         |CREATE (pr:Product {id: id * rand(), name: 'Product ' + id})\n         |CREATE (pe:Person {id: id, fullName: 'Person ' + id})\n         |CREATE (pe)-[:BOUGHT{when: rand(), quantity: rand() * 1000}]->(pr)\n         |RETURN *\n    \"\"\".stripMargin\n\n    SparkConnectorScalaSuiteIT.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(fixtureQuery).consume()\n        }\n      )\n\n    val df: DataFrame = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"relationship.nodes.map\", \"true\")\n      .option(\"relationship\", \"BOUGHT\")\n      .option(\"relationship.source.labels\", \":Person\")\n      .option(\"relationship.target.labels\", \":Product\")\n      .load()\n\n    val rows = df.collectAsList().asScala\n    val count = rows\n      .filter(row =>\n        row.getAs[Long](\"<rel.id>\") >= 0\n          && row.getAs[String](\"<rel.type>\") != null\n          && row.getAs[Double](\"rel.when\") >= 0\n          && row.getAs[Double](\"rel.quantity\") >= 0\n          && row.getAs[Map[String, String]](\"<source>\") != null\n          && row.getAs[Map[String, String]](\"<target>\") != null\n      )\n      .size\n    assertEquals(total, count)\n\n    val countSourceMap = rows.map(row => row.getAs[Map[String, String]](\"<source>\"))\n      .filter(row => row.keys == Set(\"id\", \"fullName\", \"<id>\", \"<labels>\"))\n      .size\n    assertEquals(total, countSourceMap)\n    val countTargetMap = rows.map(row => row.getAs[Map[String, String]](\"<target>\"))\n      .filter(row => row.keys == Set(\"id\", \"name\", \"<id>\", \"<labels>\"))\n      .size\n    assertEquals(total, countTargetMap)\n  }\n\n  @Test\n  def testQueries(): Unit = {\n    val dfMap = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"query\", \"RETURN {a: 1, b: '3'} AS map\")\n      .load()\n    val map = dfMap.collect()(0).getAs[Map[String, String]](\"map\")\n    val expectedMap = Map(\"a\" -> \"1\", \"b\" -> \"3\")\n    assertEquals(expectedMap, map)\n\n    val dfArrayMap = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"query\", \"RETURN [{a: 1, b: '3'}, {a: 'foo'}] AS listMap\")\n      .load()\n    val listMap = dfArrayMap.collect()(0).getAs[Seq[_]](\"listMap\").toList\n    val expectedListMap = Seq(Map(\"a\" -> \"1\", \"b\" -> \"3\"), Map(\"a\" -> \"foo\"))\n    assertEquals(expectedListMap, listMap)\n\n    val dfArray = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"query\", \"RETURN [1, 'foo'] AS list\")\n      .load()\n    val list = dfArray.collect()(0).getAs[Seq[_]](\"list\")\n    val expectedList = Seq(\"1\", \"foo\")\n    assertEquals(expectedList, list)\n  }\n\n  @Test\n  def testComplexQuery(): Unit = {\n    val total = 100\n    val fixtureQuery: String =\n      s\"\"\"UNWIND range(1, $total) as id\n         |CREATE (pr:Product {id: id * rand(), name: 'Product ' + id})\n         |CREATE (pe:Person {id: id, fullName: 'Person ' + id})\n         |CREATE (pe)-[:BOUGHT{when: rand(), quantity: rand() * 1000}]->(pr)\n         |RETURN *\n    \"\"\".stripMargin\n\n    SparkConnectorScalaSuiteIT.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(fixtureQuery).consume()\n        }\n      )\n\n    val df: DataFrame = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"query\", \"MATCH (n:Person) WITH n LIMIT 2 RETURN collect(n) AS nodes\")\n      .load()\n\n    val data = df.collect()\n    val count = data.flatMap(row => row.getAs[Seq[Row]](\"nodes\"))\n      .filter(row =>\n        row.getAs[Long](\"<id>\") >= 0\n          && !row.getAs[Seq[String]](\"<labels>\").isEmpty\n          && !row.getAs[String](\"fullName\").isEmpty\n          && row.getAs[Long](\"id\") >= 0\n      )\n      .size\n    assertEquals(2, count)\n\n    val dfString: DataFrame = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\n        \"query\",\n        \"\"\"MATCH (p:Person)-[b:BOUGHT]->(pr:Product)\n          |RETURN id(p) AS personId, id(pr) AS productId, {quantity: b.quantity, when: b.when} AS map\"\"\".stripMargin\n      )\n      .option(\"schema.strategy\", \"string\")\n      .load()\n\n    val dataString = dfString.collect()\n    val countString = dataString\n      .filter(row =>\n        !row.getAs[String](\"personId\").isEmpty\n          && !row.getAs[String](\"productId\").isEmpty\n          && !row.getAs[String](\"map\").isEmpty\n      )\n      .size\n    assertEquals(100, countString)\n\n    val dfRel: DataFrame = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\n        \"query\",\n        \"\"\"MATCH (p:Person)-[b:BOUGHT]->(pr:Product)\n          |RETURN b AS rel\"\"\".stripMargin\n      )\n      .load()\n    val dataRel = dfRel.collect()\n    val countRel = dataRel\n      .map(_.getAs[Row](\"rel\"))\n      .filter(row =>\n        row.getAs[Long](\"<rel.id>\") >= 0\n          && !row.getAs[String](\"<rel.type>\").isEmpty\n          && row.getAs[Long](\"<source.id>\") >= 0\n          && row.getAs[Long](\"<target.id>\") >= 0\n          && row.getAs[Double](\"when\") != null\n          && row.getAs[Double](\"quantity\") != null\n      )\n      .size\n    assertEquals(100, countRel)\n  }\n\n  @Test\n  def testShouldCreateTheCorrectDataframeWithTwoPartitions(): Unit = {\n    SparkConnectorScalaSuiteIT.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary =\n            tx.run(\"CREATE (i1:Instrument{name: 'Drums'}), (i2:Instrument{name: 'Guitar'})\").consume()\n        }\n      )\n    val df = ss.read\n      .format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"labels\", \"Instrument\")\n      .option(\"partitions\", \"2\")\n      .load\n\n    assertEquals(2, df.count())\n  }\n\n  @Test\n  def testEmptyDataset(): Unit = {\n    val df = ss.read\n      .format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"query\", \"MATCH (e:ID_DO_NOT_EXIST) RETURN id(e) as f, 1 as g\")\n      .load\n\n    assertEquals(0, df.count())\n    assertEquals(Set(\"f\", \"g\"), df.columns.toSet)\n  }\n\n  @Test\n  def testColumnSorted(): Unit = {\n    SparkConnectorScalaSuiteIT.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary =\n            tx.run(\"CREATE (i1:Instrument{name: 'Drums', id: 1}), (i2:Instrument{name: 'Guitar', id: 2})\").consume()\n        }\n      )\n\n    val df = ss.read\n      .format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"query\", \"MATCH (i:Instrument) RETURN id(i) as internal_id, i.id as id, i.name as name, i.name\")\n      .load()\n      .orderBy(\"id\")\n\n    val row = df.collectAsList().get(0)\n    assertEquals(1L, row.get(1))\n    assertEquals(\"Drums\", row.get(2))\n    assertEquals(Set(\"internal_id\", \"id\", \"name\", \"i.name\"), df.columns.toSet)\n  }\n\n  @Test\n  def testComplexReturnStatement(): Unit = {\n    val total = 100\n    val fixtureQuery: String =\n      s\"\"\"UNWIND range(1, $total) as id\n         |CREATE (pr:Product {id: id * rand(), name: 'Product ' + id})\n         |CREATE (pe:Person {id: id, fullName: 'Person ' + id})\n         |CREATE (pe)-[:BOUGHT{when: rand(), quantity: rand() * 1000}]->(pr)\n         |RETURN *\n    \"\"\".stripMargin\n\n    SparkConnectorScalaSuiteIT.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(fixtureQuery).consume()\n        }\n      )\n\n    val df = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\n        \"query\",\n        \"\"\"MATCH (p:Person)-[b:BOUGHT]->(pr:Product)\n          |RETURN id(p) AS personId, id(pr) AS productId, {quantity: b.quantity, when: b.when} AS map, \"some string\" as someString, {anotherField: \"201\"} as map2\"\"\".stripMargin\n      )\n      .option(\"schema.strategy\", \"string\")\n      .load()\n\n    assertEquals(Set(\"personId\", \"productId\", \"map\", \"someString\", \"map2\"), df.columns.toSet)\n    assertEquals(100, df.count())\n  }\n\n  @Test\n  def testComplexReturnStatementNoValues(): Unit = {\n    val df = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\n        \"query\",\n        \"\"\"MATCH (p:Person)-[b:BOUGHT]->(pr:Product)\n          |RETURN id(p) AS personId, id(pr) AS productId, {quantity: b.quantity, when: b.when} AS map, \"some string\" as someString, {anotherField: \"201\", and: 1} as map2\"\"\".stripMargin\n      )\n      .option(\"schema.strategy\", \"string\")\n      .load()\n\n    assertEquals(Set(\"personId\", \"productId\", \"map\", \"someString\", \"map2\"), df.columns.toSet)\n    assertEquals(0, df.count())\n  }\n\n  @Test\n  def testShouldPassTheScriptResult(): Unit = {\n    val df = ss.read\n      .format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"script\", \"RETURN 'foo' AS val\")\n      .option(\"query\", \"UNWIND range(1,2) as id RETURN id AS val, scriptResult[0].val AS script\")\n      .option(\"partitions\", 2)\n      .option(\"query.count\", 2)\n      .load\n      .orderBy(\"val\")\n    val data = df.collect()\n      .map(row => (row.getAs[String](\"script\"), row.getAs[Long](\"val\")))\n      .toSeq\n    val expected = Seq((\"foo\", 1), (\"foo\", 2))\n    assertEquals(expected, data)\n  }\n\n  @Test\n  def testShouldFailWithExplicitErrorIfSkipLimitIsUsedAtTheEndOfTheQuery(): Unit = {\n    try {\n      ss.read\n        .format(classOf[DataSource].getName)\n        .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n        .option(\"query\", \"MATCH (n:Label) RETURN id(n) as id LIMIT 100\")\n        .option(\"partitions\", 2)\n        .option(\"query.count\", 2)\n        .load()\n        .show() // we need the action to be able to trigger the exception because of the changes in Spark 3\n      org.junit.Assert.fail(\"Expected to throw an exception\")\n    } catch {\n      case iae: IllegalArgumentException => {\n        assertTrue(iae.getMessage.equals(\"SKIP/LIMIT are not allowed at the end of the query\"))\n      }\n      case _: Throwable => fail(s\"should be thrown a ${classOf[IllegalArgumentException].getName}\")\n    }\n  }\n\n  @Test\n  def testShouldFailWithExplicitErrorIfLowercaseSkipLimitIsUsedAtTheEndOfTheQuery(): Unit = {\n    try {\n      ss.read\n        .format(classOf[DataSource].getName)\n        .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n        .option(\"query\", \"MATCH (n:Label) RETURN id(n) as id limit 100 skip 2\")\n        .option(\"partitions\", 2)\n        .option(\"query.count\", 2)\n        .load()\n        .show() // we need the action to be able to trigger the exception because of the changes in Spark 3\n      org.junit.Assert.fail(\"Expected to throw an exception\")\n    } catch {\n      case iae: IllegalArgumentException => {\n        assertTrue(iae.getMessage.equals(\"SKIP/LIMIT are not allowed at the end of the query\"))\n      }\n      case _: Throwable => fail(s\"should be thrown a ${classOf[IllegalArgumentException].getName}\")\n    }\n  }\n\n  @Test\n  def testShouldFailWithExplicitErrorIfRandomcaseSkipLimitIsUsedAtTheEndOfTheQuery(): Unit = {\n    try {\n      ss.read\n        .format(classOf[DataSource].getName)\n        .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n        .option(\"query\", \"MATCH (n:Label) RETURN id(n) as id LiMIt 100 skIp 2\")\n        .option(\"partitions\", 2)\n        .option(\"query.count\", 2)\n        .load()\n        .show() // we need the action to be able to trigger the exception because of the changes in Spark 3\n      org.junit.Assert.fail(\"Expected to throw an exception\")\n    } catch {\n      case iae: IllegalArgumentException => {\n        assertTrue(iae.getMessage.equals(\"SKIP/LIMIT are not allowed at the end of the query\"))\n      }\n      case _: Throwable => fail(s\"should be thrown a ${classOf[IllegalArgumentException].getName}\")\n    }\n  }\n\n  @Test\n  def testShouldFailWithExplicitErrorIfSkipLimitIsUsedAtTheEndOfTheQueryWithMultilineQuery(): Unit = {\n    try {\n      ss.read\n        .format(classOf[DataSource].getName)\n        .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n        .option(\n          \"query\",\n          \"MATCH (n:Label)\\n\" +\n            \"RETURN id(n) as id\\n\" +\n            \"LIMIT 100\"\n        )\n        .option(\"partitions\", 2)\n        .option(\"query.count\", 2)\n        .load()\n        .show() // we need the action to be able to trigger the exception because of the changes in Spark 3\n      org.junit.Assert.fail(\"Expected to throw an exception\")\n    } catch {\n      case iae: IllegalArgumentException => {\n        assertTrue(iae.getMessage.equals(\"SKIP/LIMIT are not allowed at the end of the query\"))\n      }\n      case t: Throwable => {\n        t.printStackTrace()\n        fail(s\"should be thrown a ${classOf[IllegalArgumentException].getName}\")\n      }\n    }\n  }\n\n  @Test\n  def testShouldAllowSkipLimitInsideTheQuery(): Unit = {\n    val total = 100\n    val fixtureQuery: String =\n      s\"\"\"UNWIND range(1, $total) as id\n         |CREATE (pr:Product {id: id, name: 'Product ' + id})\n         |RETURN *\n    \"\"\".stripMargin\n\n    SparkConnectorScalaSuiteIT.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(fixtureQuery).consume()\n        }\n      )\n\n    val df = ss.read\n      .format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"query\", \"MATCH (p:Product) WITH p\\nLIMIT 10\\nRETURN p\")\n      .option(\"partitions\", 2)\n      .option(\"query.count\", 20)\n      .load\n\n    assertEquals(10, df.count())\n  }\n\n  @Test\n  def testShouldReturnJustTheSelectedFieldWithNode(): Unit = {\n    val total = 100\n    val fixtureQuery: String =\n      s\"\"\"UNWIND range(1, $total) as id\n         |CREATE (pr:Product {id: id, name: 'Product ' + id})\n         |RETURN *\n    \"\"\".stripMargin\n\n    SparkConnectorScalaSuiteIT.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(fixtureQuery).consume()\n        }\n      )\n\n    val df = ss.read\n      .format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"labels\", \"Product\")\n      .load\n      .select(\"name\")\n\n    df.count()\n\n    assertEquals(Set(\"name\"), df.columns.toSet)\n  }\n\n  @Test\n  def testShouldReturnJustTheSelectedFieldWithNodeAndWeirdColumnName(): Unit = {\n    val total = 100\n    val fixtureQuery: String =\n      s\"\"\"UNWIND range(1, $total) as id\n         |CREATE (pr:Product {id: id, `(╯°□°)╯︵ ┻━┻`: 'Product ' + id})\n         |RETURN *\n    \"\"\".stripMargin\n\n    SparkConnectorScalaSuiteIT.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(fixtureQuery).consume()\n        }\n      )\n\n    val df = ss.read\n      .format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"labels\", \"Product\")\n      .load\n      .select(\"`(╯°□°)╯︵ ┻━┻`\")\n\n    df.count()\n\n    assertEquals(Set(\"(╯°□°)╯︵ ┻━┻\"), df.columns.toSet)\n  }\n\n  @Test\n  def testShouldSelectTheSystemColumnsInRelationship(): Unit = {\n    val total = 100\n    val fixtureQuery: String =\n      s\"\"\"UNWIND range(1, $total) as id\n         |CREATE (pr:Product {id: id * rand(), name: 'Product ' + id})\n         |CREATE (pe:Person {id: id, fullName: 'Person ' + id})\n         |CREATE (pe)-[:BOUGHT{when: rand(), quantity: rand() * 1000}]->(pr)\n         |RETURN *\n    \"\"\".stripMargin\n\n    SparkConnectorScalaSuiteIT.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(fixtureQuery).consume()\n        }\n      )\n\n    val df = ss.read\n      .format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"relationship\", \"BOUGHT\")\n      .option(\"relationship.source.labels\", \"Person\")\n      .option(\"relationship.target.labels\", \"Product\")\n      .load\n      .select(\"`<rel.type>`\")\n\n    df.collect()\n\n    assertEquals(Set(\"<rel.type>\"), df.columns.toSet)\n  }\n\n  @Test\n  def testShouldReturnJustTheSelectedFieldWithRelationship(): Unit = {\n    val total = 100\n    val fixtureQuery: String =\n      s\"\"\"UNWIND range(1, $total) as id\n         |CREATE (pr:Product {id: id * rand(), name: 'Product ' + id})\n         |CREATE (pe:Person {id: id, fullName: 'Person ' + id})\n         |CREATE (pe)-[:BOUGHT{when: rand(), quantity: rand() * 1000}]->(pr)\n         |RETURN *\n    \"\"\".stripMargin\n\n    SparkConnectorScalaSuiteIT.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(fixtureQuery).consume()\n        }\n      )\n\n    val df = ss.read\n      .format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"relationship\", \"BOUGHT\")\n      .option(\"relationship.source.labels\", \"Product\")\n      .option(\"relationship.target.labels\", \"Person\")\n      .load\n      .select(\"`source.name`\", \"`<source.id>`\")\n\n    df.count()\n\n    assertEquals(Set(\"source.name\", \"<source.id>\"), df.columns.toSet)\n  }\n\n  @Test\n  def testShouldReturnJustTheSelectedFieldWithRelationshipAndWeirdColumn(): Unit = {\n    val total = 100\n    val fixtureQuery: String =\n      s\"\"\"UNWIND range(1, $total) as id\n         |CREATE (pr:Product {id: id * rand(), `(╯°□°)╯︵ ┻━┻`: 'Product ' + id})\n         |CREATE (pe:Person {id: id, fullName: 'Person ' + id})\n         |CREATE (pe)-[:BOUGHT{when: rand(), quantity: rand() * 1000}]->(pr)\n         |RETURN *\n    \"\"\".stripMargin\n\n    SparkConnectorScalaSuiteIT.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(fixtureQuery).consume()\n        }\n      )\n\n    val df = ss.read\n      .format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"relationship\", \"BOUGHT\")\n      .option(\"relationship.source.labels\", \"Person\")\n      .option(\"relationship.target.labels\", \"Product\")\n      .load\n      .select(\"`target.(╯°□°)╯︵ ┻━┻`\", \"`<source.id>`\")\n\n    df.count()\n\n    assertEquals(Set(\"target.(╯°□°)╯︵ ┻━┻\", \"<source.id>\"), df.columns.toSet)\n  }\n\n  @Test\n  def testShouldReturnJustTheSelectedFieldWithQuery(): Unit = {\n    val total = 100\n    val fixtureQuery: String =\n      s\"\"\"UNWIND range(1, $total) as id\n         |CREATE (pr:Product {id: id * rand(), name: 'Product ' + id})\n         |CREATE (pe:Person {id: id, fullName: 'Person ' + id})\n         |CREATE (pe)-[:BOUGHT{when: rand(), quantity: rand() * 1000}]->(pr)\n         |RETURN *\n    \"\"\".stripMargin\n\n    SparkConnectorScalaSuiteIT.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(fixtureQuery).consume()\n        }\n      )\n\n    val df = ss.read\n      .format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"query\", \"MATCH (p:Product) RETURN p.name as name\")\n      .option(\"partitions\", 2)\n      .option(\"query.count\", 20)\n      .load\n      .select(\"name\")\n\n    df.count()\n\n    assertEquals(Set(\"name\"), df.columns.toSet)\n  }\n\n  @Test\n  def testShouldReturnJustTheSelectedFieldWithFilter(): Unit = {\n    val total = 100\n    val fixtureQuery: String =\n      s\"\"\"UNWIND range(1, $total) as id\n         |CREATE (pr:Product {id: id, name: 'Product ' + id})\n         |RETURN *\n    \"\"\".stripMargin\n\n    SparkConnectorScalaSuiteIT.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(fixtureQuery).consume()\n        }\n      )\n\n    val df = ss.read\n      .format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"labels\", \"Product\")\n      .load\n      .filter(\"name = 'Product 1'\")\n\n    df.count()\n\n    assertEquals(Set(\"<id>\", \"<labels>\", \"name\", \"id\"), df.columns.toSet)\n  }\n\n  @Test\n  def testShouldReturnJustTheSelectedFieldWithRelationshipWithFilter(): Unit = {\n    val total = 100\n    val fixtureQuery: String =\n      s\"\"\"UNWIND range(1, $total) as id\n         |CREATE (pr:Product {id: id * rand(), name: 'Product ' + id})\n         |CREATE (pe:Person {id: id, fullName: 'Person ' + id})\n         |CREATE (pe)-[:BOUGHT{when: rand(), quantity: rand() * 1000}]->(pr)\n         |RETURN *\n    \"\"\".stripMargin\n\n    SparkConnectorScalaSuiteIT.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(fixtureQuery).consume()\n        }\n      )\n\n    val df = ss.read\n      .format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"relationship\", \"BOUGHT\")\n      .option(\"relationship.source.labels\", \"Person\")\n      .option(\"relationship.target.labels\", \"Product\")\n      .load\n      .filter(\"`target.name` = 'Product 1' AND `target.id` = '16'\")\n      .select(\"`target.name`\", \"`target.id`\")\n\n    df.count()\n\n    assertEquals(Set(\"target.name\", \"target.id\"), df.columns.toSet)\n  }\n\n  @Test\n  def testShouldUseTheUserSpecifiedSchema(): Unit = {\n    SparkConnectorScalaSuiteIT.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary =\n            tx.run(\"CREATE (p:Person {name: 'Foo Bar', age: 8})\").consume()\n        }\n      )\n\n    val df = ss.read.format(classOf[DataSource].getName)\n      .schema(StructType(Seq(StructField(\"age\", DataTypes.StringType)).toSeq))\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"query\", \"MATCH (n:Person) RETURN n.age AS age\")\n      .load()\n\n    assertEquals(\"8\", df.collect().head.get(0))\n  }\n\n  @Test\n  def testQueryWithOrderByShouldBeAllowed(): Unit = {\n    SparkConnectorScalaSuiteIT.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary =\n            tx.run(\"CREATE (p:Person {name: 'Foo Bar', age: 8})\").consume()\n        }\n      )\n\n    val df = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"query\", \"MATCH (n:Person) RETURN n.age AS age ORDER by age\")\n      .load()\n\n    assertEquals(8L, df.collect().head.get(0))\n  }\n\n  @Test\n  def testShouldLimitTheNodeResults(): Unit = {\n    val total = 100\n    val fixtureQuery: String =\n      s\"\"\"UNWIND range(1, $total) as id\n         |CREATE (pr:Product {id: id, name: 'Product ' + id})\n         |RETURN *\n    \"\"\".stripMargin\n\n    SparkConnectorScalaSuiteIT.session()\n      .writeTransaction((tx: Transaction) => tx.run(fixtureQuery).consume())\n\n    val df = ss.read\n      .format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"labels\", \"Product\")\n      .load\n      .limit(10)\n\n    assertEquals(10, df.count())\n    assertEquals(Set(\"<id>\", \"<labels>\", \"name\", \"id\"), df.columns.toSet)\n  }\n\n  @Test\n  def testShouldLimitTheRelationshipResults(): Unit = {\n    val total = 100\n    val fixtureQuery: String =\n      s\"\"\"UNWIND range(1, $total) as id\n         |CREATE (pr:Product {id: id * rand(), name: 'Product ' + id})\n         |CREATE (pe:Person {id: id, fullName: 'Person ' + id})\n         |CREATE (pe)-[:BOUGHT{when: rand(), quantity: rand() * 1000}]->(pr)\n         |RETURN *\n    \"\"\".stripMargin\n\n    SparkConnectorScalaSuiteIT.session()\n      .writeTransaction((tx: Transaction) => tx.run(fixtureQuery).consume())\n\n    val df = ss.read\n      .format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"relationship\", \"BOUGHT\")\n      .option(\"relationship.source.labels\", \"Person\")\n      .option(\"relationship.target.labels\", \"Product\")\n      .load\n      .select(\"`target.name`\", \"`target.id`\")\n      .limit(10)\n\n    assertEquals(10, df.count())\n    assertEquals(Set(\"target.name\", \"target.id\"), df.columns.toSet)\n  }\n\n  @Test\n  def test531(): Unit = {\n    val dataFrame = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\n        \"query\",\n        \"\"\"\n          |UNWIND [\n          |  {first: '2022-06-14T10:02:28.192Z', second: null},\n          |  {first: '2022-06-15T10:02:28.192Z', second: '2022-06-16T10:02:28.192Z'}\n          |]AS event\n          |RETURN datetime(event.first) AS first, datetime(event.second) AS second\n          |\"\"\".stripMargin\n      )\n      .load()\n\n    assertEquals(\n      StructType(Array(\n        StructField(\"first\", DataTypes.TimestampType),\n        StructField(\"second\", DataTypes.StringType)\n      )),\n      dataFrame.schema\n    )\n\n    assertEquals(\n      List(\n        (Timestamp.from(OffsetDateTime.parse(\"2022-06-14T10:02:28.192Z\").toInstant), null),\n        (Timestamp.from(OffsetDateTime.parse(\"2022-06-15T10:02:28.192Z\").toInstant), \"2022-06-16T10:02:28.192Z\")\n      ),\n      dataFrame.collect()\n        .map(r => (r.getTimestamp(0), r.getString(1)))\n        .toList\n    )\n  }\n\n  @Test\n  def test531WithSchema(): Unit = {\n    val schema = StructType(Array(\n      StructField(\"first\", DataTypes.TimestampType),\n      StructField(\"second\", DataTypes.TimestampType)\n    ))\n    // dataFrameWithSchema must with the proper data type\n    val dataFrameWithSchema = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\n        \"query\",\n        \"\"\"\n          |UNWIND [\n          |  {first: '2022-06-14T10:02:28.192Z', second: null},\n          |  {first: '2022-06-15T10:02:28.192Z', second: '2022-06-16T10:02:28.192Z'}\n          |] AS event\n          |RETURN datetime(event.first) AS first, datetime(event.second) AS second\n          |\"\"\".stripMargin\n      )\n      .schema(schema)\n      .load()\n    assertEquals(\n      schema,\n      dataFrameWithSchema.schema\n    )\n    assertEquals(\n      List(\n        (Timestamp.from(OffsetDateTime.parse(\"2022-06-14T10:02:28.192Z\").toInstant), null),\n        (\n          Timestamp.from(OffsetDateTime.parse(\"2022-06-15T10:02:28.192Z\").toInstant),\n          Timestamp.from(OffsetDateTime.parse(\"2022-06-16T10:02:28.192Z\").toInstant)\n        )\n      ),\n      dataFrameWithSchema.collect()\n        .map(r => (r.getTimestamp(0), r.getTimestamp(1)))\n        .toList\n    )\n  }\n\n  @Test\n  def testShouldAggregateAndLimitTheRelationshipResults(): Unit = {\n    val total = 100\n    val fixtureQuery: String =\n      s\"\"\"UNWIND range(1, $total) as id\n         |CREATE (pr:Product {id: id * rand(), name: 'Product ' + id})\n         |CREATE (pe:Person {id: id, fullName: 'Person ' + id})\n         |CREATE (pe)-[:BOUGHT{when: rand(), quantity: rand() * 1000}]->(pr)\n         |RETURN *\n    \"\"\".stripMargin\n\n    SparkConnectorScalaSuiteIT.session()\n      .writeTransaction((tx: Transaction) => tx.run(fixtureQuery).consume())\n\n    val df = ss.read\n      .format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"relationship\", \"BOUGHT\")\n      .option(\"relationship.source.labels\", \"Person\")\n      .option(\"relationship.target.labels\", \"Product\")\n      .load\n      .select(\"`target.name`\", \"`target.id`\")\n      .orderBy(col(\"`target.name`\").desc)\n      .limit(10)\n\n    df.show()\n    assertEquals(10, df.count())\n    assertEquals(Set(\"target.name\", \"target.id\"), df.columns.toSet)\n  }\n\n  private def initTest(query: String): DataFrame = {\n    SparkConnectorScalaSuiteIT.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(query).consume()\n        }\n      )\n\n    ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"labels\", \"Person\")\n      .load()\n  }\n}\n"
  },
  {
    "path": "spark-3/src/test/scala/org/neo4j/spark/DataSourceReaderWithApocTSE.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark\n\nimport org.apache.spark.sql.DataFrame\nimport org.apache.spark.sql.catalyst.expressions.GenericRowWithSchema\nimport org.junit.Assert._\nimport org.junit.Test\nimport org.neo4j.driver.Transaction\nimport org.neo4j.driver.TransactionWork\nimport org.neo4j.driver.summary.ResultSummary\n\nimport java.sql.Timestamp\nimport java.time.Instant\nimport java.time.LocalDateTime\nimport java.time.LocalTime\nimport java.time.OffsetDateTime\nimport java.time.OffsetTime\nimport java.time.ZoneOffset\nimport java.util.TimeZone\n\nimport scala.collection.JavaConverters._\nimport scala.collection.mutable.ArraySeq\nimport scala.collection.mutable.Seq\n\nclass DataSourceReaderWithApocTSE extends SparkConnectorScalaBaseWithApocTSE {\n\n  @Test\n  def testReadNodeHasIdField(): Unit = {\n    val df: DataFrame = initTest(s\"CREATE (p:Person {name: 'John'})\")\n\n    /**\n     * utnaf: Since we can't be sure we are in total isolation, and the id is generated\n     * internally by org.neo4j.neo4j, we just check that the <id> field is an integer and is greater\n     * than -1\n     */\n    assertTrue(df.select(\"<id>\").collectAsList().get(0).getLong(0) > -1)\n  }\n\n  @Test\n  def testReadNodeHasLabelsField(): Unit = {\n    val df: DataFrame = initTest(s\"CREATE (p:Person:Customer {name: 'John'})\")\n\n    val result = df.select(\"<labels>\").collectAsList().get(0).getAs[Seq[String]](0)\n\n    assertEquals(\"Person\", result.head)\n    assertEquals(\"Customer\", result(1))\n  }\n\n  @Test\n  def testReadNodeHasUnusualLabelsField(): Unit = {\n    val df: DataFrame = initTest(s\"CREATE (p:`Foo Bar`:Person {name: 'John'})\")\n\n    val result = df.select(\"<labels>\").collectAsList().get(0).getAs[Seq[String]](0)\n\n    assertEquals(Set(\"Person\", \"Foo Bar\"), result.toSet[String])\n  }\n\n  @Test\n  def testReadNodeWithFieldWithDifferentTypes(): Unit = {\n    val df: DataFrame = initTest(\"CREATE (p1:Person {id: 1, field: [12,34]}), (p2:Person {id: 2, field: 123})\")\n\n    val res = df.orderBy(\"id\").collectAsList()\n\n    assertEquals(\"[12,34]\", res.get(0).get(3))\n    assertEquals(\"123\", res.get(1).get(3))\n  }\n\n  @Test\n  def testReadNodeWithString(): Unit = {\n    val name: String = \"John\"\n    val df: DataFrame = initTest(s\"CREATE (p:Person {name: '$name'})\")\n\n    assertEquals(name, df.select(\"name\").collectAsList().get(0).getString(0))\n  }\n\n  @Test\n  def testReadNodeWithLong(): Unit = {\n    val age: Long = 42\n    val df: DataFrame = initTest(s\"CREATE (p:Person {age: $age})\")\n\n    assertEquals(age, df.select(\"age\").collectAsList().get(0).getLong(0))\n  }\n\n  @Test\n  def testReadNodeWithDouble(): Unit = {\n    val score: Double = 3.14\n    val df: DataFrame = initTest(s\"CREATE (p:Person {score: $score})\")\n\n    assertEquals(score, df.select(\"score\").collectAsList().get(0).getDouble(0), 0)\n  }\n\n  @Test\n  def testReadNodeWithLocalTime(): Unit = {\n    val df: DataFrame =\n      initTest(s\"CREATE (p:Person {aTime: localtime({hour:12, minute: 23, second: 0, millisecond: 294})})\")\n\n    val result = df.select(\"aTime\").collectAsList().get(0).getAs[GenericRowWithSchema](0)\n\n    assertEquals(\"local-time\", result.get(0))\n    assertEquals(\"12:23:00.294\", result.get(1))\n  }\n\n  @Test\n  def testReadNodeWithTime(): Unit = {\n    val timezone = TimeZone.getDefault\n    val df: DataFrame = initTest(s\"CREATE (p:Person {aTime: time({hour:12, minute: 23, second: 0, millisecond: 294})})\")\n\n    val result = df.select(\"aTime\").collectAsList().get(0).getAs[GenericRowWithSchema](0)\n\n    val localTime = LocalTime.of(12, 23, 0, 294000000)\n    val expectedTime = OffsetTime.of(localTime, timezone.toZoneId.getRules.getOffset(Instant.now()))\n\n    assertEquals(\"offset-time\", result.get(0))\n    assertEquals(expectedTime.toString, result.get(1))\n  }\n\n  @Test\n  def testReadNodeWithLocalDateTime(): Unit = {\n    val localDateTime = \"2007-12-03T10:15:30\"\n    val df: DataFrame = initTest(s\"CREATE (p:Person {aTime: localdatetime('$localDateTime')})\")\n\n    val result = df.select(\"aTime\").collectAsList().get(0).getAs[LocalDateTime](0)\n    assertEquals(LocalDateTime.parse(localDateTime), result)\n  }\n\n  @Test\n  def testReadNodeWithZonedDateTime(): Unit = {\n    val datetime = \"2015-06-24T12:50:35.556+01:00\"\n    val df: DataFrame = initTest(s\"CREATE (p:Person {aTime: datetime('$datetime')})\")\n\n    val result = df.select(\"aTime\").collectAsList().get(0).getTimestamp(0)\n\n    assertEquals(Timestamp.from(OffsetDateTime.parse(datetime).toInstant), result)\n  }\n\n  @Test\n  def testReadNodeWithPoint(): Unit = {\n    val df: DataFrame = initTest(s\"CREATE (p:Person {location: point({x: 12.12, y: 13.13})})\")\n\n    val res = df.select(\"location\").collectAsList().get(0).getAs[GenericRowWithSchema](0);\n\n    assertEquals(\"point-2d\", res.get(0))\n    assertEquals(7203, res.get(1))\n    assertEquals(12.12, res.get(2))\n    assertEquals(13.13, res.get(3))\n  }\n\n  @Test\n  def testReadNodeWithGeoPoint(): Unit = {\n    val df: DataFrame = initTest(s\"CREATE (p:Person {location: point({longitude: 12.12, latitude: 13.13})})\")\n\n    val res = df.select(\"location\").collectAsList().get(0).getAs[GenericRowWithSchema](0);\n\n    assertEquals(\"point-2d\", res.get(0))\n    assertEquals(4326, res.get(1))\n    assertEquals(12.12, res.get(2))\n    assertEquals(13.13, res.get(3))\n  }\n\n  @Test\n  def testReadNodeWithPoint3D(): Unit = {\n    val df: DataFrame = initTest(s\"CREATE (p:Person {location: point({x: 12.12, y: 13.13, z: 1})})\")\n\n    val res = df.select(\"location\").collectAsList().get(0).getAs[GenericRowWithSchema](0)\n\n    assertEquals(\"point-3d\", res.get(0))\n    assertEquals(9157, res.get(1))\n    assertEquals(12.12, res.get(2))\n    assertEquals(13.13, res.get(3))\n    assertEquals(1.0, res.get(4))\n  }\n\n  @Test\n  def testReadNodeWithDate(): Unit = {\n    val df: DataFrame = initTest(s\"CREATE (p:Person {born: date('2009-10-10')})\")\n\n    val list = df.select(\"born\").collectAsList()\n    val res = list.get(0).getDate(0)\n\n    assertEquals(java.sql.Date.valueOf(\"2009-10-10\"), res)\n  }\n\n  @Test\n  def testReadNodeWithDuration(): Unit = {\n    val df: DataFrame = initTest(s\"CREATE (p:Person {range: duration({days: 14, hours:16, minutes: 12})})\")\n\n    val list = df.select(\"range\").collectAsList()\n    val res = list.get(0).getAs[GenericRowWithSchema](0)\n\n    assertEquals(\"duration\", res(0))\n    assertEquals(0L, res(1))\n    assertEquals(14L, res(2))\n    assertEquals(58320L, res(3))\n    assertEquals(0, res(4))\n    assertEquals(\"P0M14DT58320S\", res(5))\n  }\n\n  @Test\n  def testReadNodeWithStringArray(): Unit = {\n    val df: DataFrame = initTest(s\"CREATE (p:Person {names: ['John', 'Doe']})\")\n\n    val res = df.select(\"names\").collectAsList().get(0).getAs[Seq[String]](0)\n\n    assertEquals(\"John\", res.head)\n    assertEquals(\"Doe\", res(1))\n  }\n\n  @Test\n  def testReadNodeWithLongArray(): Unit = {\n    val df: DataFrame = initTest(s\"CREATE (p:Person {ages: [22, 23]})\")\n\n    val res = df.select(\"ages\").collectAsList().get(0).getAs[Seq[Long]](0)\n\n    assertEquals(22, res.head)\n    assertEquals(23, res(1))\n  }\n\n  @Test\n  def testReadNodeWithDoubleArray(): Unit = {\n    val df: DataFrame = initTest(s\"CREATE (p:Person {scores: [22.33, 44.55]})\")\n\n    val res = df.select(\"scores\").collectAsList().get(0).getAs[Seq[Double]](0)\n\n    assertEquals(22.33, res.head, 0)\n    assertEquals(44.55, res(1), 0)\n  }\n\n  @Test\n  def testReadNodeWithLocalTimeArray(): Unit = {\n    val df: DataFrame =\n      initTest(s\"CREATE (p:Person {someTimes: [localtime({hour:12}), localtime({hour:1, minute: 3})]})\")\n\n    val res = df.select(\"someTimes\").collectAsList().get(0).getAs[Seq[GenericRowWithSchema]](0)\n\n    assertEquals(\"local-time\", res.head.get(0))\n    assertEquals(\"12:00:00\", res.head.get(1))\n    assertEquals(\"local-time\", res(1).get(0))\n    assertEquals(\"01:03:00\", res(1).get(1))\n  }\n\n  @Test\n  def testReadNodeWithBooleanArray(): Unit = {\n    val df: DataFrame = initTest(s\"CREATE (p:Person {bools: [true, false]})\")\n\n    val res = df.select(\"bools\").collectAsList().get(0).getAs[Seq[Boolean]](0)\n\n    assertEquals(true, res.head)\n    assertEquals(false, res(1))\n  }\n\n  @Test\n  def testReadNodeWithPointArray(): Unit = {\n    val df: DataFrame =\n      initTest(s\"CREATE (p:Person {locations: [point({x: 11, y: 33.111}), point({x: 22, y: 44.222})]})\")\n\n    val res = df.select(\"locations\").collectAsList().get(0).getAs[Seq[GenericRowWithSchema]](0)\n\n    assertEquals(\"point-2d\", res.head.get(0))\n    assertEquals(7203, res.head.get(1))\n    assertEquals(11.0, res.head.get(2))\n    assertEquals(33.111, res.head.get(3))\n\n    assertEquals(\"point-2d\", res(1).get(0))\n    assertEquals(7203, res(1).get(1))\n    assertEquals(22.0, res(1).get(2))\n    assertEquals(44.222, res(1).get(3))\n  }\n\n  @Test\n  def testReadNodeWithGeoPointArray(): Unit = {\n    val df: DataFrame = initTest(\n      s\"CREATE (p:Person {locations: [point({longitude: 11, latitude: 33.111}), point({longitude: 22, latitude: 44.222})]})\"\n    )\n\n    val res = df.select(\"locations\").collectAsList().get(0).getAs[Seq[GenericRowWithSchema]](0)\n\n    assertEquals(\"point-2d\", res.head.get(0))\n    assertEquals(4326, res.head.get(1))\n    assertEquals(11.0, res.head.get(2))\n    assertEquals(33.111, res.head.get(3))\n\n    assertEquals(\"point-2d\", res(1).get(0))\n    assertEquals(4326, res(1).get(1))\n    assertEquals(22.0, res(1).get(2))\n    assertEquals(44.222, res(1).get(3))\n  }\n\n  @Test\n  def testReadNodeWithPoint3DArray(): Unit = {\n    val df: DataFrame =\n      initTest(s\"CREATE (p:Person {locations: [point({x: 11, y: 33.111, z: 12}), point({x: 22, y: 44.222, z: 99.1})]})\")\n\n    val res = df.select(\"locations\").collectAsList().get(0).getAs[Seq[GenericRowWithSchema]](0)\n\n    assertEquals(\"point-3d\", res.head.get(0))\n    assertEquals(9157, res.head.get(1))\n    assertEquals(11.0, res.head.get(2))\n    assertEquals(33.111, res.head.get(3))\n    assertEquals(12.0, res.head.get(4))\n\n    assertEquals(\"point-3d\", res(1).get(0))\n    assertEquals(9157, res(1).get(1))\n    assertEquals(22.0, res(1).get(2))\n    assertEquals(44.222, res(1).get(3))\n    assertEquals(99.1, res(1).get(4))\n  }\n\n  @Test\n  def testReadNodeWithArrayDate(): Unit = {\n    val df: DataFrame = initTest(s\"CREATE (p:Person {dates: [date('2009-10-10'), date('2009-10-11')]})\")\n\n    val res = df.select(\"dates\").collectAsList().get(0).getAs[Seq[java.sql.Date]](0)\n\n    assertEquals(java.sql.Date.valueOf(\"2009-10-10\"), res.head)\n    assertEquals(java.sql.Date.valueOf(\"2009-10-11\"), res(1))\n  }\n\n  @Test\n  def testReadNodeWithArrayZonedDateTime(): Unit = {\n    val datetime1 = \"2015-06-24T12:50:35.556+01:00\"\n    val datetime2 = \"2015-06-23T12:50:35.556+01:00\"\n    val df: DataFrame = initTest(s\"\"\"\n     CREATE (p:Person {aTime: [\n      datetime('$datetime1'),\n      datetime('$datetime2')\n     ]})\n     \"\"\")\n\n    val result = df.select(\"aTime\").collectAsList().get(0).getAs[Seq[Timestamp]](0)\n\n    assertEquals(Timestamp.from(OffsetDateTime.parse(datetime1).toInstant), result.head)\n    assertEquals(Timestamp.from(OffsetDateTime.parse(datetime2).toInstant), result(1))\n  }\n\n  @Test\n  def testReadNodeWithArrayDurations(): Unit = {\n    val df: DataFrame = initTest(s\"CREATE (p:Person {durations: [duration({months: 0.75}), duration({weeks: 2.5})]})\")\n\n    val res = df.select(\"durations\").collectAsList().get(0).getAs[Seq[GenericRowWithSchema]](0)\n\n    assertEquals(\"duration\", res.head.get(0))\n    assertEquals(0L, res.head.get(1))\n    assertEquals(22L, res.head.get(2))\n    assertEquals(71509L, res.head.get(3))\n    assertEquals(500000000, res.head.get(4))\n    assertEquals(\"P0M22DT71509.500000000S\", res.head.get(5))\n\n    assertEquals(\"duration\", res(1).get(0))\n    assertEquals(0L, res(1).get(1))\n    assertEquals(17L, res(1).get(2))\n    assertEquals(43200L, res(1).get(3))\n    assertEquals(0, res(1).get(4))\n    assertEquals(\"P0M17DT43200S\", res(1).get(5))\n  }\n\n  @Test\n  def testReadNodeWithEqualToFilter(): Unit = {\n    val df: DataFrame = initTest(s\"\"\"\n     CREATE (p1:Person {name: 'John Doe'}),\n      (p2:Person {name: 'Jane Doe'})\n     \"\"\")\n\n    val result = df.select(\"name\").where(\"name = 'John Doe'\").collectAsList()\n\n    assertEquals(1, result.size())\n    assertEquals(\"John Doe\", result.get(0).getString(0))\n  }\n\n  @Test\n  def testReadNodeWithNotEqualToFilter(): Unit = {\n    val df: DataFrame = initTest(s\"\"\"\n     CREATE (p1:Person {name: 'John Doe'}),\n      (p2:Person {name: 'Jane Doe'})\n     \"\"\")\n\n    val result = df.select(\"name\").where(\"NOT name = 'John Doe'\").collectAsList()\n\n    assertEquals(1, result.size())\n    assertEquals(\"Jane Doe\", result.get(0).getString(0))\n  }\n\n  @Test\n  def testReadNodeWithDifferentOperatorFilter(): Unit = {\n    val df: DataFrame = initTest(s\"\"\"\n     CREATE (p1:Person {name: 'John Doe'}),\n      (p2:Person {name: 'Jane Doe'})\n     \"\"\")\n\n    val result = df.select(\"name\").where(\"name != 'John Doe'\").collectAsList()\n\n    assertEquals(1, result.size())\n    assertEquals(\"Jane Doe\", result.get(0).getString(0))\n  }\n\n  @Test\n  def testReadNodeWithGtFilter(): Unit = {\n    val df: DataFrame = initTest(s\"\"\"\n     CREATE (p1:Person {age: 19}),\n      (p2:Person {age: 20}),\n      (p3:Person {age: 21})\n     \"\"\")\n\n    val result = df.select(\"age\").where(\"age > 20\").collectAsList()\n\n    assertEquals(1, result.size())\n    assertEquals(21, result.get(0).getLong(0))\n  }\n\n  @Test\n  def testReadNodeWithGteFilter(): Unit = {\n    val df: DataFrame = initTest(s\"\"\"\n     CREATE (p1:Person {age: 19}),\n      (p2:Person {age: 20}),\n      (p3:Person {age: 21})\n     \"\"\")\n\n    val result = df.select(\"age\").orderBy(\"age\").where(\"age >= 20\").collectAsList()\n\n    assertEquals(2, result.size())\n    assertEquals(20, result.get(0).getLong(0))\n    assertEquals(21, result.get(1).getLong(0))\n  }\n\n  @Test\n  def testReadNodeWithGteFilterWithProp(): Unit = {\n    val df: DataFrame = initTest(s\"\"\"\n     CREATE (p1:Person {score: 19, limit: 20}),\n      (p2:Person {score: 20,  limit: 18}),\n      (p3:Person {score: 21,  limit: 12})\n     \"\"\")\n\n    val result = df.select(\"score\").orderBy(\"score\").where(\"score >= limit\").collectAsList()\n\n    assertEquals(2, result.size())\n    assertEquals(20, result.get(0).getLong(0))\n    assertEquals(21, result.get(1).getLong(0))\n  }\n\n  @Test\n  def testReadNodeWithLtFilter(): Unit = {\n    val df: DataFrame = initTest(s\"\"\"\n     CREATE (p1:Person {age: 39}),\n      (p2:Person {age: 41}),\n      (p3:Person {age: 43})\n     \"\"\")\n\n    val result = df.select(\"age\").orderBy(\"age\").where(\"age < 40\").collectAsList()\n\n    assertEquals(1, result.size())\n    assertEquals(39, result.get(0).getLong(0))\n  }\n\n  @Test\n  def testReadNodeWithLteFilter(): Unit = {\n    val df: DataFrame = initTest(s\"\"\"\n     CREATE (p1:Person {age: 39}),\n      (p2:Person {age: 41}),\n      (p3:Person {age: 43})\n     \"\"\")\n\n    val result = df.select(\"age\").orderBy(\"age\").where(\"age <= 41\").collectAsList()\n\n    assertEquals(2, result.size())\n    assertEquals(39, result.get(0).getLong(0))\n    assertEquals(41, result.get(1).getLong(0))\n  }\n\n  @Test\n  def testReadNodeWithInFilter(): Unit = {\n    val df: DataFrame = initTest(s\"\"\"\n     CREATE (p1:Person {age: 39}),\n      (p2:Person {age: 41}),\n      (p3:Person {age: 43})\n     \"\"\")\n\n    val result = df.select(\"age\").orderBy(\"age\").where(\"age IN(41,43)\").collectAsList()\n\n    assertEquals(2, result.size())\n    assertEquals(41, result.get(0).getLong(0))\n    assertEquals(43, result.get(1).getLong(0))\n  }\n\n  @Test\n  def testReadNodeWithIsNullFilter(): Unit = {\n    val df: DataFrame = initTest(s\"\"\"\n     CREATE (p1:Person {age: 39}),\n      (p2:Person {age: null}),\n      (p3:Person {age: 43})\n     \"\"\")\n\n    val result = df.select(\"age\").where(\"age IS NULL\").collectAsList()\n\n    assertEquals(1, result.size())\n    assertNull(result.get(0).get(0))\n  }\n\n  @Test\n  def testReadNodeWithIsNotNullFilter(): Unit = {\n    val df: DataFrame = initTest(s\"\"\"\n     CREATE (p1:Person {age: 39}),\n      (p2:Person {age: null}),\n      (p3:Person {age: 43})\n     \"\"\")\n\n    val result = df.select(\"age\").orderBy(\"age\").where(\"age IS NOT NULL\").collectAsList()\n\n    assertEquals(2, result.size())\n    assertEquals(39, result.get(0).getLong(0))\n    assertEquals(43, result.get(1).getLong(0))\n  }\n\n  @Test\n  def testReadNodeWithOrCondition(): Unit = {\n    val df: DataFrame = initTest(s\"\"\"\n     CREATE (p1:Person {age: 39}),\n      (p2:Person {age: null}),\n      (p3:Person {age: 43})\n     \"\"\")\n\n    val result = df.select(\"age\").orderBy(\"age\").where(\"age = 43 OR age = 39 OR age = 32\").collectAsList()\n\n    assertEquals(2, result.size())\n    assertEquals(39, result.get(0).getLong(0))\n    assertEquals(43, result.get(1).getLong(0))\n  }\n\n  @Test\n  def testReadNodeWithAndCondition(): Unit = {\n    val df: DataFrame = initTest(s\"\"\"\n     CREATE (p1:Person {age: 39}),\n      (p2:Person {age: null}),\n      (p3:Person {age: 43})\n     \"\"\")\n\n    val result = df.select(\"age\").orderBy(\"age\").where(\"age >= 39 AND age <= 43\").collectAsList()\n\n    assertEquals(2, result.size())\n    assertEquals(39, result.get(0).getLong(0))\n    assertEquals(43, result.get(1).getLong(0))\n  }\n\n  @Test\n  def testReadNodeWithStartsWith(): Unit = {\n    val df: DataFrame = initTest(s\"\"\"\n     CREATE (p1:Person {name: 'John Mayer'}),\n      (p2:Person {name: 'John Scofield'}),\n      (p3:Person {name: 'John Butler'})\n     \"\"\")\n\n    val result = df.select(\"name\").orderBy(\"name\").where(\"name LIKE 'John%'\").collectAsList()\n\n    assertEquals(3, result.size())\n    assertEquals(\"John Butler\", result.get(0).getString(0))\n    assertEquals(\"John Mayer\", result.get(1).getString(0))\n    assertEquals(\"John Scofield\", result.get(2).getString(0))\n  }\n\n  @Test\n  def testReadNodeWithEndsWith(): Unit = {\n    val df: DataFrame = initTest(s\"\"\"\n     CREATE (p1:Person {name: 'John Mayer'}),\n      (p2:Person {name: 'John Scofield'}),\n      (p3:Person {name: 'John Butler'})\n     \"\"\")\n\n    val result = df.select(\"name\").where(\"name LIKE '%Scofield'\").collectAsList()\n\n    assertEquals(1, result.size())\n    assertEquals(\"John Scofield\", result.get(0).getString(0))\n  }\n\n  @Test\n  def testReadNodeWithContains(): Unit = {\n    val df: DataFrame = initTest(s\"\"\"\n     CREATE (p1:Person {name: 'John Mayer'}),\n      (p2:Person {name: 'John Scofield'}),\n      (p3:Person {name: 'John Butler'})\n     \"\"\")\n\n    val result = df.select(\"name\").where(\"name LIKE '%ay%'\").collectAsList()\n\n    assertEquals(1, result.size())\n    assertEquals(\"John Mayer\", result.get(0).getString(0))\n  }\n\n  @Test\n  def testRelFiltersWithMap(): Unit = {\n    val fixtureQuery: String =\n      \"\"\"UNWIND range(1,100) as id\n        |CREATE (p:Person {id:id,ids:[id,id]}) WITH collect(p) as people\n        |UNWIND people as p1\n        |UNWIND range(1,10) as friend\n        |WITH p1, people[(p1.id + friend) % size(people)] as p2\n        |CREATE (p1)-[:KNOWS]->(p2)\n        |RETURN *\n    \"\"\".stripMargin\n\n    SparkConnectorScalaSuiteWithApocIT.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(fixtureQuery).consume()\n        }\n      )\n\n    val df = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteWithApocIT.server.getBoltUrl)\n      .option(\"relationship.nodes.map\", \"true\")\n      .option(\"relationship\", \"KNOWS\")\n      .option(\"relationship.source.labels\", \"Person\")\n      .option(\"relationship.target.labels\", \"Person\")\n      .load()\n\n    assertEquals(1, df.filter(\"`<source>`.`id` = '14' AND `<target>`.`id` = '16'\").collectAsList().size())\n  }\n\n  @Test\n  def testRelFiltersWithoutMap(): Unit = {\n    val fixtureQuery: String =\n      \"\"\"UNWIND range(1,100) as id\n        |CREATE (p:Person {id:id,ids:[id,id]}) WITH collect(p) as people\n        |UNWIND people as p1\n        |UNWIND range(1,10) as friend\n        |WITH p1, people[(p1.id + friend) % size(people)] as p2\n        |CREATE (p1)-[:KNOWS]->(p2)\n        |RETURN *\n    \"\"\".stripMargin\n\n    SparkConnectorScalaSuiteWithApocIT.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(fixtureQuery).consume()\n        }\n      )\n\n    val df = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteWithApocIT.server.getBoltUrl)\n      .option(\"relationship\", \"KNOWS\")\n      .option(\"relationship.nodes.map\", \"false\")\n      .option(\"relationship.source.labels\", \"Person\")\n      .option(\"relationship.target.labels\", \"Person\")\n      .load()\n\n    assertEquals(1, df.filter(\"`source.id` = 14 AND `target.id` = 16\").collectAsList().size())\n  }\n\n  @Test\n  def testReadNodeRepartition(): Unit = {\n    val fixtureQuery: String =\n      \"\"\"UNWIND range(1,100) as id\n        |CREATE (p:Person {id:id,ids:[id,id]}) WITH collect(p) as people\n        |UNWIND people as p1\n        |UNWIND range(1,10) as friend\n        |WITH p1, people[(p1.id + friend) % size(people)] as p2\n        |CREATE (p1)-[:KNOWS]->(p2)\n        |RETURN *\n    \"\"\".stripMargin\n\n    val df: DataFrame = initTest(fixtureQuery)\n    val repartitionedDf = df.repartition(10)\n\n    assertEquals(10, repartitionedDf.rdd.getNumPartitions)\n    val numNode = repartitionedDf.collect().length\n    assertEquals(100, numNode)\n  }\n\n  @Test\n  def testRelationshipsFlatten(): Unit = {\n    val total = 100\n    val fixtureQuery: String =\n      s\"\"\"UNWIND range(1, $total) as id\n         |CREATE (pr:Product {id: id * rand(), name: 'Product ' + id})\n         |CREATE (pe:Person {id: id, fullName: 'Person ' + id})\n         |CREATE (pe)-[:BOUGHT{when: rand(), quantity: rand() * 1000}]->(pr)\n         |RETURN *\n    \"\"\".stripMargin\n\n    SparkConnectorScalaSuiteWithApocIT.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(fixtureQuery).consume()\n        }\n      )\n\n    val df: DataFrame = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteWithApocIT.server.getBoltUrl)\n      .option(\"relationship\", \"BOUGHT\")\n      .option(\"relationship.nodes.map\", \"false\")\n      .option(\"relationship.source.labels\", \":Person\")\n      .option(\"relationship.target.labels\", \":Product\")\n      .load()\n\n    val count = df.collectAsList()\n      .asScala\n      .filter(row =>\n        row.getAs[Long](\"<rel.id>\") >= 0\n          && row.getAs[String](\"<rel.type>\") != null\n          && row.getAs[Double](\"rel.when\") >= 0\n          && row.getAs[Double](\"rel.quantity\") >= 0\n          && row.getAs[Long](\"<source.id>\") >= 0\n          && row.getAs[Long](\"source.id\") >= 0\n          && !row.getAs[Seq[String]](\"<source.labels>\").isEmpty\n          && row.getAs[String](\"source.fullName\") != null\n          && row.getAs[Long](\"<target.id>\") >= 0\n          && row.getAs[Double](\"target.id\") >= 0\n          && !row.getAs[Seq[String]](\"<target.labels>\").isEmpty\n          && row.getAs[String](\"target.name\") != null\n      )\n      .size\n    assertEquals(total, count)\n  }\n\n  @Test\n  def testRelationshipsMap(): Unit = {\n    val total = 100\n    val fixtureQuery: String =\n      s\"\"\"UNWIND range(1, $total) as id\n         |CREATE (pr:Product {id: id * rand(), name: 'Product ' + id})\n         |CREATE (pe:Person {id: id, fullName: 'Person ' + id})\n         |CREATE (pe)-[:BOUGHT{when: rand(), quantity: rand() * 1000}]->(pr)\n         |RETURN *\n    \"\"\".stripMargin\n\n    SparkConnectorScalaSuiteWithApocIT.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(fixtureQuery).consume()\n        }\n      )\n\n    val df: DataFrame = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteWithApocIT.server.getBoltUrl)\n      .option(\"relationship\", \"BOUGHT\")\n      .option(\"relationship.nodes.map\", \"true\")\n      .option(\"relationship.source.labels\", \":Person\")\n      .option(\"relationship.target.labels\", \":Product\")\n      .load()\n\n    val rows = df.collectAsList().asScala\n    val count = rows\n      .filter(row =>\n        row.getAs[Long](\"<rel.id>\") >= 0\n          && row.getAs[String](\"<rel.type>\") != null\n          && row.getAs[Double](\"rel.when\") >= 0\n          && row.getAs[Double](\"rel.quantity\") >= 0\n          && row.getAs[Map[String, String]](\"<source>\") != null\n          && row.getAs[Map[String, String]](\"<target>\") != null\n      )\n      .size\n    assertEquals(total, count)\n\n    val countSourceMap = rows.map(row => row.getAs[Map[String, String]](\"<source>\"))\n      .filter(row => row.keys == Set(\"id\", \"fullName\", \"<id>\", \"<labels>\"))\n      .size\n    assertEquals(total, countSourceMap)\n    val countTargetMap = rows.map(row => row.getAs[Map[String, String]](\"<target>\"))\n      .filter(row => row.keys == Set(\"id\", \"name\", \"<id>\", \"<labels>\"))\n      .size\n    assertEquals(total, countTargetMap)\n  }\n\n  @Test\n  def testRelationshipsDifferentFieldValues(): Unit = {\n    val fixtureQuery: String =\n      s\"\"\"CREATE (pr1:Product {id: '1'})\n         |CREATE (pr2:Product {id: 2})\n         |CREATE (pe1:Person {id: '3'})\n         |CREATE (pe2:Person {id: 4})\n         |CREATE (pe1)-[:BOUGHT]->(pr1)\n         |CREATE (pe2)-[:BOUGHT]->(pr2)\n         |RETURN *\n    \"\"\".stripMargin\n\n    SparkConnectorScalaSuiteWithApocIT.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(fixtureQuery).consume()\n        }\n      )\n\n    val df: DataFrame = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteWithApocIT.server.getBoltUrl)\n      .option(\"relationship.nodes.map\", \"false\")\n      .option(\"relationship\", \"BOUGHT\")\n      .option(\"relationship.source.labels\", \":Person\")\n      .option(\"relationship.target.labels\", \":Product\")\n      .load()\n\n    val res = df.sort(\"`source.id`\").collectAsList()\n\n    assertEquals(\"3\", res.get(0).get(4))\n    assertEquals(\"1\", res.get(0).get(7))\n    assertEquals(\"4\", res.get(1).get(4))\n    assertEquals(\"2\", res.get(1).get(7))\n  }\n\n  @Test\n  def testShouldReturnSamePropertiesForNodesWithMultipleLabels(): Unit = {\n    val fixtureQuery: String =\n      s\"\"\"CREATE (actor:Person:Actor {name: 'Keanu Reeves', born: 1964, actor: true})\n         |CREATE (soccerPlayer:Person:SoccerPlayer {name: 'Zlatan Ibrahimović', born: 1981, soccerPlayer: true})\n         |CREATE (writer:Person:Writer {name: 'Philip K. Dick', born: 1928, writer: true})\n    \"\"\".stripMargin\n\n    SparkConnectorScalaSuiteWithApocIT.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(fixtureQuery).consume()\n        }\n      )\n\n    val df: DataFrame = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteWithApocIT.server.getBoltUrl)\n      .option(\"labels\", \"Person\")\n      .load()\n      .sort(\"name\")\n\n    val cols = df.columns.toSeq.sorted\n    val expectedCols = Seq(\"name\", \"born\", \"actor\", \"soccerPlayer\", \"writer\", \"<id>\", \"<labels>\")\n      .sorted\n    assertEquals(expectedCols, cols)\n\n    val data = df.collect().toSeq\n      .map(row =>\n        expectedCols.filterNot(_ == \"<id>\").map(col => {\n          row.getAs[Any](col) match {\n            case array: Array[String] => array.toList\n            case null                 => null\n            case other: Any           => other\n          }\n        })\n      )\n    val expectedData = Seq(\n      Seq(ArraySeq(\"Person\", \"Actor\"), true, 1964, \"Keanu Reeves\", null, null),\n      Seq(ArraySeq(\"Person\", \"Writer\"), null, 1928, \"Philip K. Dick\", null, true),\n      Seq(ArraySeq(\"Person\", \"SoccerPlayer\"), null, 1981, \"Zlatan Ibrahimović\", true, null)\n    ).toBuffer\n    assertEquals(expectedData, data)\n  }\n\n  @Test\n  def testShouldReturnSamePropertiesForNodesWithMultipleLabelsAndDifferentValues(): Unit = {\n    val fixtureQuery: String =\n      s\"\"\"CREATE (:Person { prop: 25 }),\n         |(:Person:Player { prop: \"hello\" }),\n         |(:Person:Player:Weirdo { prop: true })\n    \"\"\".stripMargin\n\n    SparkConnectorScalaSuiteWithApocIT.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(fixtureQuery).consume()\n        }\n      )\n\n    val df: DataFrame = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteWithApocIT.server.getBoltUrl)\n      .option(\"labels\", \"Person\")\n      .load()\n      .sort(\"prop\")\n\n    val cols = df.columns.toSeq.sorted\n    val expectedCols = Seq(\"prop\", \"<id>\", \"<labels>\")\n      .sorted\n    assertEquals(expectedCols, cols)\n\n    val data = df.collect().toSeq\n      .map(row =>\n        expectedCols.filterNot(_ == \"<id>\").map(col => {\n          row.getAs[Any](col) match {\n            case array: Array[String] => array.toList\n            case null                 => null\n            case other: Any           => other\n          }\n        })\n      )\n    val expectedData = Seq(\n      Seq(ArraySeq(\"Person\"), \"25\"),\n      Seq(ArraySeq(\"Person\", \"Player\"), \"hello\"),\n      Seq(ArraySeq(\"Person\", \"Player\", \"Weirdo\"), \"true\")\n    )\n    assertEquals(expectedData, data)\n  }\n\n  @Test\n  def testReadNodesCustomPartitions(): Unit = {\n    val fixtureQuery: String =\n      \"\"\"UNWIND range(1,100) as id\n        |CREATE (p:Person:Customer {id: id, name: 'Person ' + id})\n        |RETURN *\n    \"\"\".stripMargin\n    val fixture2Query: String =\n      \"\"\"UNWIND range(1,100) as id\n        |CREATE (p:Employee:Customer {id: id, name: 'Person ' + id})\n        |RETURN *\n    \"\"\".stripMargin\n    SparkConnectorScalaSuiteWithApocIT.driver.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(fixtureQuery).consume()\n        }\n      )\n    SparkConnectorScalaSuiteWithApocIT.driver.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(fixture2Query).consume()\n        }\n      )\n\n    val partitionedDf = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteWithApocIT.server.getBoltUrl)\n      .option(\"labels\", \":Person:Customer\")\n      .option(\"partitions\", \"5\")\n      .load()\n\n    assertEquals(5, partitionedDf.rdd.getNumPartitions)\n    assertEquals(100, partitionedDf.collect().map(_.getAs[Long](\"id\")).toSet.size)\n  }\n\n  @Test\n  def testReadRelsCustomPartitions(): Unit = {\n    val fixtureQuery: String =\n      \"\"\"UNWIND range(1,100) as id\n        |CREATE (p:Person {id: id, name: 'Person ' + id})-[:BOUGHT{quantity: ceil(rand() * 100)}]->(:Product{id: id, name: 'Product ' + id})\n        |RETURN *\n    \"\"\".stripMargin\n    SparkConnectorScalaSuiteWithApocIT.driver.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(fixtureQuery).consume()\n        }\n      )\n\n    val partitionedDf = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteWithApocIT.server.getBoltUrl)\n      .option(\"relationship.nodes.map\", \"true\")\n      .option(\"relationship\", \"BOUGHT\")\n      .option(\"relationship.source.labels\", \":Person\")\n      .option(\"relationship.target.labels\", \":Product\")\n      .option(\"partitions\", \"5\")\n      .load()\n\n    assertEquals(5, partitionedDf.rdd.getNumPartitions)\n    assertEquals(100, partitionedDf.collect().map(_.getAs[Long](\"<rel.id>\")).toSet.size)\n  }\n\n  @Test\n  def testReturnProcedure(): Unit = {\n    val query =\n      \"\"\"RETURN apoc.convert.toSet([1,1,3]) AS foo, 'bar' AS bar\n        |\"\"\".stripMargin\n\n    val df = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteWithApocIT.server.getBoltUrl)\n      .option(\"partitions\", 1)\n      .option(\"query\", query)\n      .load\n\n    assertEquals(Set(\"foo\", \"bar\"), df.columns.toSet)\n    assertEquals(1, df.count())\n  }\n\n  private def initTest(query: String): DataFrame = {\n    SparkConnectorScalaSuiteWithApocIT.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(query).consume()\n        }\n      )\n\n    ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteWithApocIT.server.getBoltUrl)\n      .option(\"labels\", \"Person\")\n      .load()\n  }\n}\n"
  },
  {
    "path": "spark-3/src/test/scala/org/neo4j/spark/DataSourceSchemaWriterTSE.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark\n\nimport org.apache.spark.sql.DataFrame\nimport org.apache.spark.sql.SaveMode\nimport org.apache.spark.sql.SparkSession\nimport org.apache.spark.sql.catalyst.util.DateTimeUtils\nimport org.apache.spark.sql.types.DataTypes\nimport org.apache.spark.sql.types.DayTimeIntervalType\nimport org.apache.spark.sql.types.StructField\nimport org.apache.spark.sql.types.StructType\nimport org.apache.spark.sql.types.YearMonthIntervalType\nimport org.junit.Assert.assertArrayEquals\nimport org.junit.Assert.assertEquals\nimport org.junit.Assert.assertTrue\nimport org.junit.Assume\nimport org.junit.BeforeClass\nimport org.junit.Test\nimport org.neo4j.driver.types.IsoDuration\nimport org.neo4j.spark.util.ConstraintsOptimizationType\nimport org.neo4j.spark.util.Neo4jOptions\nimport org.neo4j.spark.util.SchemaConstraintsOptimizationType\n\nimport java.sql.Date\nimport java.sql.Timestamp\nimport java.time.LocalDate\nimport java.time.LocalDateTime\nimport java.time.ZoneId\nimport java.time.ZoneOffset\nimport java.time.ZonedDateTime\nimport java.util.TimeZone\n\nimport scala.collection.JavaConverters.iterableAsScalaIterableConverter\nimport scala.collection.JavaConverters.mapAsScalaMapConverter\nimport scala.math.Ordering.Implicits.infixOrderingOps\n\nobject DataSourceSchemaWriterTSE {\n\n  @BeforeClass\n  def checkNeo4jVersion() {\n    Assume.assumeTrue(TestUtil.neo4jVersion(SparkConnectorScalaSuiteIT.session()) >= Versions.NEO4J_5_13)\n  }\n}\n\nclass DataSourceSchemaWriterTSE extends SparkConnectorScalaBaseTSE {\n  val timeZoneLock = \"UTC\" // to make TIMESTAMP_NTZ tests deterministic\n\n  final private val SHOW_CONSTRAINTS_QUERY =\n    \"\"\"|SHOW CONSTRAINTS\n       |YIELD name, type, entityType, labelsOrTypes, properties, ownedIndex, propertyType\"\"\".stripMargin\n\n  final private val NODE_UNIQUENESS_SHOW_CONSTRAINTS_QUERY =\n    \"\"\"|SHOW CONSTRAINTS\n       |YIELD name, type AS ptype, entityType, labelsOrTypes, properties, ownedIndex, propertyType\n       |RETURN name, entityType, labelsOrTypes, properties, ownedIndex,\n       |CASE ptype\n       |  WHEN \"UNIQUENESS\" THEN \"NODE_PROPERTY_UNIQUENESS\"\n       |  ELSE ptype\n       |END AS type, propertyType\n       |ORDER BY type ASC\"\"\".stripMargin\n\n  final private val RELATIONSHIP_UNIQUENESS_SHOW_CONSTRAINTS_QUERY =\n    \"\"\"|SHOW CONSTRAINTS\n       |YIELD name, type AS ptype, entityType, labelsOrTypes, properties, ownedIndex, propertyType\n       |RETURN name, entityType, labelsOrTypes, properties, ownedIndex,\n       |CASE ptype\n       |  WHEN \"RELATIONSHIP_UNIQUENESS\" THEN \"RELATIONSHIP_PROPERTY_UNIQUENESS\"\n       |  ELSE ptype\n       |END AS type, propertyType\n       |ORDER BY type ASC\"\"\".stripMargin\n\n  final private val ALL_TYPES_AS_COL_NAMES = Array(\n    \"string\",\n    \"int\",\n    \"boolean\",\n    \"float\",\n    \"date\",\n    \"localDateTime\",\n    \"zonedDateTime\",\n    \"stringArray\",\n    \"intArray\",\n    \"booleanArray\",\n    \"floatArray\",\n    \"dateArray\",\n    \"localDateTimeArray\",\n    \"zonedDateTimeArray\"\n  )\n\n  val sparkSession = SparkSession.builder()\n    .master(\"local[*]\")\n    .appName(\"DataSourceWriterTSE\")\n    .config(\"spark.sql.session.timeZone\", timeZoneLock) // to make TIMESTAMP_NTZ tests deterministic\n    .getOrCreate()\n\n  import sparkSession.implicits._\n\n  private def mapData(data: Any): Any = data match {\n    case null                 => null\n    case a: Array[_]          => a.toSeq.map(mapData)\n    case l: java.util.List[_] => l.asScala.toSeq.map(mapData)\n    case d: LocalDate         => Date.valueOf(d)\n    case zdt: ZonedDateTime   => Timestamp.from(zdt.toInstant)\n    case any: Any             => any\n  }\n\n  private val schemaOptimization = SchemaConstraintsOptimizationType.values\n    .filterNot(_ == SchemaConstraintsOptimizationType.NONE)\n    .mkString(\",\")\n\n  private val nodeWithSchema = \"NodeWithSchema\"\n\n  @Test\n  def shouldApplySchemaForNodes(): Unit = {\n    val (expectedNode: Map[_root_.java.lang.String, Any], df: DataFrame) = createNodesDataFrameWithNotNullColumns\n\n    df\n      .write\n      .mode(SaveMode.Append)\n      .format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"labels\", s\":$nodeWithSchema\")\n      .option(Neo4jOptions.SCHEMA_OPTIMIZATION, schemaOptimization)\n      .save()\n\n    val count: Long = SparkConnectorScalaSuiteIT.session().run(\n      s\"\"\"\n         |MATCH (n:$nodeWithSchema)\n         |RETURN count(n)\n         |\"\"\".stripMargin\n    )\n      .single()\n      .get(0)\n      .asLong()\n\n    assertEquals(1L, count)\n\n    val expectedSchema = Seq(\n      constraintNodeNotNull(nodeWithSchema, \"boolean\"),\n      constraintNodeNotNull(nodeWithSchema, \"float\"),\n      constraintNodeNotNull(nodeWithSchema, \"int\"),\n      constraintNodeNotNull(nodeWithSchema, \"string\"),\n      constraintNodeType(nodeWithSchema, \"boolean\", \"BOOLEAN\"),\n      constraintNodeType(nodeWithSchema, \"booleanArray\", \"LIST<BOOLEAN NOT NULL>\"),\n      constraintNodeType(nodeWithSchema, \"date\", \"DATE\"),\n      constraintNodeType(nodeWithSchema, \"dateArray\", \"LIST<DATE NOT NULL>\"),\n      constraintNodeType(nodeWithSchema, \"float\", \"FLOAT\"),\n      constraintNodeType(nodeWithSchema, \"floatArray\", \"LIST<FLOAT NOT NULL>\"),\n      constraintNodeType(nodeWithSchema, \"int\", \"INTEGER\"),\n      constraintNodeType(nodeWithSchema, \"intArray\", \"LIST<INTEGER NOT NULL>\"),\n      constraintNodeType(nodeWithSchema, \"localDateTime\", \"LOCAL DATETIME\"),\n      constraintNodeType(nodeWithSchema, \"localDateTimeArray\", \"LIST<LOCAL DATETIME NOT NULL>\"),\n      constraintNodeType(nodeWithSchema, \"string\", \"STRING\"),\n      constraintNodeType(nodeWithSchema, \"stringArray\", \"LIST<STRING NOT NULL>\"),\n      constraintNodeType(nodeWithSchema, \"zonedDateTime\", \"ZONED DATETIME\"),\n      constraintNodeType(nodeWithSchema, \"zonedDateTimeArray\", \"LIST<ZONED DATETIME NOT NULL>\")\n    )\n\n    val actualSchema = SparkConnectorScalaSuiteIT.session()\n      .run(SHOW_CONSTRAINTS_QUERY)\n      .list()\n      .asScala\n      .map(_.asMap(v => v.asObject()).asScala.mapValues(mapData).toMap)\n      .toSeq\n\n    assertEquals(expectedSchema, actualSchema)\n\n    val actualNode = SparkConnectorScalaSuiteIT.session()\n      .readTransaction(tx =>\n        tx.run(s\"MATCH (n:$nodeWithSchema) RETURN n\")\n          .list()\n          .asScala\n          .map(_.get(\"n\").asNode())\n          .map(_.asMap())\n      )\n      .head\n      .asScala\n      .mapValues(mapData)\n      .toMap\n\n    assertEquals(expectedNode, actualNode)\n  }\n\n  @Test\n  def shouldApplySchemaAndNodeKeysForNodes(): Unit = {\n    val (expectedNode: Map[_root_.java.lang.String, Any], df: DataFrame) = createNodesDataFrameWithNotNullColumns\n\n    df.write\n      .mode(SaveMode.Overwrite)\n      .format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"labels\", s\":$nodeWithSchema\")\n      .option(Neo4jOptions.SCHEMA_OPTIMIZATION, schemaOptimization)\n      .option(Neo4jOptions.SCHEMA_OPTIMIZATION_NODE_KEY, ConstraintsOptimizationType.KEY.toString)\n      .option(\"node.keys\", \"int,string\")\n      .save()\n\n    val count: Long = SparkConnectorScalaSuiteIT.session().run(\n      s\"\"\"\n         |MATCH (n:$nodeWithSchema)\n         |RETURN count(n)\n         |\"\"\".stripMargin\n    )\n      .single()\n      .get(0)\n      .asLong()\n\n    assertEquals(1L, count)\n\n    val expectedSchema = Seq(\n      constraintNodeNotNull(nodeWithSchema, \"boolean\"),\n      constraintNodeNotNull(nodeWithSchema, \"float\"),\n      constraintNodeNotNull(nodeWithSchema, \"int\"),\n      constraintNodeNotNull(nodeWithSchema, \"string\"),\n      constraintNodeType(nodeWithSchema, \"boolean\", \"BOOLEAN\"),\n      constraintNodeType(nodeWithSchema, \"booleanArray\", \"LIST<BOOLEAN NOT NULL>\"),\n      constraintNodeType(nodeWithSchema, \"date\", \"DATE\"),\n      constraintNodeType(nodeWithSchema, \"dateArray\", \"LIST<DATE NOT NULL>\"),\n      constraintNodeType(nodeWithSchema, \"float\", \"FLOAT\"),\n      constraintNodeType(nodeWithSchema, \"floatArray\", \"LIST<FLOAT NOT NULL>\"),\n      constraintNodeType(nodeWithSchema, \"int\", \"INTEGER\"),\n      constraintNodeType(nodeWithSchema, \"intArray\", \"LIST<INTEGER NOT NULL>\"),\n      constraintNodeType(nodeWithSchema, \"localDateTime\", \"LOCAL DATETIME\"),\n      constraintNodeType(nodeWithSchema, \"localDateTimeArray\", \"LIST<LOCAL DATETIME NOT NULL>\"),\n      constraintNodeType(nodeWithSchema, \"string\", \"STRING\"),\n      constraintNodeType(nodeWithSchema, \"stringArray\", \"LIST<STRING NOT NULL>\"),\n      constraintNodeType(nodeWithSchema, \"zonedDateTime\", \"ZONED DATETIME\"),\n      constraintNodeType(nodeWithSchema, \"zonedDateTimeArray\", \"LIST<ZONED DATETIME NOT NULL>\"),\n      constraintNodeKey(nodeWithSchema, Seq(\"int\", \"string\"))\n    )\n\n    val actualSchema = SparkConnectorScalaSuiteIT.session()\n      .run(SHOW_CONSTRAINTS_QUERY)\n      .list()\n      .asScala\n      .map(_.asMap(v => v.asObject()).asScala.mapValues(mapData).toMap)\n      .toSeq\n\n    assertEquals(expectedSchema, actualSchema)\n\n    val actualNode = SparkConnectorScalaSuiteIT.session()\n      .readTransaction(tx =>\n        tx.run(s\"MATCH (n:$nodeWithSchema) RETURN n\")\n          .list()\n          .asScala\n          .map(_.get(\"n\").asNode())\n          .map(_.asMap())\n      )\n      .head\n      .asScala\n      .mapValues(mapData)\n      .toMap\n\n    assertEquals(expectedNode, actualNode)\n  }\n\n  @Test\n  def shouldApplySchemaAndNodeKeysForNodesWhenRemapped(): Unit = {\n    val (node: Map[_root_.java.lang.String, Any], df: DataFrame) = createNodesDataFrameWithNotNullColumns\n\n    df.write\n      .mode(SaveMode.Overwrite)\n      .format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"labels\", s\":$nodeWithSchema\")\n      .option(Neo4jOptions.SCHEMA_OPTIMIZATION, schemaOptimization)\n      .option(Neo4jOptions.SCHEMA_OPTIMIZATION_NODE_KEY, ConstraintsOptimizationType.KEY.toString)\n      .option(\"node.keys\", \"int:int_prop,string:string_prop\")\n      .save()\n\n    val count: Long = SparkConnectorScalaSuiteIT.session().run(\n      s\"\"\"\n         |MATCH (n:$nodeWithSchema)\n         |RETURN count(n)\n         |\"\"\".stripMargin\n    )\n      .single()\n      .get(0)\n      .asLong()\n\n    assertEquals(1L, count)\n\n    val expectedSchema = Seq(\n      constraintNodeNotNull(nodeWithSchema, \"boolean\"),\n      constraintNodeNotNull(nodeWithSchema, \"float\"),\n      constraintNodeNotNull(nodeWithSchema, \"int_prop\"),\n      constraintNodeNotNull(nodeWithSchema, \"string_prop\"),\n      constraintNodeType(nodeWithSchema, \"boolean\", \"BOOLEAN\"),\n      constraintNodeType(nodeWithSchema, \"booleanArray\", \"LIST<BOOLEAN NOT NULL>\"),\n      constraintNodeType(nodeWithSchema, \"date\", \"DATE\"),\n      constraintNodeType(nodeWithSchema, \"dateArray\", \"LIST<DATE NOT NULL>\"),\n      constraintNodeType(nodeWithSchema, \"float\", \"FLOAT\"),\n      constraintNodeType(nodeWithSchema, \"floatArray\", \"LIST<FLOAT NOT NULL>\"),\n      constraintNodeType(nodeWithSchema, \"intArray\", \"LIST<INTEGER NOT NULL>\"),\n      constraintNodeType(nodeWithSchema, \"int_prop\", \"INTEGER\"),\n      constraintNodeType(nodeWithSchema, \"localDateTime\", \"LOCAL DATETIME\"),\n      constraintNodeType(nodeWithSchema, \"localDateTimeArray\", \"LIST<LOCAL DATETIME NOT NULL>\"),\n      constraintNodeType(nodeWithSchema, \"stringArray\", \"LIST<STRING NOT NULL>\"),\n      constraintNodeType(nodeWithSchema, \"string_prop\", \"STRING\"),\n      constraintNodeType(nodeWithSchema, \"zonedDateTime\", \"ZONED DATETIME\"),\n      constraintNodeType(nodeWithSchema, \"zonedDateTimeArray\", \"LIST<ZONED DATETIME NOT NULL>\"),\n      constraintNodeKey(nodeWithSchema, Seq(\"int_prop\", \"string_prop\"))\n    )\n\n    val actualSchema = SparkConnectorScalaSuiteIT.session()\n      .run(SHOW_CONSTRAINTS_QUERY)\n      .list()\n      .asScala\n      .map(_.asMap(v => v.asObject()).asScala.mapValues(mapData).toMap)\n      .toSeq\n\n    assertEquals(expectedSchema, actualSchema)\n\n    val expectedNode =\n      node.map {\n        case (k, v) =>\n          if (k == \"string\" || k == \"int\") (k + \"_prop\", v)\n          else (k, v)\n      }\n\n    val actualNode = SparkConnectorScalaSuiteIT.session()\n      .readTransaction(tx =>\n        tx.run(s\"MATCH (n:$nodeWithSchema) RETURN n\")\n          .list()\n          .asScala\n          .map(_.get(\"n\").asNode())\n          .map(_.asMap())\n      )\n      .head\n      .asScala\n      .mapValues(mapData)\n      .toMap\n\n    assertEquals(expectedNode, actualNode)\n  }\n\n  final private def constraintNodeNotNull(node: String, prop: String): Map[String, Any] = Map(\n    \"name\" -> s\"spark_NODE-NOT_NULL-CONSTRAINT-$node-$prop\",\n    \"type\" -> \"NODE_PROPERTY_EXISTENCE\",\n    \"entityType\" -> \"NODE\",\n    \"labelsOrTypes\" -> Seq(node),\n    \"properties\" -> Seq(prop),\n    \"ownedIndex\" -> null,\n    \"propertyType\" -> null\n  )\n\n  final private def constraintNodeType(node: String, prop: String, expectedType: String): Map[String, Any] = Map(\n    \"name\" -> s\"spark_NODE-TYPE-CONSTRAINT-$node-$prop\",\n    \"type\" -> \"NODE_PROPERTY_TYPE\",\n    \"entityType\" -> \"NODE\",\n    \"labelsOrTypes\" -> Seq(node),\n    \"properties\" -> Seq(prop),\n    \"ownedIndex\" -> null,\n    \"propertyType\" -> expectedType\n  )\n\n  final private def constraintNodeKey(node: String, props: Seq[String]): Map[String, Any] = Map(\n    \"name\" -> s\"spark_NODE_KEY-CONSTRAINT_${node}_${props.mkString(\"-\")}\",\n    \"type\" -> \"NODE_KEY\",\n    \"entityType\" -> \"NODE\",\n    \"labelsOrTypes\" -> Seq(node),\n    \"properties\" -> props,\n    \"ownedIndex\" -> s\"spark_NODE_KEY-CONSTRAINT_${node}_${props.mkString(\"-\")}\",\n    \"propertyType\" -> null\n  )\n\n  private def createNodesDataFrameWithNotNullColumns: (Map[String, Any], DataFrame) = {\n    TimeZone.setDefault(TimeZone.getTimeZone(timeZoneLock))\n\n    val row = (\n      \"Foo\",\n      1,\n      false,\n      1.1,\n      Date.valueOf(\"2023-11-22\"),\n      LocalDateTime.of(2023, 11, 22, 12, 12, 12),\n      Timestamp.valueOf(s\"2020-11-22 11:11:11.11\"),\n      Seq(\"Foo1\", \"Foo2\"),\n      Seq(1, 2),\n      Seq(true, false),\n      Seq(1.1, 2.2),\n      Seq(Date.valueOf(\"2023-11-22\"), Date.valueOf(\"2023-11-23\")),\n      Seq(LocalDateTime.of(2023, 11, 22, 11, 11, 11), LocalDateTime.of(2023, 11, 23, 12, 12, 12)),\n      Seq(Timestamp.valueOf(\"2023-11-22 11:11:11.11\"), Timestamp.valueOf(\"2023-11-23 12:12:12.12\"))\n    )\n\n    val data = Seq(row).toDF(ALL_TYPES_AS_COL_NAMES: _*)\n    val expectedNode = ALL_TYPES_AS_COL_NAMES.zip(row.productIterator.toSeq).toMap\n\n    val schema = StructType(data.schema.map { sf =>\n      sf.name match {\n        case \"localDateTimeArray\" =>\n          StructField(sf.name, DataTypes.createArrayType(DataTypes.TimestampNTZType, false), sf.nullable)\n        case \"zonedDateTimeArray\" =>\n          StructField(sf.name, DataTypes.createArrayType(DataTypes.TimestampType, false), sf.nullable)\n        case \"stringArray\" => StructField(sf.name, DataTypes.createArrayType(DataTypes.StringType, false), sf.nullable)\n        case \"dateArray\"   => StructField(sf.name, DataTypes.createArrayType(DataTypes.DateType, false), sf.nullable)\n        case \"string\"      => StructField(sf.name, DataTypes.StringType, false)\n        case _             => sf\n      }\n    })\n\n    val df = ss.createDataFrame(data.rdd, schema)\n    (expectedNode, df)\n  }\n\n  @Test\n  def shouldApplySchemaForRelationshipsAndNodes(): Unit = {\n    val expectedMap = createDatasetForRelationships(\n      Map(\n        Neo4jOptions.SCHEMA_OPTIMIZATION -> schemaOptimization\n      )\n    )\n\n    val count: Long = SparkConnectorScalaSuiteIT.session().run(\n      \"\"\"\n        |MATCH p = (:NodeA)-[:MY_REL]->(:NodeB)\n        |RETURN count(p)\n        |\"\"\".stripMargin\n    )\n      .single()\n      .get(0)\n      .asLong()\n\n    assertEquals(1L, count)\n\n    val expected = Seq(\n      constraintNodeNotNull(\"NodeA\", \"id\"),\n      constraintNodeNotNull(\"NodeB\", \"id\"),\n      constraintNodeType(\"NodeA\", \"id\", \"STRING\"),\n      constraintNodeType(\"NodeB\", \"id\", \"STRING\"),\n      constraintRelNotNull(\"boolean\"),\n      constraintRelNotNull(\"float\"),\n      constraintRelNotNull(\"int\"),\n      constraintRelType(\"boolean\", \"BOOLEAN\"),\n      constraintRelType(\"booleanArray\", \"LIST<BOOLEAN NOT NULL>\"),\n      constraintRelType(\"date\", \"DATE\"),\n      constraintRelType(\"dateArray\", \"LIST<DATE NOT NULL>\"),\n      constraintRelType(\"float\", \"FLOAT\"),\n      constraintRelType(\"floatArray\", \"LIST<FLOAT NOT NULL>\"),\n      constraintRelType(\"int\", \"INTEGER\"),\n      constraintRelType(\"intArray\", \"LIST<INTEGER NOT NULL>\"),\n      constraintRelType(\"localDateTime\", \"LOCAL DATETIME\"),\n      constraintRelType(\"localDateTimeArray\", \"LIST<LOCAL DATETIME NOT NULL>\"),\n      constraintRelType(\"string\", \"STRING\"),\n      constraintRelType(\"stringArray\", \"LIST<STRING NOT NULL>\"),\n      constraintRelType(\"zonedDateTime\", \"ZONED DATETIME\"),\n      constraintRelType(\"zonedDateTimeArray\", \"LIST<ZONED DATETIME NOT NULL>\")\n    )\n\n    val actual = SparkConnectorScalaSuiteIT.session()\n      .run(SHOW_CONSTRAINTS_QUERY)\n      .list()\n      .asScala\n      .map(_.asMap(v => v.asObject()).asScala.mapValues(mapData).toMap)\n      .toSeq\n\n    assertEquals(expected, actual)\n\n    val actualMap = SparkConnectorScalaSuiteIT.session().run(\n      \"\"\"\n        |MATCH (s:NodeA)-[r:MY_REL]->(t:NodeB)\n        |RETURN s.id AS idSource, t.id AS idTarget, r\n        |\"\"\".stripMargin\n    )\n      .list()\n      .asScala\n      .map(r =>\n        Map(\"idSource\" -> r.get(\"idSource\").asString(), \"idTarget\" -> r.get(\"idTarget\").asString()) ++ r.get(\n          \"r\"\n        ).asRelationship().asMap().asScala\n      )\n      .head\n      .mapValues(mapData)\n      .toMap\n\n    assertEquals(expectedMap, actualMap)\n  }\n\n  private def createDatasetForRelationships(options: Map[String, String]): Map[String, Any] = {\n    val shouldRemap = options.contains(Neo4jOptions.RELATIONSHIP_PROPERTIES)\n\n    SparkConnectorScalaSuiteIT.session()\n      .run(\"CREATE (:NodeA{id: 'a'}), (:NodeB{id: 'b'})\")\n      .consume()\n\n    val colNames = Array(\n      \"idSource\",\n      \"idTarget\"\n    ) ++ ALL_TYPES_AS_COL_NAMES\n\n    val row = (\n      \"a\",\n      \"b\",\n      \"Foo\",\n      1,\n      false,\n      1.1,\n      Date.valueOf(\"2023-11-22\"),\n      LocalDateTime.of(2023, 11, 22, 12, 12, 12),\n      Timestamp.valueOf(s\"2020-11-22 11:11:11.11\"),\n      Seq(\"Foo1\", \"Foo2\"),\n      Seq(1, 2),\n      Seq(true, false),\n      Seq(1.1, 2.2),\n      Seq(Date.valueOf(\"2023-11-22\"), Date.valueOf(\"2023-11-23\")),\n      Seq(LocalDateTime.of(2023, 11, 22, 11, 11, 11), LocalDateTime.of(2023, 11, 23, 12, 12, 12)),\n      Seq(Timestamp.valueOf(\"2023-11-22 11:11:11.11\"), Timestamp.valueOf(\"2023-11-23 12:12:12.12\"))\n    )\n\n    val data = Seq(row).toDF(colNames: _*)\n\n    val schema = StructType(data.schema.map { sf =>\n      sf.name match {\n        case \"localDateTimeArray\" =>\n          StructField(sf.name, DataTypes.createArrayType(DataTypes.TimestampNTZType, false), sf.nullable)\n        case \"zonedDateTimeArray\" =>\n          StructField(sf.name, DataTypes.createArrayType(DataTypes.TimestampType, false), sf.nullable)\n        case \"stringArray\" => StructField(sf.name, DataTypes.createArrayType(DataTypes.StringType, false), sf.nullable)\n        case \"dateArray\"   => StructField(sf.name, DataTypes.createArrayType(DataTypes.DateType, false), sf.nullable)\n        case \"idSource\"    => StructField(sf.name, DataTypes.StringType, false)\n        case \"idTarget\"    => StructField(sf.name, DataTypes.StringType, false)\n        case _             => sf\n      }\n    })\n\n    ss.createDataFrame(data.rdd, schema)\n      .write\n      .mode(SaveMode.Overwrite)\n      .format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"relationship\", \"MY_REL\")\n      .option(\"relationship.save.strategy\", \"keys\")\n      .option(\"relationship.source.labels\", \":NodeA\")\n      .option(\"relationship.source.save.mode\", \"Overwrite\")\n      .option(\"relationship.source.node.keys\", \"idSource:id\")\n      .option(\"relationship.target.labels\", \":NodeB\")\n      .option(\"relationship.target.node.keys\", \"idTarget:id\")\n      .option(\"relationship.target.save.mode\", \"Overwrite\")\n      .options(options)\n      .save()\n\n    colNames.map(c =>\n      if (shouldRemap && (c == \"string\" || c == \"int\")) c + \"_prop\"\n      else c\n    ).zip(row.productIterator.toSeq).toMap\n  }\n\n  final private def constraintRelNotNull(prop: String): Map[String, Any] = Map(\n    \"name\" -> s\"spark_RELATIONSHIP-NOT_NULL-CONSTRAINT-MY_REL-$prop\",\n    \"type\" -> \"RELATIONSHIP_PROPERTY_EXISTENCE\",\n    \"entityType\" -> \"RELATIONSHIP\",\n    \"labelsOrTypes\" -> Seq(\"MY_REL\"),\n    \"properties\" -> Seq(prop),\n    \"ownedIndex\" -> null,\n    \"propertyType\" -> null\n  )\n\n  final private def constraintRelType(prop: String, expectedType: String) = Map(\n    \"name\" -> s\"spark_RELATIONSHIP-TYPE-CONSTRAINT-MY_REL-$prop\",\n    \"type\" -> \"RELATIONSHIP_PROPERTY_TYPE\",\n    \"entityType\" -> \"RELATIONSHIP\",\n    \"labelsOrTypes\" -> Seq(\"MY_REL\"),\n    \"properties\" -> Seq(prop),\n    \"ownedIndex\" -> null,\n    \"propertyType\" -> expectedType\n  )\n\n  @Test\n  def shouldApplySchemaForRelationshipsAndNodesWhenRemapped(): Unit = {\n    val expectedMap = createDatasetForRelationships(\n      Map(\n        Neo4jOptions.SCHEMA_OPTIMIZATION -> schemaOptimization,\n        Neo4jOptions.RELATIONSHIP_PROPERTIES -> ALL_TYPES_AS_COL_NAMES.map {\n          case \"string\" => \"string:string_prop\"\n          case \"int\"    => \"int:int_prop\"\n          case c        => c\n        }.mkString(\",\")\n      )\n    )\n\n    val count: Long = SparkConnectorScalaSuiteIT.session().run(\n      \"\"\"\n        |MATCH p = (:NodeA)-[:MY_REL]->(:NodeB)\n        |RETURN count(p)\n        |\"\"\".stripMargin\n    )\n      .single()\n      .get(0)\n      .asLong()\n\n    assertEquals(1L, count)\n\n    val expected = Seq(\n      constraintNodeNotNull(\"NodeA\", \"id\"),\n      constraintNodeNotNull(\"NodeB\", \"id\"),\n      constraintNodeType(\"NodeA\", \"id\", \"STRING\"),\n      constraintNodeType(\"NodeB\", \"id\", \"STRING\"),\n      constraintRelNotNull(\"boolean\"),\n      constraintRelNotNull(\"float\"),\n      constraintRelNotNull(\"int_prop\"),\n      constraintRelType(\"boolean\", \"BOOLEAN\"),\n      constraintRelType(\"booleanArray\", \"LIST<BOOLEAN NOT NULL>\"),\n      constraintRelType(\"date\", \"DATE\"),\n      constraintRelType(\"dateArray\", \"LIST<DATE NOT NULL>\"),\n      constraintRelType(\"float\", \"FLOAT\"),\n      constraintRelType(\"floatArray\", \"LIST<FLOAT NOT NULL>\"),\n      constraintRelType(\"intArray\", \"LIST<INTEGER NOT NULL>\"),\n      constraintRelType(\"int_prop\", \"INTEGER\"),\n      constraintRelType(\"localDateTime\", \"LOCAL DATETIME\"),\n      constraintRelType(\"localDateTimeArray\", \"LIST<LOCAL DATETIME NOT NULL>\"),\n      constraintRelType(\"stringArray\", \"LIST<STRING NOT NULL>\"),\n      constraintRelType(\"string_prop\", \"STRING\"),\n      constraintRelType(\"zonedDateTime\", \"ZONED DATETIME\"),\n      constraintRelType(\"zonedDateTimeArray\", \"LIST<ZONED DATETIME NOT NULL>\")\n    )\n\n    val actual = SparkConnectorScalaSuiteIT.session()\n      .run(SHOW_CONSTRAINTS_QUERY)\n      .list()\n      .asScala\n      .map(_.asMap(v => v.asObject()).asScala.mapValues(mapData).toMap)\n      .toSeq\n\n    assertEquals(expected, actual)\n\n    val actualMap = SparkConnectorScalaSuiteIT.session().run(\n      \"\"\"\n        |MATCH (s:NodeA)-[r:MY_REL]->(t:NodeB)\n        |RETURN s.id AS idSource, t.id AS idTarget, r\n        |\"\"\".stripMargin\n    )\n      .list()\n      .asScala\n      .map(r =>\n        Map(\"idSource\" -> r.get(\"idSource\").asString(), \"idTarget\" -> r.get(\"idTarget\").asString()) ++ r.get(\n          \"r\"\n        ).asRelationship().asMap().asScala\n      )\n      .head\n      .mapValues(mapData)\n      .toMap\n\n    assertEquals(expectedMap, actualMap)\n  }\n\n  @Test\n  def shouldApplyUniqueConstraintForNode(): Unit = {\n    val total = 10\n    val ds = (1 to total)\n      .map(i => i.toString)\n      .toDF(\"surname\")\n\n    ds.write\n      .format(classOf[DataSource].getName)\n      .mode(SaveMode.Overwrite)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"labels\", \":Person:Customer\")\n      .option(\"node.keys\", \"surname\")\n      .option(Neo4jOptions.SCHEMA_OPTIMIZATION_NODE_KEY, ConstraintsOptimizationType.UNIQUE.toString)\n      .save()\n\n    val records = SparkConnectorScalaSuiteIT.session().run(\n      \"\"\"MATCH (p:Person:Customer)\n        |RETURN p.surname AS surname\n        |\"\"\".stripMargin\n    ).list().asScala\n      .map(r => r.asMap().asScala)\n      .toSet\n    val expected = ds.collect().map(row => Map(\"surname\" -> row.getAs[String](\"surname\")))\n      .toSet\n    assertEquals(expected, records)\n\n    val actualConstraint = SparkConnectorScalaSuiteIT.session().run(NODE_UNIQUENESS_SHOW_CONSTRAINTS_QUERY)\n      .list()\n      .asScala\n      .map(_.asMap(v => v.asObject()).asScala.mapValues(mapData).toMap)\n      .head\n    val expectedConstraint = Map(\n      \"name\" -> \"spark_NODE_UNIQUE-CONSTRAINT_Person_surname\",\n      \"type\" -> \"NODE_PROPERTY_UNIQUENESS\",\n      \"entityType\" -> \"NODE\",\n      \"labelsOrTypes\" -> Seq(\"Person\"),\n      \"properties\" -> Seq(\"surname\"),\n      \"ownedIndex\" -> \"spark_NODE_UNIQUE-CONSTRAINT_Person_surname\",\n      \"propertyType\" -> null\n    )\n    assertEquals(expectedConstraint, actualConstraint)\n\n    SparkConnectorScalaSuiteIT.session().run(\"DROP CONSTRAINT `spark_NODE_UNIQUE-CONSTRAINT_Person_surname`\").consume()\n  }\n\n  @Test\n  def shouldApplyNodeKeyConstraintForNode(): Unit = {\n    val total = 10\n    val ds = (1 to total)\n      .map(i => i.toString)\n      .toDF(\"surname\")\n\n    ds.write\n      .format(classOf[DataSource].getName)\n      .mode(SaveMode.Overwrite)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"labels\", \":Person:Customer\")\n      .option(\"node.keys\", \"surname\")\n      .option(Neo4jOptions.SCHEMA_OPTIMIZATION_NODE_KEY, ConstraintsOptimizationType.KEY.toString)\n      .save()\n\n    val records = SparkConnectorScalaSuiteIT.session().run(\n      \"\"\"MATCH (p:Person:Customer)\n        |RETURN p.surname AS surname\n        |\"\"\".stripMargin\n    ).list().asScala\n      .map(r => r.asMap().asScala)\n      .toSet\n    val expected = ds.collect().map(row => Map(\"surname\" -> row.getAs[String](\"surname\")))\n      .toSet\n    assertEquals(expected, records)\n\n    val actualConstraint = SparkConnectorScalaSuiteIT.session().run(SHOW_CONSTRAINTS_QUERY)\n      .list()\n      .asScala\n      .map(_.asMap(v => v.asObject()).asScala.mapValues(mapData).toMap)\n      .head\n    val expectedConstraint = Map(\n      \"name\" -> \"spark_NODE_KEY-CONSTRAINT_Person_surname\",\n      \"type\" -> \"NODE_KEY\",\n      \"entityType\" -> \"NODE\",\n      \"labelsOrTypes\" -> Seq(\"Person\"),\n      \"properties\" -> Seq(\"surname\"),\n      \"ownedIndex\" -> \"spark_NODE_KEY-CONSTRAINT_Person_surname\",\n      \"propertyType\" -> null\n    )\n    assertEquals(expectedConstraint, actualConstraint)\n\n    SparkConnectorScalaSuiteIT.session().run(\"DROP CONSTRAINT `spark_NODE_KEY-CONSTRAINT_Person_surname`\").consume()\n  }\n\n  @Test\n  def shouldApplyAppropriateConstraintsEvenWhenRemapped(): Unit = {\n    val total = 10\n    val ds = (1 to total)\n      .map(i => i.toString)\n      .toDF(\"surname\")\n\n    ds.write\n      .format(classOf[DataSource].getName)\n      .mode(SaveMode.Overwrite)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"labels\", \":SurnameKey\")\n      .option(\"node.keys\", \"surname:surname_key\")\n      .option(Neo4jOptions.SCHEMA_OPTIMIZATION_NODE_KEY, ConstraintsOptimizationType.KEY.toString)\n      .save()\n\n    ds.write\n      .format(classOf[DataSource].getName)\n      .mode(SaveMode.Overwrite)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"labels\", \":SurnameUnique\")\n      .option(\"node.keys\", \"surname:surname_unique\")\n      .option(Neo4jOptions.SCHEMA_OPTIMIZATION_NODE_KEY, ConstraintsOptimizationType.UNIQUE.toString)\n      .save()\n\n    val actualConstraint = SparkConnectorScalaSuiteIT.session().run(NODE_UNIQUENESS_SHOW_CONSTRAINTS_QUERY)\n      .list()\n      .asScala\n      .map(_.asMap(v => v.asObject()).asScala.mapValues(mapData).toMap)\n      .toSeq\n\n    val expectedConstraint = Seq(\n      Map(\n        \"name\" -> \"spark_NODE_KEY-CONSTRAINT_SurnameKey_surname_key\",\n        \"type\" -> \"NODE_KEY\",\n        \"entityType\" -> \"NODE\",\n        \"labelsOrTypes\" -> Seq(\"SurnameKey\"),\n        \"properties\" -> Seq(\"surname_key\"),\n        \"ownedIndex\" -> \"spark_NODE_KEY-CONSTRAINT_SurnameKey_surname_key\",\n        \"propertyType\" -> null\n      ),\n      Map(\n        \"name\" -> \"spark_NODE_UNIQUE-CONSTRAINT_SurnameUnique_surname_unique\",\n        \"type\" -> \"NODE_PROPERTY_UNIQUENESS\",\n        \"entityType\" -> \"NODE\",\n        \"labelsOrTypes\" -> Seq(\"SurnameUnique\"),\n        \"properties\" -> Seq(\"surname_unique\"),\n        \"ownedIndex\" -> \"spark_NODE_UNIQUE-CONSTRAINT_SurnameUnique_surname_unique\",\n        \"propertyType\" -> null\n      )\n    )\n\n    assertEquals(expectedConstraint, actualConstraint)\n\n    SparkConnectorScalaSuiteIT.session().run(\n      \"DROP CONSTRAINT `spark_NODE_KEY-CONSTRAINT_SurnameKey_surname_key`\"\n    ).consume()\n    SparkConnectorScalaSuiteIT.session().run(\n      \"DROP CONSTRAINT `spark_NODE_UNIQUE-CONSTRAINT_SurnameUnique_surname_unique`\"\n    ).consume()\n  }\n\n  @Test\n  def shouldApplyUniqueConstraintForRelationship(): Unit = {\n    val expectedMap = createDatasetForRelationships(\n      Map(\n        Neo4jOptions.SCHEMA_OPTIMIZATION_RELATIONSHIP_KEY -> ConstraintsOptimizationType.UNIQUE.toString,\n        \"relationship.keys\" -> \"string,int\"\n      )\n    )\n    val actualMap = SparkConnectorScalaSuiteIT.session().run(\n      \"\"\"\n        |MATCH (s:NodeA)-[r:MY_REL]->(t:NodeB)\n        |RETURN s.id AS idSource, t.id AS idTarget, r\n        |\"\"\".stripMargin\n    )\n      .list()\n      .asScala\n      .map(r =>\n        Map(\"idSource\" -> r.get(\"idSource\").asString(), \"idTarget\" -> r.get(\"idTarget\").asString()) ++ r.get(\n          \"r\"\n        ).asRelationship().asMap().asScala\n      )\n      .head\n      .mapValues(mapData)\n      .toMap\n\n    assertEquals(expectedMap, actualMap)\n\n    val actualConstraint = SparkConnectorScalaSuiteIT.session().run(RELATIONSHIP_UNIQUENESS_SHOW_CONSTRAINTS_QUERY)\n      .list()\n      .asScala\n      .map(_.asMap(v => v.asObject()).asScala.mapValues(mapData).toMap)\n      .head\n    val expectedConstraint = Map(\n      \"name\" -> \"spark_RELATIONSHIP_UNIQUE-CONSTRAINT_MY_REL_string-int\",\n      \"type\" -> \"RELATIONSHIP_PROPERTY_UNIQUENESS\",\n      \"entityType\" -> \"RELATIONSHIP\",\n      \"labelsOrTypes\" -> Seq(\"MY_REL\"),\n      \"properties\" -> Seq(\"string\", \"int\"),\n      \"ownedIndex\" -> \"spark_RELATIONSHIP_UNIQUE-CONSTRAINT_MY_REL_string-int\",\n      \"propertyType\" -> null\n    )\n    assertEquals(expectedConstraint, actualConstraint)\n  }\n\n  @Test\n  def shouldApplyRelUniqueConstraintForRelationship(): Unit = {\n    val expectedMap = createDatasetForRelationships(\n      Map(\n        Neo4jOptions.SCHEMA_OPTIMIZATION_RELATIONSHIP_KEY -> ConstraintsOptimizationType.KEY.toString,\n        \"relationship.keys\" -> \"string,int\"\n      )\n    )\n\n    val actualMap = SparkConnectorScalaSuiteIT.session().run(\n      \"\"\"\n        |MATCH (s:NodeA)-[r:MY_REL]->(t:NodeB)\n        |RETURN s.id AS idSource, t.id AS idTarget, r\n        |\"\"\".stripMargin\n    )\n      .list()\n      .asScala\n      .map(r =>\n        Map(\"idSource\" -> r.get(\"idSource\").asString(), \"idTarget\" -> r.get(\"idTarget\").asString()) ++ r.get(\n          \"r\"\n        ).asRelationship().asMap().asScala\n      )\n      .head\n      .mapValues(mapData)\n      .toMap\n\n    assertEquals(expectedMap, actualMap)\n\n    val actualConstraint = SparkConnectorScalaSuiteIT.session().run(SHOW_CONSTRAINTS_QUERY)\n      .list()\n      .asScala\n      .map(_.asMap(v => v.asObject()).asScala.mapValues(mapData).toMap)\n      .head\n    val expectedConstraint = Map(\n      \"name\" -> \"spark_RELATIONSHIP_KEY-CONSTRAINT_MY_REL_string-int\",\n      \"type\" -> \"RELATIONSHIP_KEY\",\n      \"entityType\" -> \"RELATIONSHIP\",\n      \"labelsOrTypes\" -> Seq(\"MY_REL\"),\n      \"properties\" -> Seq(\"string\", \"int\"),\n      \"ownedIndex\" -> \"spark_RELATIONSHIP_KEY-CONSTRAINT_MY_REL_string-int\",\n      \"propertyType\" -> null\n    )\n\n    assertEquals(expectedConstraint, actualConstraint)\n  }\n\n  @Test\n  def shouldWriteNodeWithLegacyTypeConversionDisabledByDefault(): Unit = {\n    val df = sparkSession.sql(\n      \"\"\"\n        |SELECT\n        |  'legacy-type-conversion' AS id,\n        |  timestamp('2025-01-01 11:11:11') AS timestamp,\n        |  CAST('2025-01-01 11:11:11' AS TIMESTAMP_NTZ) AS timestampNtz,\n        |  INTERVAL '4' DAY AS dayInterval,\n        |  INTERVAL '10 05' DAY TO HOUR AS dayToHour,\n        |  timestamp('2025-01-02 18:30:00.454') - timestamp('2024-01-01 00:00:00') AS arithmeticDuration,\n        |  INTERVAL '3' YEAR AS yearInterval,\n        |  INTERVAL '1-2' YEAR TO MONTH AS yearToMonth,\n        |  CAST('erik' AS BINARY) AS binary,\n        |  CAST(array(1, 2, 3) AS array<tinyint>) AS byteArray\n        |\"\"\".stripMargin\n    )\n    assertTrue(df.schema(\"dayInterval\").dataType.isInstanceOf[DayTimeIntervalType])\n    assertTrue(df.schema(\"dayToHour\").dataType.isInstanceOf[DayTimeIntervalType])\n    assertTrue(df.schema(\"arithmeticDuration\").dataType.isInstanceOf[DayTimeIntervalType])\n    assertTrue(df.schema(\"yearInterval\").dataType.isInstanceOf[YearMonthIntervalType])\n    assertTrue(df.schema(\"yearToMonth\").dataType.isInstanceOf[YearMonthIntervalType])\n\n    df.write\n      .mode(SaveMode.Overwrite)\n      .format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"labels\", \":LegacyTypeConversionDisabled\")\n      .option(\"node.keys\", \"id\")\n      .save()\n\n    val actual = SparkConnectorScalaSuiteIT.session().run(\n      \"\"\"\n        |MATCH (n:LegacyTypeConversionDisabled {id: 'legacy-type-conversion'})\n        |RETURN n\n        |\"\"\".stripMargin\n    )\n      .single()\n      .get(\"n\")\n      .asNode()\n      .asMap()\n      .asScala\n      .toMap\n    assertEquals(\n      Set(\n        \"id\",\n        \"timestamp\",\n        \"timestampNtz\",\n        \"dayInterval\",\n        \"dayToHour\",\n        \"arithmeticDuration\",\n        \"yearInterval\",\n        \"yearToMonth\",\n        \"binary\",\n        \"byteArray\"\n      ),\n      actual.keySet\n    )\n    assertEquals(\"legacy-type-conversion\", actual(\"id\"))\n    val expectedZoned = ZonedDateTime.of(2025, 1, 1, 11, 11, 11, 0, ZoneOffset.UTC)\n    assertEquals(expectedZoned, actual(\"timestamp\"))\n    val expectedNtz = LocalDateTime.of(2025, 1, 1, 11, 11, 11)\n    assertEquals(expectedNtz, actual(\"timestampNtz\"))\n    val dayInterval = actual(\"dayInterval\").asInstanceOf[IsoDuration]\n    assertEquals(0L, dayInterval.months())\n    assertEquals(4L, dayInterval.days())\n    assertEquals(0L, dayInterval.seconds())\n    assertEquals(0, dayInterval.nanoseconds())\n    val dayToHour = actual(\"dayToHour\").asInstanceOf[IsoDuration]\n    assertEquals(0L, dayToHour.months())\n    assertEquals(10L, dayToHour.days())\n    assertEquals(18000L, dayToHour.seconds())\n    assertEquals(0, dayToHour.nanoseconds())\n    val arithmetic = actual(\"arithmeticDuration\").asInstanceOf[IsoDuration]\n    assertEquals(0L, arithmetic.months())\n    assertEquals(367L, arithmetic.days())\n    assertEquals(66600L, arithmetic.seconds())\n    assertEquals(454000000, arithmetic.nanoseconds())\n    val yearInterval = actual(\"yearInterval\").asInstanceOf[IsoDuration]\n    assertEquals(36L, yearInterval.months())\n    assertEquals(0L, yearInterval.days())\n    assertEquals(0L, yearInterval.seconds())\n    assertEquals(0, yearInterval.nanoseconds())\n    val yearToMonth = actual(\"yearToMonth\").asInstanceOf[IsoDuration]\n    assertEquals(14L, yearToMonth.months())\n    assertEquals(0L, yearToMonth.days())\n    assertEquals(0L, yearToMonth.seconds())\n    assertEquals(0, yearToMonth.nanoseconds())\n    assertArrayEquals(Array[Byte](101, 114, 105, 107), actual(\"binary\").asInstanceOf[Array[Byte]])\n    assertArrayEquals(Array[Byte](1, 2, 3), actual(\"byteArray\").asInstanceOf[Array[Byte]])\n  }\n\n  @Test\n  def shouldWriteNodeWithLegacyTypeConversionEnabled(): Unit = {\n    val df = sparkSession.sql(\n      \"\"\"\n        |SELECT\n        |  'legacy-type-conversion' AS id,\n        |  timestamp('2025-01-01 11:11:11') AS timestamp,\n        |  CAST('2025-01-01 11:11:11' AS TIMESTAMP_NTZ) AS timestampNtz,\n        |  INTERVAL '4' DAY AS dayInterval,\n        |  INTERVAL '10 05' DAY TO HOUR AS dayToHour,\n        |  timestamp('2025-01-02 18:30:00.454') - timestamp('2024-01-01 00:00:00') AS arithmeticDuration,\n        |  INTERVAL '3' YEAR AS yearInterval,\n        |  INTERVAL '1-2' YEAR TO MONTH AS yearToMonth,\n        |  CAST('erik' AS BINARY) AS binary,\n        |  CAST(array(1, 2, 3) AS array<tinyint>) AS byteArray\n        |\"\"\".stripMargin\n    )\n    assertTrue(df.schema(\"dayInterval\").dataType.isInstanceOf[DayTimeIntervalType])\n    assertTrue(df.schema(\"dayToHour\").dataType.isInstanceOf[DayTimeIntervalType])\n    assertTrue(df.schema(\"arithmeticDuration\").dataType.isInstanceOf[DayTimeIntervalType])\n    assertTrue(df.schema(\"yearInterval\").dataType.isInstanceOf[YearMonthIntervalType])\n    assertTrue(df.schema(\"yearToMonth\").dataType.isInstanceOf[YearMonthIntervalType])\n\n    df.write\n      .mode(SaveMode.Overwrite)\n      .format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"labels\", \":LegacyTypeConversionEnabled\")\n      .option(\"node.keys\", \"id\")\n      .option(Neo4jOptions.TYPE_CONVERSION, \"legacy\")\n      .save()\n\n    val actual = SparkConnectorScalaSuiteIT.session().run(\n      \"\"\"\n        |MATCH (n:LegacyTypeConversionEnabled {id: 'legacy-type-conversion'})\n        |RETURN n\n        |\"\"\".stripMargin\n    )\n      .single()\n      .get(\"n\")\n      .asNode()\n      .asMap()\n      .asScala\n      .toMap\n    assertEquals(\n      Set(\n        \"id\",\n        \"timestamp\",\n        \"timestampNtz\",\n        \"dayInterval\",\n        \"dayToHour\",\n        \"arithmeticDuration\",\n        \"yearInterval\",\n        \"yearToMonth\",\n        \"binary\",\n        \"byteArray\"\n      ),\n      actual.keySet\n    )\n    assertEquals(\"legacy-type-conversion\", actual(\"id\"))\n    val expectedTimestamp = ZonedDateTime.of(2025, 1, 1, 11, 11, 11, 0, ZoneOffset.UTC)\n      .withZoneSameInstant(ZoneId.systemDefault())\n      .toLocalDateTime\n    assertEquals(expectedTimestamp, actual(\"timestamp\"))\n    assertEquals(\n      DateTimeUtils.localDateTimeToMicros(LocalDateTime.of(2025, 1, 1, 11, 11, 11)),\n      actual(\"timestampNtz\").asInstanceOf[java.lang.Number].longValue()\n    )\n    assertEquals(4L * 24L * 3600L * 1000000L, actual(\"dayInterval\").asInstanceOf[java.lang.Number].longValue())\n    assertEquals((10L * 24L + 5L) * 3600L * 1000000L, actual(\"dayToHour\").asInstanceOf[java.lang.Number].longValue())\n    assertEquals(\n      (367L * 24L * 3600L + 66600L) * 1000000L + 454000L,\n      actual(\"arithmeticDuration\").asInstanceOf[java.lang.Number].longValue()\n    )\n    assertEquals(36L, actual(\"yearInterval\").asInstanceOf[java.lang.Number].longValue())\n    assertEquals(14L, actual(\"yearToMonth\").asInstanceOf[java.lang.Number].longValue())\n    assertArrayEquals(Array[Byte](101, 114, 105, 107), actual(\"binary\").asInstanceOf[Array[Byte]])\n    val byteArray = actual(\"byteArray\").asInstanceOf[java.util.List[_]].asScala\n      .map(_.asInstanceOf[java.lang.Number].longValue())\n    assertEquals(Seq(1L, 2L, 3L), byteArray)\n  }\n}\n"
  },
  {
    "path": "spark-3/src/test/scala/org/neo4j/spark/DataSourceStreamingReaderTSE.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark\n\nimport org.apache.spark.sql.Row\nimport org.apache.spark.sql.streaming.StreamingQuery\nimport org.apache.spark.sql.streaming.Trigger\nimport org.hamcrest.Matchers\nimport org.junit.After\nimport org.junit.Assert.assertEquals\nimport org.junit.Assert.assertTrue\nimport org.junit.Rule\nimport org.junit.Test\nimport org.junit.rules.TemporaryFolder\nimport org.neo4j.Closeables.use\nimport org.neo4j.spark.SparkConnectorScalaSuiteIT.session\n\nimport java.util.concurrent.Executors\nimport java.util.concurrent.TimeUnit\n\nimport scala.annotation.meta.getter\n\nclass DataSourceStreamingReaderTSE extends SparkConnectorScalaBaseTSE {\n\n  @(Rule @getter)\n  val folder: TemporaryFolder = new TemporaryFolder()\n\n  private var query: StreamingQuery = _\n\n  @After\n  def close(): Unit = {\n    if (query != null) {\n      query.stop()\n    }\n  }\n\n  @Test\n  def testReadStreamWithLabels(): Unit = {\n    createMovieNodes(0, 1)\n\n    val stream = ss.readStream.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"labels\", \"Movie\")\n      .option(\"streaming.property.name\", \"timestamp\")\n      .option(\"streaming.from\", \"NOW\")\n      .load()\n\n    query = stream.writeStream\n      .format(\"memory\")\n      .queryName(\"readStreamWithLabels\")\n      .start()\n\n    val total = 60\n    val expected: Seq[Map[String, Any]] = (1 to total).map(index =>\n      Map(\n        \"<labels>\" -> Seq(\"Movie\"),\n        \"title\" -> s\"My movie $index\"\n      )\n    )\n\n    // Continue creating nodes in the background\n    Executors.newSingleThreadExecutor().submit(new Runnable {\n      override def run(): Unit = {\n        createMovieNodes(1, total, 1000, 200)\n      }\n    })\n\n    Assert.assertEventually(\n      new Assert.ThrowingSupplier[Seq[Map[String, Any]], Exception] {\n        override def get(): Seq[Map[String, Any]] = {\n          selectRowsFromTable(\"select * from readStreamWithLabels order by timestamp\", mapMovie)\n        }\n      },\n      Matchers.equalTo(expected),\n      30L,\n      TimeUnit.SECONDS\n    )\n  }\n\n  @Test\n  def testReadStreamWithLabelsGetAll(): Unit = {\n    createMovieNodes(0, 1)\n\n    val stream = ss.readStream.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"labels\", \"Movie\")\n      .option(\"streaming.property.name\", \"timestamp\")\n      .option(\"streaming.from\", \"ALL\")\n      .load()\n\n    query = stream.writeStream\n      .format(\"memory\")\n      .queryName(\"readStreamWithLabelsAll\")\n      .start()\n\n    val total = 60\n    Executors.newSingleThreadExecutor().submit(new Runnable {\n      override def run(): Unit = {\n        createMovieNodes(1, total, 1000, 200)\n      }\n    })\n\n    val expected: Seq[Map[String, Any]] = (0 to total).map(index =>\n      Map(\n        \"<labels>\" -> Seq(\"Movie\"),\n        \"title\" -> s\"My movie $index\"\n      )\n    )\n\n    Assert.assertEventually(\n      new Assert.ThrowingSupplier[Seq[Map[String, Any]], Exception] {\n        override def get(): Seq[Map[String, Any]] = {\n          selectRowsFromTable(\"select * from readStreamWithLabelsAll order by timestamp\", mapMovie)\n        }\n      },\n      Matchers.equalTo(expected),\n      30L,\n      TimeUnit.SECONDS\n    )\n  }\n\n  @Test\n  def testReadStreamWithLabelsResumesFromCheckpoint(): Unit = {\n    createMovieNodes(0, 1)\n\n    val stream = ss.readStream.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"labels\", \"Movie\")\n      .option(\"streaming.property.name\", \"timestamp\")\n      .option(\"streaming.from\", \"NOW\")\n      .load()\n\n    val total = 60\n    val expected: Seq[Map[String, Any]] = (1 to total).map(index =>\n      Map(\n        \"<labels>\" -> List(\"Movie\"),\n        \"title\" -> s\"My movie $index\"\n      )\n    )\n\n    val checkpoint = folder.newFolder()\n\n    stream.writeStream\n      .trigger(Trigger.AvailableNow())\n      .option(\"checkpointLocation\", checkpoint.getAbsolutePath)\n      .toTable(\"readStreamWithLabelsCheckpoint\")\n      .awaitTermination()\n\n    val partial: Int = total / 2\n    // create partial movies starting from 1\n    createMovieNodes(1, partial, 0, 10)\n\n    // fetch whatever is available\n    stream.writeStream\n      .trigger(Trigger.AvailableNow())\n      .option(\"checkpointLocation\", checkpoint.getAbsolutePath)\n      .toTable(\"readStreamWithLabelsCheckpoint\")\n      .awaitTermination()\n\n    // create rest of the movies starting from partial+1\n    createMovieNodes(partial + 1, total - partial, 0, 10)\n\n    // fetch rest of the items from where we left off\n    stream.writeStream\n      .trigger(Trigger.AvailableNow())\n      .option(\"checkpointLocation\", checkpoint.getAbsolutePath)\n      .toTable(\"readStreamWithLabelsCheckpoint\")\n      .awaitTermination()\n\n    assertEquals(\n      expected,\n      selectRowsFromTable(\"select * from readStreamWithLabelsCheckpoint order by timestamp\", mapMovie)\n    )\n  }\n\n  @Test\n  def testReadStreamWithRelationship(): Unit = {\n    createLikesRelationships(0, 1)\n\n    val stream = ss.readStream.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"relationship\", \"LIKES\")\n      .option(\"streaming.property.name\", \"timestamp\")\n      .option(\"streaming.from\", \"NOW\")\n      .option(\"relationship.source.labels\", \"Person\")\n      .option(\"relationship.target.labels\", \"Post\")\n      .load()\n\n    query = stream.writeStream\n      .format(\"memory\")\n      .queryName(\"readStreamWithRelationship\")\n      .start()\n\n    val total = 60\n\n    val expected: Seq[Map[String, Any]] = (1 to total).map(index =>\n      Map(\n        \"<rel.type>\" -> \"LIKES\",\n        \"<source.labels>\" -> Seq(\"Person\"),\n        \"source.age\" -> index,\n        \"<target.labels>\" -> Seq(\"Post\"),\n        \"target.hash\" -> s\"hash$index\",\n        \"rel.id\" -> index\n      )\n    )\n\n    Executors.newSingleThreadExecutor().submit(new Runnable {\n      override def run(): Unit = {\n        createLikesRelationships(1, total, 1000, 200)\n      }\n    })\n\n    Assert.assertEventually(\n      new Assert.ThrowingSupplier[Seq[Map[String, Any]], Exception] {\n        override def get(): Seq[Map[String, Any]] = {\n          selectRowsFromTable(\"select * from readStreamWithRelationship order by `rel.timestamp`\", mapLikes)\n        }\n      },\n      Matchers.equalTo(expected),\n      30L,\n      TimeUnit.SECONDS\n    )\n  }\n\n  @Test\n  def testReadStreamWithRelationshipGetAll(): Unit = {\n    createLikesRelationships(0, 1)\n\n    val stream = ss.readStream.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"relationship\", \"LIKES\")\n      .option(\"streaming.property.name\", \"timestamp\")\n      .option(\"streaming.from\", \"ALL\")\n      .option(\"relationship.source.labels\", \"Person\")\n      .option(\"relationship.target.labels\", \"Post\")\n      .load()\n\n    query = stream.writeStream\n      .format(\"memory\")\n      .queryName(\"readStreamWithRelationshipAll\")\n      .start()\n\n    val total = 60\n    val expected: Seq[Map[String, Any]] = (0 to total).map(index =>\n      Map(\n        \"<rel.type>\" -> \"LIKES\",\n        \"<source.labels>\" -> Seq(\"Person\"),\n        \"source.age\" -> index,\n        \"<target.labels>\" -> Seq(\"Post\"),\n        \"target.hash\" -> s\"hash$index\",\n        \"rel.id\" -> index\n      )\n    )\n\n    Executors.newSingleThreadExecutor().submit(new Runnable {\n      override def run(): Unit = {\n        createLikesRelationships(1, total, 1000, 200)\n      }\n    })\n\n    Assert.assertEventually(\n      new Assert.ThrowingSupplier[Seq[Map[String, Any]], Exception] {\n        override def get(): Seq[Map[String, Any]] = {\n          selectRowsFromTable(\"select * from readStreamWithRelationshipAll order by `rel.timestamp`\", mapLikes)\n        }\n      },\n      Matchers.equalTo(expected),\n      30L,\n      TimeUnit.SECONDS\n    )\n  }\n\n  @Test\n  def testReadStreamWithRelationshipResumesFromCheckpoint(): Unit = {\n    createLikesRelationships(0, 1)\n\n    val stream = ss.readStream.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"relationship\", \"LIKES\")\n      .option(\"streaming.property.name\", \"timestamp\")\n      .option(\"streaming.from\", \"ALL\")\n      .option(\"relationship.source.labels\", \"Person\")\n      .option(\"relationship.target.labels\", \"Post\")\n      .load()\n\n    val total = 60\n    val expected: Seq[Map[String, Any]] = (0 to total).map(index =>\n      Map(\n        \"<rel.type>\" -> \"LIKES\",\n        \"<source.labels>\" -> Seq(\"Person\"),\n        \"source.age\" -> index,\n        \"<target.labels>\" -> Seq(\"Post\"),\n        \"target.hash\" -> s\"hash$index\",\n        \"rel.id\" -> index\n      )\n    )\n\n    val checkpoint = folder.newFolder()\n\n    stream.writeStream\n      .trigger(Trigger.AvailableNow())\n      .option(\"checkpointLocation\", checkpoint.getAbsolutePath)\n      .toTable(\"readStreamWithRelationshipCheckpoint\")\n      .awaitTermination()\n\n    val partial: Int = total / 2\n    // create partial number of likes starting from 1\n    createLikesRelationships(1, partial, 0, 10)\n\n    // fetch whatever is available\n    stream.writeStream\n      .trigger(Trigger.AvailableNow())\n      .option(\"checkpointLocation\", checkpoint.getAbsolutePath)\n      .toTable(\"readStreamWithRelationshipCheckpoint\")\n      .awaitTermination()\n\n    // create rest of the likes starting from partial+1\n    createLikesRelationships(partial + 1, total - partial, 0, 10)\n\n    // fetch rest of the items from where we left off\n    stream.writeStream\n      .trigger(Trigger.AvailableNow())\n      .option(\"checkpointLocation\", checkpoint.getAbsolutePath)\n      .toTable(\"readStreamWithRelationshipCheckpoint\")\n      .awaitTermination()\n\n    assertEquals(\n      expected,\n      selectRowsFromTable(\"select * from readStreamWithRelationshipCheckpoint order by `rel.timestamp`\", mapLikes)\n    )\n  }\n\n  @Test\n  def testReadStreamWithQuery(): Unit = {\n    createPersonNodes(0, 1)\n\n    val stream = ss.readStream.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"streaming.from\", \"NOW\")\n      .option(\"streaming.property.name\", \"timestamp\")\n      .option(\n        \"query\",\n        \"\"\"\n          |MATCH (p:Person)\n          |WHERE p.timestamp > $stream.offset\n          |RETURN p.age AS age, p.timestamp AS timestamp\n          |\"\"\".stripMargin\n      )\n      .option(\n        \"streaming.query.offset\",\n        \"\"\"\n          |MATCH (p:Person)\n          |RETURN max(p.timestamp)\n          |\"\"\".stripMargin\n      )\n      .load()\n\n    query = stream.writeStream\n      .format(\"memory\")\n      .queryName(\"readStreamWithQuery\")\n      .start()\n\n    val total = 60\n    val expected: Seq[Map[String, Any]] = (1 to total).map(index =>\n      Map(\n        \"age\" -> s\"$index\"\n      )\n    )\n\n    Executors.newSingleThreadExecutor().submit(new Runnable {\n      override def run(): Unit = {\n        createPersonNodes(1, total, 1000, 200)\n      }\n    })\n\n    Assert.assertEventually(\n      new Assert.ThrowingSupplier[Seq[Map[String, Any]], Exception] {\n        override def get(): Seq[Map[String, Any]] = {\n          selectRowsFromTable(\"select * from readStreamWithQuery order by timestamp\", mapPerson)\n        }\n      },\n      Matchers.equalTo(expected),\n      30L,\n      TimeUnit.SECONDS\n    )\n  }\n\n  @Test\n  def testReadStreamWithQueryGetAll(): Unit = {\n    createPersonNodes(0, 1)\n\n    val stream = ss.readStream.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"streaming.property.name\", \"timestamp\")\n      .option(\"streaming.from\", \"ALL\")\n      .option(\n        \"query\",\n        \"\"\"\n          |MATCH (p:Person)\n          |WHERE p.timestamp > $stream.offset\n          |RETURN p.age AS age, p.timestamp AS timestamp\n          |\"\"\".stripMargin\n      )\n      .option(\n        \"streaming.query.offset\",\n        \"\"\"\n          |MATCH (p:Person)\n          |RETURN max(p.timestamp)\n          |\"\"\".stripMargin\n      )\n      .load()\n\n    query = stream.writeStream\n      .format(\"memory\")\n      .queryName(\"readStreamWithQueryAll\")\n      .start()\n\n    val total = 60\n    val expected: Seq[Map[String, Any]] = (0 to total).map(index =>\n      Map(\n        \"age\" -> s\"$index\"\n      )\n    ).toList\n\n    Executors.newSingleThreadExecutor().submit(new Runnable {\n      override def run(): Unit = {\n        createPersonNodes(1, total, 1000, 200)\n      }\n    })\n\n    Assert.assertEventually(\n      new Assert.ThrowingSupplier[Seq[Map[String, Any]], Exception] {\n        override def get(): Seq[Map[String, Any]] = {\n          selectRowsFromTable(\"select * from readStreamWithQueryAll order by timestamp\", mapPerson)\n        }\n      },\n      Matchers.equalTo(expected),\n      30L,\n      TimeUnit.SECONDS\n    )\n  }\n\n  @Test\n  def testReadStreamWithQueryResumesFromCheckpoint(): Unit = {\n    createPersonNodes(0, 1)\n\n    val stream = ss.readStream.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"streaming.property.name\", \"timestamp\")\n      .option(\"streaming.from\", \"ALL\")\n      .option(\n        \"query\",\n        \"\"\"\n          |MATCH (p:Person)\n          |WHERE p.timestamp > $stream.offset\n          |RETURN p.age AS age, p.timestamp AS timestamp\n          |\"\"\".stripMargin\n      )\n      .option(\n        \"streaming.query.offset\",\n        \"\"\"\n          |MATCH (p:Person)\n          |RETURN max(p.timestamp)\n          |\"\"\".stripMargin\n      )\n      .load()\n\n    val total = 60\n    val expected: Seq[Map[String, Any]] = (0 to total).map(index =>\n      Map(\n        \"age\" -> s\"$index\"\n      )\n    ).toList\n\n    val checkpoint = folder.newFolder()\n\n    stream.writeStream\n      .trigger(Trigger.AvailableNow())\n      .option(\"checkpointLocation\", checkpoint.getAbsolutePath)\n      .toTable(\"readStreamWithQueryCheckpoint\")\n      .awaitTermination()\n\n    val partial: Int = total / 2\n    // create partial number of persons starting from 1\n    createPersonNodes(1, partial, 0, 10)\n\n    // fetch whatever is available\n    stream.writeStream\n      .trigger(Trigger.AvailableNow())\n      .option(\"checkpointLocation\", checkpoint.getAbsolutePath)\n      .toTable(\"readStreamWithQueryCheckpoint\")\n      .awaitTermination()\n\n    // create rest of the persons starting from partial+1\n    createPersonNodes(partial + 1, total - partial, 0, 10)\n\n    // fetch rest of the items from where we left off\n    stream.writeStream\n      .trigger(Trigger.AvailableNow())\n      .option(\"checkpointLocation\", checkpoint.getAbsolutePath)\n      .toTable(\"readStreamWithQueryCheckpoint\")\n      .awaitTermination()\n\n    assertEquals(\n      expected,\n      selectRowsFromTable(\"select * from readStreamWithQueryCheckpoint order by timestamp\", mapPerson)\n    )\n  }\n\n  @Test\n  def testReadStreamWithQueryResumesFromCheckpointWithNewParams(): Unit = {\n    createPersonNodes(0, 1)\n\n    val stream = ss.readStream.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"streaming.property.name\", \"timestamp\")\n      .option(\"streaming.from\", \"ALL\")\n      .option(\n        \"query\",\n        \"\"\"\n          |MATCH (p:Person)\n          |WHERE p.timestamp > $stream.from AND p.timestamp <= $stream.to\n          |RETURN p.age AS age, p.timestamp AS timestamp\n          |\"\"\".stripMargin\n      )\n      .option(\n        \"streaming.query.offset\",\n        \"\"\"\n          |MATCH (p:Person)\n          |RETURN max(p.timestamp)\n          |\"\"\".stripMargin\n      )\n      .load()\n\n    val total = 60\n    val expected: Seq[Map[String, Any]] = (0 to total).map(index =>\n      Map(\n        \"age\" -> s\"$index\"\n      )\n    ).toList\n\n    val checkpoint = folder.newFolder()\n\n    stream.writeStream\n      .trigger(Trigger.AvailableNow())\n      .option(\"checkpointLocation\", checkpoint.getAbsolutePath)\n      .toTable(\"readStreamWithQueryCheckpointNewParams\")\n      .awaitTermination()\n\n    val partial: Int = total / 2\n    // create partial number of persons starting from 1\n    createPersonNodes(1, partial, 0, 10)\n\n    // fetch whatever is available\n    stream.writeStream\n      .trigger(Trigger.AvailableNow())\n      .option(\"checkpointLocation\", checkpoint.getAbsolutePath)\n      .toTable(\"readStreamWithQueryCheckpointNewParams\")\n      .awaitTermination()\n\n    // create rest of the persons starting from partial+1\n    createPersonNodes(partial + 1, total - partial, 0, 10)\n\n    // fetch rest of the items from where we left off\n    stream.writeStream\n      .trigger(Trigger.AvailableNow())\n      .option(\"checkpointLocation\", checkpoint.getAbsolutePath)\n      .toTable(\"readStreamWithQueryCheckpointNewParams\")\n      .awaitTermination()\n\n    assertEquals(\n      expected,\n      selectRowsFromTable(\"select * from readStreamWithQueryCheckpointNewParams order by timestamp\", mapPerson)\n    )\n  }\n\n  @Test\n  def testStreamDoesNotReadAnyDataIfStreamingQueryReturnsNothing(): Unit = {\n    createPersonNodes(0, 50)\n    use(session()) { session =>\n      session.run(\"MATCH (p:Person) SET p:Human\").consume()\n    }\n    val stream = ss.readStream.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"streaming.property.name\", \"timestamp\")\n      .option(\"streaming.from\", \"ALL\")\n      .option(\n        \"query\",\n        \"\"\"\n          |MATCH (p:Person)\n          |WHERE p.timestamp > $stream.from AND p.timestamp <= $stream.to\n          |RETURN p.age AS age, p.timestamp AS timestamp\n          |\"\"\".stripMargin\n      )\n      .option(\"streaming.query.offset\", \"MATCH (p:Human) RETURN max(p.timestamp)\")\n      .load()\n\n    val checkpoint = folder.newFolder()\n    // 1st trigger: every node was processed\n    var streamTable = stream.writeStream\n      .trigger(Trigger.AvailableNow())\n      .option(\"checkpointLocation\", checkpoint.getAbsolutePath)\n      .toTable(\"testStreamDoesNotReadAnyDataIfStreamingQueryReturnsNothing\")\n    streamTable.awaitTermination()\n    val firstSource = streamTable.lastProgress.sources.head\n    assertEquals(50, firstSource.numInputRows)\n    val endOffset1 = firstSource.endOffset\n    use(session()) { session =>\n      session.run(\"MATCH (p:Human) REMOVE p:Human\").consume()\n    }\n    // 2nd trigger: previous offset is kept intact\n    streamTable = stream.writeStream\n      .trigger(Trigger.AvailableNow())\n      .option(\"checkpointLocation\", checkpoint.getAbsolutePath)\n      .toTable(\"testStreamDoesNotReadAnyDataIfStreamingQueryReturnsNothing\")\n    streamTable.awaitTermination()\n    val source = streamTable.lastProgress.sources.head\n    assertEquals(endOffset1, source.startOffset)\n    assertEquals(endOffset1, source.endOffset)\n    assertEquals(0L, source.numInputRows)\n  }\n\n  private def createPersonNodes(minAge: Int, maxAge: Int, delayMs: Int = 0, intervalMs: Int = 0): Unit = {\n    use(session()) { session =>\n      Thread.sleep(delayMs)\n      (minAge until minAge + maxAge).foreach(age => {\n        Thread.sleep(intervalMs)\n        session.run(\n          s\"CREATE (p:Person {age: '$age', timestamp: timestamp()})\"\n        ).consume()\n      })\n    }\n  }\n\n  private def createMovieNodes(from: Int, count: Int, delayMs: Int = 0, intervalMs: Int = 0): Unit = {\n    use(session()) { session =>\n      Thread.sleep(delayMs)\n      (from until from + count).foreach(index => {\n        Thread.sleep(intervalMs)\n        session.run(\n          s\"CREATE (n:Movie {title: 'My movie $index', timestamp: timestamp()})\"\n        ).consume()\n      })\n    }\n  }\n\n  private def createLikesRelationships(from: Int, count: Int, delayMs: Int = 0, intervalMs: Int = 0): Unit = {\n    use(session()) { session =>\n      Thread.sleep(delayMs)\n      (from until from + count).foreach(index => {\n        Thread.sleep(intervalMs)\n        session.run(\n          s\"\"\"\n             |CREATE (person:Person {age: $index})\n             |CREATE (post:Post {hash: \"hash$index\"})\n             |CREATE (person)-[:LIKES{id: $index, timestamp: timestamp()}]->(post)\n             |\"\"\".stripMargin\n        ).consume()\n      })\n    }\n  }\n\n  private def selectRowsFromTable(\n    query: String,\n    mapper: (Row) => Map[String, Any]\n  ): Seq[Map[String, Any]] = {\n    ss.sql(query)\n      .collect()\n      .map(row => mapper(row))\n      .toList\n  }\n\n  private def mapPerson(row: Row): Map[String, Any] = {\n    Map(\n      \"age\" -> row.getAs[String](\"age\")\n    )\n  }\n\n  private def mapMovie(row: Row): Map[String, Any] = {\n    Map(\n      \"<labels>\" -> row.getAs[java.util.List[String]](\"<labels>\"),\n      \"title\" -> row.getAs[String](\"title\")\n    )\n  }\n\n  private def mapLikes(row: Row): Map[String, Any] = {\n    Map(\n      \"<rel.type>\" -> row.getAs[String](\"<rel.type>\"),\n      \"<source.labels>\" -> row.getAs[java.util.List[String]](\"<source.labels>\"),\n      \"source.age\" -> row.getAs[Long](\"source.age\"),\n      \"<target.labels>\" -> row.getAs[java.util.List[String]](\"<target.labels>\"),\n      \"target.hash\" -> row.getAs[String](\"target.hash\"),\n      \"rel.id\" -> row.getAs[Long](\"rel.id\")\n    )\n  }\n\n}\n"
  },
  {
    "path": "spark-3/src/test/scala/org/neo4j/spark/DataSourceStreamingWriterTSE.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark\n\nimport org.apache.spark.sql.execution.streaming.MemoryStream\nimport org.apache.spark.sql.streaming.StreamingQuery\nimport org.hamcrest.Matchers\nimport org.junit.After\nimport org.junit.Test\nimport org.neo4j.driver.Transaction\nimport org.neo4j.driver.TransactionWork\nimport org.neo4j.spark.Assert.ThrowingSupplier\n\nimport java.util.UUID\nimport java.util.concurrent.TimeUnit\n\nclass DataSourceStreamingWriterTSE extends SparkConnectorScalaBaseTSE {\n\n  private var query: StreamingQuery = null\n\n  @After\n  def close(): Unit = {\n    if (query != null) {\n      query.stop()\n    }\n  }\n\n  @Test\n  def testSinkStreamWithLabelsWithAppend(): Unit = {\n    implicit val ctx = ss.sqlContext\n    import ss.implicits._\n    val memStream = MemoryStream[Int]\n    val recordSize = 2000\n    val partition = 5\n    val checkpointLocation = \"/tmp/checkpoint/\" + UUID.randomUUID().toString\n    query = memStream.toDF().writeStream\n      .format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"save.mode\", \"Append\")\n      .option(\"labels\", \"Timestamp\")\n      .option(\"checkpointLocation\", checkpointLocation)\n      .option(\"node.keys\", \"value\")\n      .start()\n\n    (1 to partition).foreach(index => {\n      // we send the total of records in 5 times\n      val start = ((index - 1) * recordSize) + 1\n      val end = index * recordSize\n      memStream.addData((start to end).toArray)\n    })\n\n    Assert.assertEventually(\n      new ThrowingSupplier[Boolean, Exception] {\n        override def get(): Boolean = {\n          val dataFrame = ss.read.format(classOf[DataSource].getName)\n            .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n            .option(\"labels\", \"Timestamp\")\n            .load()\n\n          val collect = dataFrame.collect()\n          val data = if (dataFrame.columns.contains(\"value\")) {\n            collect\n              .map(row => row.getAs[Long](\"value\").toInt)\n              .sorted\n          } else {\n            Array.empty[Int]\n          }\n          data.toList == (1 to (recordSize * partition)).toList\n        }\n      },\n      Matchers.equalTo(true),\n      30L,\n      TimeUnit.SECONDS\n    )\n  }\n\n  @Test\n  def testSinkStreamWithRelationshipWithAppend(): Unit = {\n    implicit val ctx = ss.sqlContext\n    import ss.implicits._\n    val memStream = MemoryStream[Int]\n    val recordSize = 2000\n    val partition = 5\n    val checkpointLocation = \"/tmp/checkpoint/\" + UUID.randomUUID().toString\n\n    query = memStream.toDF().writeStream\n      .format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"save.mode\", \"Append\")\n      .option(\"relationship\", \"PAIRS\")\n      .option(\"relationship.save.strategy\", \"keys\")\n      .option(\"relationship.source.labels\", \":From\")\n      .option(\"relationship.source.node.keys\", \"value\")\n      .option(\"relationship.source.save.mode\", \"Append\")\n      .option(\"relationship.target.labels\", \":To\")\n      .option(\"relationship.target.node.keys\", \"value\")\n      .option(\"relationship.target.save.mode\", \"Append\")\n      .option(\"checkpointLocation\", checkpointLocation)\n      .start()\n\n    (1 to partition).foreach(index => {\n      // we send the total of records in 5 times\n      val start = ((index - 1) * recordSize) + 1\n      val end = index * recordSize\n      memStream.addData((start to end).toArray)\n    })\n\n    Assert.assertEventually(\n      new ThrowingSupplier[Boolean, Exception] {\n        override def get(): Boolean =\n          try {\n            val dataFrame = ss.read.format(classOf[DataSource].getName)\n              .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n              .option(\"relationship\", \"PAIRS\")\n              .option(\"relationship.source.labels\", \":From\")\n              .option(\"relationship.target.labels\", \":To\")\n              .load()\n\n            val collect = dataFrame.collect()\n            val data = if (dataFrame.columns.contains(\"source.value\") && dataFrame.columns.contains(\"target.value\")) {\n              collect\n                .map(row => (row.getAs[Long](\"source.value\").toInt, row.getAs[Long](\"target.value\").toInt))\n                .sorted\n            } else {\n              Array.empty[(Int, Int)]\n            }\n            data.toList == (1 to (recordSize * partition)).map(v => (v, v)).toList\n          } catch {\n            case _: Throwable => false\n          }\n      },\n      Matchers.equalTo(true),\n      30L,\n      TimeUnit.SECONDS\n    )\n  }\n\n  @Test\n  def testSinkStreamWithQuery(): Unit = {\n    implicit val ctx = ss.sqlContext\n    import ss.implicits._\n    val memStream = MemoryStream[Int]\n    val recordSize = 2000\n    val partition = 5\n    val checkpointLocation = \"/tmp/checkpoint/\" + UUID.randomUUID().toString\n\n    query = memStream.toDF().writeStream\n      .format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"query\", \"MERGE (m:MyNewNode {the_value: event.value})\")\n      .option(\"checkpointLocation\", checkpointLocation)\n      .start()\n\n    (1 to partition).foreach(index => {\n      // we send the total of records in 5 times\n      val start = ((index - 1) * recordSize) + 1\n      val end = index * recordSize\n      memStream.addData((start to end).toArray)\n    })\n\n    Assert.assertEventually(\n      new ThrowingSupplier[Boolean, Exception] {\n        override def get(): Boolean =\n          try {\n            val dataFrame = ss.read.format(classOf[DataSource].getName)\n              .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n              .option(\"labels\", \"MyNewNode\")\n              .load()\n\n            val collect = dataFrame.collect()\n            val data = if (dataFrame.columns.contains(\"the_value\")) {\n              collect\n                .map(row => row.getAs[Long](\"the_value\").toInt)\n                .sorted\n            } else {\n              Array.empty[Int]\n            }\n            val l1 = data.toList\n            val l2 = (1 to (recordSize * partition)).map(v => v).toList\n            l1 == l2\n          } catch {\n            case _: Throwable => false\n          }\n      },\n      Matchers.equalTo(true),\n      30L,\n      TimeUnit.SECONDS\n    )\n  }\n\n  @Test\n  def testSinkStreamWithLabelsWithOverwrite(): Unit = {\n    implicit val ctx = ss.sqlContext\n    import ss.implicits._\n    val memStream = MemoryStream[Int]\n    val partition = 5\n    val checkpointLocation = \"/tmp/checkpoint/\" + UUID.randomUUID().toString\n\n    SparkConnectorScalaSuiteIT.session().run(\n      \"CREATE CONSTRAINT timestamp_value FOR (t:Timestamp) REQUIRE (t.value) IS UNIQUE\"\n    )\n\n    query = memStream.toDF().writeStream\n      .format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"save.mode\", \"Overwrite\")\n      .option(\"labels\", \"Timestamp\")\n      .option(\"checkpointLocation\", checkpointLocation)\n      .option(\"node.keys\", \"value\")\n      .start()\n    (1 to partition).foreach(index => {\n      memStream.addData((1 to 500).toArray)\n    })\n\n    Assert.assertEventually(\n      new ThrowingSupplier[Boolean, Exception] {\n        override def get(): Boolean = {\n          val dataFrame = ss.read.format(classOf[DataSource].getName)\n            .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n            .option(\"labels\", \"Timestamp\")\n            .load()\n\n          val collect = dataFrame.collect()\n          val data = if (dataFrame.columns.contains(\"value\")) {\n            collect\n              .map(row => row.getAs[Long](\"value\").toInt)\n              .sorted\n          } else {\n            Array.empty[Int]\n          }\n          data.toList == (1 to 500).toList\n        }\n      },\n      Matchers.equalTo(true),\n      30L,\n      TimeUnit.SECONDS\n    )\n\n    SparkConnectorScalaSuiteIT.session().run(\"DROP CONSTRAINT timestamp_value\")\n  }\n\n  @Test\n  def testSinkStreamWithRelationshipWithAppendAndOverwrite(): Unit = {\n    implicit val ctx = ss.sqlContext\n    import ss.implicits._\n    val memStream = MemoryStream[Int]\n    val partition = 5\n    val checkpointLocation = \"/tmp/checkpoint/\" + UUID.randomUUID().toString\n\n    SparkConnectorScalaSuiteIT.driver.session()\n      .writeTransaction(\n        new TransactionWork[Unit] {\n          override def execute(tx: Transaction): Unit = {\n            tx.run(\"CREATE CONSTRAINT From_value FOR (p:From) REQUIRE p.value IS UNIQUE\")\n            tx.run(\"CREATE CONSTRAINT To_value FOR (p:To) REQUIRE p.value IS UNIQUE\")\n          }\n        }\n      )\n\n    query = memStream.toDF().writeStream\n      .format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"save.mode\", \"Append\")\n      .option(\"relationship\", \"PAIRS\")\n      .option(\"relationship.save.strategy\", \"keys\")\n      .option(\"relationship.source.labels\", \":From\")\n      .option(\"relationship.source.node.keys\", \"value\")\n      .option(\"relationship.source.save.mode\", \"Overwrite\")\n      .option(\"relationship.target.labels\", \":To\")\n      .option(\"relationship.target.node.keys\", \"value\")\n      .option(\"relationship.target.save.mode\", \"Overwrite\")\n      .option(\"checkpointLocation\", checkpointLocation)\n      .start()\n\n    (1 to partition).foreach(index => {\n      memStream.addData((1 to 500).toArray)\n    })\n\n    Assert.assertEventually(\n      new ThrowingSupplier[Boolean, Exception] {\n        override def get(): Boolean =\n          try {\n            val dataFrame = ss.read.format(classOf[DataSource].getName)\n              .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n              .option(\"relationship\", \"PAIRS\")\n              .option(\"relationship.source.labels\", \":From\")\n              .option(\"relationship.target.labels\", \":To\")\n              .load()\n\n            val collect = dataFrame.collect()\n            val data = if (dataFrame.columns.contains(\"source.value\") && dataFrame.columns.contains(\"target.value\")) {\n              collect\n                .map(row => (row.getAs[Long](\"source.value\").toInt, row.getAs[Long](\"target.value\").toInt))\n                .sorted\n            } else {\n              Array.empty[(Int, Int)]\n            }\n            data.toList == (1 to 500).flatMap(v => (1 to 5).map(_ => (v, v)))\n          } catch {\n            case _: Throwable => false\n          }\n      },\n      Matchers.equalTo(true),\n      30L,\n      TimeUnit.SECONDS\n    )\n\n    SparkConnectorScalaSuiteIT.driver.session()\n      .writeTransaction(\n        new TransactionWork[Unit] {\n          override def execute(tx: Transaction): Unit = {\n            tx.run(\"DROP CONSTRAINT From_value\")\n            tx.run(\"DROP CONSTRAINT To_value\")\n          }\n        }\n      )\n  }\n}\n"
  },
  {
    "path": "spark-3/src/test/scala/org/neo4j/spark/DataSourceWriterNeo4jSkipNullKeysTSE.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark\n\nimport org.apache.spark.SparkException\nimport org.apache.spark.sql.SaveMode\nimport org.junit.Assume\nimport org.junit.Test\nimport org.neo4j.Closeables.use\nimport org.neo4j.caniuse.CanIUse\nimport org.neo4j.caniuse.Schema\n\nclass DataSourceWriterNeo4jSkipNullKeysTSE extends SparkConnectorScalaBaseTSE {\n\n  import ss.implicits._\n\n  @Test\n  def `fails to write nodes when key properties contain null values`(): Unit = {\n    val cities = Seq(\n      (Some(1), \"Cherbourg en Cotentin\"),\n      (Some(2), \"London\"),\n      (Some(3), \"Malmö\"),\n      (None, \"Moon\")\n    ).toDF(\"id\", \"city\")\n\n    val caught = intercept[SparkException] {\n      cities.write\n        .format(classOf[DataSource].getName)\n        .mode(SaveMode.Overwrite)\n        .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n        .option(\"labels\", \":City\")\n        .option(\"node.keys\", \"id\")\n        .option(\"schema.optimization.node.keys\", \"KEY\")\n        .save()\n    }\n    assert(caught.getMessage contains \"Cannot merge the following node because of null property value\")\n  }\n\n  @Test\n  def `fails to write relationships when source node key properties contain null values`(): Unit = {\n    val caught = intercept[SparkException] {\n      val cities = Seq(\n        (Some(1), Some(2), \"British Airways\"),\n        (Some(2), Some(3), \"Turkish Airlines\"),\n        (None, Some(5), \"Another Airline\")\n      ).toDF(\"from\", \"to\", \"airline\")\n\n      cities.write\n        .format(classOf[DataSource].getName)\n        .mode(SaveMode.Overwrite)\n        .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n        .option(\"relationship\", \"FLIES_TO\")\n        .option(\"relationship.save.strategy\", \"keys\")\n        .option(\"relationship.source.save.mode\", \"Overwrite\")\n        .option(\"relationship.source.labels\", \":City\")\n        .option(\"relationship.source.node.keys\", \"from:id\")\n        .option(\"relationship.target.save.mode\", \"Overwrite\")\n        .option(\"relationship.target.labels\", \":City\")\n        .option(\"relationship.target.node.keys\", \"to:id\")\n        .option(\"relationship.properties\", \"airline\")\n        .option(\"schema.optimization.node.keys\", \"KEY\")\n        .save()\n    }\n    assert(caught.getMessage contains \"Cannot merge the following node because of null property value\")\n  }\n\n  @Test\n  def `fails to write relationships when target node key properties contain null values`(): Unit = {\n    val caught = intercept[SparkException] {\n      val cities = Seq(\n        (Some(1), Some(2), \"British Airways\"),\n        (Some(2), Some(3), \"Turkish Airlines\"),\n        (Some(3), None, \"Another Airline\")\n      ).toDF(\"from\", \"to\", \"airline\")\n\n      cities.write\n        .format(classOf[DataSource].getName)\n        .mode(SaveMode.Overwrite)\n        .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n        .option(\"relationship\", \"FLIES_TO\")\n        .option(\"relationship.save.strategy\", \"keys\")\n        .option(\"relationship.source.save.mode\", \"Overwrite\")\n        .option(\"relationship.source.labels\", \":City\")\n        .option(\"relationship.source.node.keys\", \"from:id\")\n        .option(\"relationship.target.save.mode\", \"Overwrite\")\n        .option(\"relationship.target.labels\", \":City\")\n        .option(\"relationship.target.node.keys\", \"to:id\")\n        .option(\"relationship.properties\", \"airline\")\n        .option(\"schema.optimization.node.keys\", \"KEY\")\n        .save()\n    }\n    assert(caught.getMessage contains \"Cannot merge the following node because of null property value\")\n  }\n\n  @Test\n  def `fails to write relationships when relationship key properties contain null values`(): Unit = {\n    Assume.assumeTrue(\n      CanIUse.INSTANCE.canIUse(Schema.INSTANCE.relationshipKeyConstraints()).withNeo4j(SparkConnectorScalaSuiteIT.neo4j)\n    )\n\n    val caught = intercept[SparkException] {\n      val cities = Seq(\n        (Some(1), Some(2), Some(\"BA721\"), \"British Airways\"),\n        (Some(2), Some(3), Some(\"TK211\"), \"Turkish Airlines\"),\n        (Some(3), Some(4), None, \"Another Airline\")\n      ).toDF(\"from\", \"to\", \"flight\", \"airline\")\n\n      cities.write\n        .format(classOf[DataSource].getName)\n        .mode(SaveMode.Overwrite)\n        .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n        .option(\"relationship\", \"FLIES_TO\")\n        .option(\"relationship.save.strategy\", \"keys\")\n        .option(\"relationship.source.save.mode\", \"Overwrite\")\n        .option(\"relationship.source.labels\", \":City\")\n        .option(\"relationship.source.node.keys\", \"from:id\")\n        .option(\"relationship.target.save.mode\", \"Overwrite\")\n        .option(\"relationship.target.labels\", \":City\")\n        .option(\"relationship.target.node.keys\", \"to:id\")\n        .option(\"relationship.keys\", \"flight\")\n        .option(\"relationship.properties\", \"airline\")\n        .option(\"schema.optimization.node.keys\", \"KEY\")\n        .option(\"schema.optimization.relationship.keys\", \"KEY\")\n        .save()\n    }\n    assert(caught.getMessage contains \"Cannot merge the following relationship because of null property value\")\n  }\n\n  @Test\n  def `skips nodes when key properties contain null values with APPEND mode`(): Unit = {\n    val cities = Seq(\n      (Some(1), \"Cherbourg en Cotentin\"),\n      (Some(2), \"London\"),\n      (Some(3), \"Malmö\"),\n      (None, \"Moon\")\n    ).toDF(\"id\", \"city\")\n\n    cities.write\n      .format(classOf[DataSource].getName)\n      .mode(SaveMode.Append)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"labels\", \":City\")\n      .option(\"node.keys\", \"id\")\n      .option(\"node.keys.skip.nulls\", \"true\")\n      .save()\n\n    use(SparkConnectorScalaSuiteIT.driver.session()) { session =>\n      val result = session.run(\"MATCH (n:City) RETURN count(n) as count\")\n        .single()\n        .get(\"count\")\n        .asLong()\n      assert(result == 3)\n    }\n  }\n\n  @Test\n  def `skips nodes when key properties contain null values with OVERWRITE mode`(): Unit = {\n    val cities = Seq(\n      (Some(1), \"Cherbourg en Cotentin\"),\n      (Some(2), \"London\"),\n      (Some(3), \"Malmö\"),\n      (None, \"Moon\")\n    ).toDF(\"id\", \"city\")\n\n    cities.write\n      .format(classOf[DataSource].getName)\n      .mode(SaveMode.Overwrite)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"labels\", \":City\")\n      .option(\"node.keys\", \"id\")\n      .option(\"node.keys.skip.nulls\", \"true\")\n      .option(\"schema.optimization.node.keys\", \"KEY\")\n      .save()\n\n    use(SparkConnectorScalaSuiteIT.driver.session()) { session =>\n      val result = session.run(\"MATCH (n:City) RETURN count(n) as count\")\n        .single()\n        .get(\"count\")\n        .asLong()\n      assert(result == 3)\n    }\n  }\n\n  @Test\n  def `skips relationships when source or target node key properties contain null values`(): Unit = {\n    val cities = Seq(\n      (Some(1), Some(2), \"British Airways\"),\n      (Some(2), Some(3), \"Turkish Airlines\"),\n      (None, Some(5), \"Another Airline\"),\n      (Some(5), None, \"Another Airline\")\n    ).toDF(\"from\", \"to\", \"airline\")\n\n    cities.write\n      .format(classOf[DataSource].getName)\n      .mode(SaveMode.Overwrite)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"relationship\", \"FLIES_TO\")\n      .option(\"relationship.save.strategy\", \"keys\")\n      .option(\"relationship.source.save.mode\", \"Overwrite\")\n      .option(\"relationship.source.labels\", \":City\")\n      .option(\"relationship.source.node.keys\", \"from:id\")\n      .option(\"relationship.target.save.mode\", \"Overwrite\")\n      .option(\"relationship.target.labels\", \":City\")\n      .option(\"relationship.target.node.keys\", \"to:id\")\n      .option(\"relationship.properties\", \"airline\")\n      .option(\"schema.optimization.node.keys\", \"KEY\")\n      .option(\"relationship.source.node.keys.skip.nulls\", \"true\")\n      .option(\"relationship.target.node.keys.skip.nulls\", \"true\")\n      .save()\n\n    use(SparkConnectorScalaSuiteIT.driver.session()) { session =>\n      val cities = session.run(\"MATCH (n:City) RETURN count(n) as count\")\n        .single()\n        .get(\"count\")\n        .asLong()\n      assert(cities == 3)\n\n      val citiesWithId5 = session.run(\"MATCH (n:City {id: 5}) RETURN count(n) as count\")\n        .single()\n        .get(\"count\")\n        .asLong()\n      assert(citiesWithId5 == 0)\n\n      val flies = session.run(\"MATCH ()-[r:FLIES_TO]->() RETURN count(r) as count\")\n        .single()\n        .get(\"count\")\n        .asLong()\n      assert(flies == 2)\n    }\n  }\n\n  @Test\n  def `skips relationships when source or target node key properties contain null values when nodes are matched`()\n    : Unit = {\n    use(SparkConnectorScalaSuiteIT.driver.session()) { session =>\n      session.run(\"UNWIND [1,2,3,5] AS id CREATE (:City {id: id})\").consume()\n    }\n\n    val cities = Seq(\n      (Some(1), Some(2), \"British Airways\"),\n      (Some(2), Some(3), \"Turkish Airlines\"),\n      (None, Some(5), \"Another Airline\"),\n      (Some(5), None, \"Another Airline\")\n    ).toDF(\"from\", \"to\", \"airline\")\n\n    cities.write\n      .format(classOf[DataSource].getName)\n      .mode(SaveMode.Overwrite)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"relationship\", \"FLIES_TO\")\n      .option(\"relationship.save.strategy\", \"keys\")\n      .option(\"relationship.source.save.mode\", \"Match\")\n      .option(\"relationship.source.labels\", \":City\")\n      .option(\"relationship.source.node.keys\", \"from:id\")\n      .option(\"relationship.target.save.mode\", \"Match\")\n      .option(\"relationship.target.labels\", \":City\")\n      .option(\"relationship.target.node.keys\", \"to:id\")\n      .option(\"relationship.properties\", \"airline\")\n      .option(\"relationship.source.node.keys.skip.nulls\", \"true\")\n      .option(\"relationship.target.node.keys.skip.nulls\", \"true\")\n      .save()\n\n    use(SparkConnectorScalaSuiteIT.driver.session()) { session =>\n      val cities = session.run(\"MATCH (n:City) RETURN count(n) as count\")\n        .single()\n        .get(\"count\")\n        .asLong()\n      assert(cities == 4)\n\n      val flies = session.run(\"MATCH ()-[r:FLIES_TO]->() RETURN count(r) as count\")\n        .single()\n        .get(\"count\")\n        .asLong()\n      assert(flies == 2)\n    }\n  }\n\n  @Test\n  def `skips relationships when source or target node key properties contain null values when nodes are appended`()\n    : Unit = {\n    val cities = Seq(\n      (Some(1), Some(2), \"British Airways\"),\n      (Some(3), Some(4), \"Turkish Airlines\"),\n      (None, Some(5), \"Another Airline\"),\n      (Some(5), None, \"Another Airline\")\n    ).toDF(\"from\", \"to\", \"airline\")\n\n    cities.write\n      .format(classOf[DataSource].getName)\n      .mode(SaveMode.Overwrite)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"relationship\", \"FLIES_TO\")\n      .option(\"relationship.save.strategy\", \"keys\")\n      .option(\"relationship.source.save.mode\", \"Append\")\n      .option(\"relationship.source.labels\", \":City\")\n      .option(\"relationship.source.node.keys\", \"from:id\")\n      .option(\"relationship.target.save.mode\", \"Append\")\n      .option(\"relationship.target.labels\", \":City\")\n      .option(\"relationship.target.node.keys\", \"to:id\")\n      .option(\"relationship.properties\", \"airline\")\n      .option(\"relationship.source.node.keys.skip.nulls\", \"true\")\n      .option(\"relationship.target.node.keys.skip.nulls\", \"true\")\n      .save()\n\n    use(SparkConnectorScalaSuiteIT.driver.session()) { session =>\n      val cities = session.run(\"MATCH (n:City) RETURN count(n) as count\")\n        .single()\n        .get(\"count\")\n        .asLong()\n      assert(cities == 4)\n\n      val citiesWithId5 = session.run(\"MATCH (n:City {id: 5}) RETURN count(n) as count\")\n        .single()\n        .get(\"count\")\n        .asLong()\n      assert(citiesWithId5 == 0)\n\n      val flies = session.run(\"MATCH ()-[r:FLIES_TO]->() RETURN count(r) as count\")\n        .single()\n        .get(\"count\")\n        .asLong()\n      assert(flies == 2)\n    }\n  }\n\n  @Test\n  def `skips relationships when source or target node key properties contain null values with append mode`(): Unit = {\n    val cities = Seq(\n      (Some(1), Some(2), \"British Airways\"),\n      (Some(3), Some(4), \"Turkish Airlines\"),\n      (None, Some(5), \"Another Airline\"),\n      (Some(5), None, \"Another Airline\")\n    ).toDF(\"from\", \"to\", \"airline\")\n\n    cities.write\n      .format(classOf[DataSource].getName)\n      .mode(SaveMode.Append)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"relationship\", \"FLIES_TO\")\n      .option(\"relationship.save.strategy\", \"keys\")\n      .option(\"relationship.source.save.mode\", \"Overwrite\")\n      .option(\"relationship.source.labels\", \":City\")\n      .option(\"relationship.source.node.keys\", \"from:id\")\n      .option(\"relationship.target.save.mode\", \"Overwrite\")\n      .option(\"relationship.target.labels\", \":City\")\n      .option(\"relationship.target.node.keys\", \"to:id\")\n      .option(\"relationship.properties\", \"airline\")\n      .option(\"schema.optimization.node.keys\", \"KEY\")\n      .option(\"relationship.source.node.keys.skip.nulls\", \"true\")\n      .option(\"relationship.target.node.keys.skip.nulls\", \"true\")\n      .save()\n\n    use(SparkConnectorScalaSuiteIT.driver.session()) { session =>\n      val cities = session.run(\"MATCH (n:City) RETURN count(n) as count\")\n        .single()\n        .get(\"count\")\n        .asLong()\n      assert(cities == 4)\n\n      val citiesWithId5 = session.run(\"MATCH (n:City {id: 5}) RETURN count(n) as count\")\n        .single()\n        .get(\"count\")\n        .asLong()\n      assert(citiesWithId5 == 0)\n\n      val flies = session.run(\"MATCH ()-[r:FLIES_TO]->() RETURN count(r) as count\")\n        .single()\n        .get(\"count\")\n        .asLong()\n      assert(flies == 2)\n    }\n  }\n\n  @Test\n  def `skips relationships when source or target node key properties contain null values when nodes are matched with append mode`()\n    : Unit = {\n    use(SparkConnectorScalaSuiteIT.driver.session()) { session =>\n      session.run(\"UNWIND [1,2,3,5] AS id CREATE (:City {id: id})\").consume()\n    }\n\n    val cities = Seq(\n      (Some(1), Some(2), \"British Airways\"),\n      (Some(2), Some(3), \"Turkish Airlines\"),\n      (None, Some(5), \"Another Airline\"),\n      (Some(5), None, \"Another Airline\")\n    ).toDF(\"from\", \"to\", \"airline\")\n\n    cities.write\n      .format(classOf[DataSource].getName)\n      .mode(SaveMode.Append)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"relationship\", \"FLIES_TO\")\n      .option(\"relationship.save.strategy\", \"keys\")\n      .option(\"relationship.source.save.mode\", \"Match\")\n      .option(\"relationship.source.labels\", \":City\")\n      .option(\"relationship.source.node.keys\", \"from:id\")\n      .option(\"relationship.target.save.mode\", \"Match\")\n      .option(\"relationship.target.labels\", \":City\")\n      .option(\"relationship.target.node.keys\", \"to:id\")\n      .option(\"relationship.properties\", \"airline\")\n      .option(\"relationship.source.node.keys.skip.nulls\", \"true\")\n      .option(\"relationship.target.node.keys.skip.nulls\", \"true\")\n      .save()\n\n    use(SparkConnectorScalaSuiteIT.driver.session()) { session =>\n      val cities = session.run(\"MATCH (n:City) RETURN count(n) as count\")\n        .single()\n        .get(\"count\")\n        .asLong()\n      assert(cities == 4)\n\n      val flies = session.run(\"MATCH ()-[r:FLIES_TO]->() RETURN count(r) as count\")\n        .single()\n        .get(\"count\")\n        .asLong()\n      assert(flies == 2)\n    }\n  }\n\n  @Test\n  def `skips relationships when source or target node key properties contain null values when nodes are appended with append mode`()\n    : Unit = {\n    val cities = Seq(\n      (Some(1), Some(2), \"British Airways\"),\n      (Some(3), Some(4), \"Turkish Airlines\"),\n      (None, Some(5), \"Another Airline\"),\n      (Some(5), None, \"Another Airline\")\n    ).toDF(\"from\", \"to\", \"airline\")\n\n    cities.write\n      .format(classOf[DataSource].getName)\n      .mode(SaveMode.Append)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"relationship\", \"FLIES_TO\")\n      .option(\"relationship.save.strategy\", \"keys\")\n      .option(\"relationship.source.save.mode\", \"Append\")\n      .option(\"relationship.source.labels\", \":City\")\n      .option(\"relationship.source.node.keys\", \"from:id\")\n      .option(\"relationship.target.save.mode\", \"Append\")\n      .option(\"relationship.target.labels\", \":City\")\n      .option(\"relationship.target.node.keys\", \"to:id\")\n      .option(\"relationship.properties\", \"airline\")\n      .option(\"relationship.source.node.keys.skip.nulls\", \"true\")\n      .option(\"relationship.target.node.keys.skip.nulls\", \"true\")\n      .save()\n\n    use(SparkConnectorScalaSuiteIT.driver.session()) { session =>\n      val cities = session.run(\"MATCH (n:City) RETURN count(n) as count\")\n        .single()\n        .get(\"count\")\n        .asLong()\n      assert(cities == 4)\n\n      val citiesWithId5 = session.run(\"MATCH (n:City {id: 5}) RETURN count(n) as count\")\n        .single()\n        .get(\"count\")\n        .asLong()\n      assert(citiesWithId5 == 0)\n\n      val flies = session.run(\"MATCH ()-[r:FLIES_TO]->() RETURN count(r) as count\")\n        .single()\n        .get(\"count\")\n        .asLong()\n      assert(flies == 2)\n    }\n  }\n\n  @Test\n  def `skips relationships when relationship key properties contain null values`(): Unit = {\n    Assume.assumeTrue(\n      CanIUse.INSTANCE.canIUse(Schema.INSTANCE.relationshipKeyConstraints()).withNeo4j(SparkConnectorScalaSuiteIT.neo4j)\n    )\n\n    val cities = Seq(\n      (Some(1), Some(2), Some(\"BA721\"), \"British Airways\"),\n      (Some(2), Some(3), Some(\"TK211\"), \"Turkish Airlines\"),\n      (Some(3), Some(5), None, \"Another Airline\")\n    ).toDF(\"from\", \"to\", \"flight\", \"airline\")\n\n    cities.write\n      .format(classOf[DataSource].getName)\n      .mode(SaveMode.Overwrite)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"relationship\", \"FLIES_TO\")\n      .option(\"relationship.save.strategy\", \"keys\")\n      .option(\"relationship.source.save.mode\", \"Overwrite\")\n      .option(\"relationship.source.labels\", \":City\")\n      .option(\"relationship.source.node.keys\", \"from:id\")\n      .option(\"relationship.target.save.mode\", \"Overwrite\")\n      .option(\"relationship.target.labels\", \":City\")\n      .option(\"relationship.target.node.keys\", \"to:id\")\n      .option(\"relationship.keys\", \"flight\")\n      .option(\"relationship.properties\", \"airline\")\n      .option(\"schema.optimization.node.keys\", \"KEY\")\n      .option(\"schema.optimization.relationship.keys\", \"KEY\")\n      .option(\"relationship.keys.skip.nulls\", \"true\")\n      .save()\n\n    use(SparkConnectorScalaSuiteIT.driver.session()) { session =>\n      val cities = session.run(\"MATCH (n:City) RETURN count(n) as count\")\n        .single()\n        .get(\"count\")\n        .asLong()\n      assert(cities == 3)\n\n      val citiesWithId5 = session.run(\"MATCH (n:City {id: 5}) RETURN count(n) as count\")\n        .single()\n        .get(\"count\")\n        .asLong()\n      assert(citiesWithId5 == 0)\n\n      val flies = session.run(\"MATCH ()-[r:FLIES_TO]->() RETURN count(r) as count\")\n        .single()\n        .get(\"count\")\n        .asLong()\n      assert(flies == 2)\n    }\n  }\n\n}\n"
  },
  {
    "path": "spark-3/src/test/scala/org/neo4j/spark/DataSourceWriterNeo4jTSE.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark\n\nimport org.apache.commons.lang3.exception.ExceptionUtils\nimport org.apache.spark.scheduler.SparkListener\nimport org.apache.spark.scheduler.SparkListenerStageCompleted\nimport org.apache.spark.scheduler.SparkListenerStageSubmitted\nimport org.apache.spark.sql.DataFrame\nimport org.apache.spark.sql.SaveMode\nimport org.hamcrest.Matchers\nimport org.junit.Assert.assertEquals\nimport org.junit.Assert.assertNotNull\nimport org.junit.Assert.assertTrue\nimport org.junit.Test\nimport org.neo4j.Closeables.use\nimport org.neo4j.driver.Session\nimport org.neo4j.driver.SessionConfig\nimport org.neo4j.driver.Transaction\nimport org.neo4j.driver.TransactionWork\nimport org.neo4j.driver.summary.ResultSummary\nimport org.neo4j.spark.writer.DataWriterMetrics\n\nimport java.util.concurrent.TimeUnit\nimport java.util.concurrent.atomic.AtomicReference\n\nclass DataSourceWriterNeo4jTSE extends SparkConnectorScalaBaseTSE {\n\n  import ss.implicits._\n\n  @Test\n  def `should read and write relations with append mode`(): Unit = {\n    val total = 100\n    val fixtureQuery: String =\n      s\"\"\"UNWIND range(1, $total) as id\n         |CREATE (pr:Product {id: id * $total, name: 'Product ' + id})\n         |CREATE (pe:Person {id: id, fullName: 'Person ' + id})\n         |CREATE (pe)-[:BOUGHT{when: rand(), quantity: rand() * 1000}]->(pr)\n         |RETURN *\n    \"\"\".stripMargin\n\n    use(SparkConnectorScalaSuiteIT.session(\"system\")) { session =>\n      session.run(\"CREATE OR REPLACE DATABASE db1 WAIT 30 seconds\").consume()\n      session.run(\"CREATE OR REPLACE DATABASE db2 WAIT 30 seconds\").consume()\n    }\n\n    use(SparkConnectorScalaSuiteIT.session(\"db1\")) { session =>\n      session.run(fixtureQuery).consume()\n    }\n\n    use(SparkConnectorScalaSuiteIT.session(\"db2\")) { session =>\n      session\n        .writeTransaction(\n          new TransactionWork[Unit] {\n            override def execute(tx: Transaction): Unit = {\n              tx.run(\"CREATE CONSTRAINT person_id FOR (p:Person) REQUIRE p.id IS UNIQUE\")\n              tx.run(\"CREATE CONSTRAINT product_id FOR (p:Product) REQUIRE p.id IS UNIQUE\")\n            }\n          }\n        )\n    }\n\n    try {\n      val dfOriginal: DataFrame = ss.read.format(classOf[DataSource].getName)\n        .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n        .option(\"database\", \"db1\")\n        .option(\"relationship\", \"BOUGHT\")\n        .option(\"relationship.nodes.map\", \"false\")\n        .option(\"relationship.source.labels\", \":Person\")\n        .option(\"relationship.target.labels\", \":Product\")\n        .load()\n\n      dfOriginal.write\n        .format(classOf[DataSource].getName)\n        .mode(SaveMode.Append)\n        .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n        .option(\"database\", \"db2\")\n        .option(\"relationship\", \"SOLD\")\n        .option(\"relationship.save.strategy\", \"NATIVE\")\n        .option(\"relationship.source.labels\", \":Person\")\n        .option(\"relationship.source.save.mode\", \"Append\")\n        .option(\"relationship.target.labels\", \":Product\")\n        .option(\"relationship.target.save.mode\", \"Append\")\n        .option(\"batch.size\", \"11\")\n        .save()\n\n      // let's write again to prove that 2 relationship are being added\n      dfOriginal.write\n        .format(classOf[DataSource].getName)\n        .mode(SaveMode.Append)\n        .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n        .option(\"database\", \"db2\")\n        .option(\"relationship\", \"SOLD\")\n        .option(\"relationship.save.strategy\", \"NATIVE\")\n        .option(\"relationship.source.labels\", \":Person\")\n        .option(\"relationship.source.save.mode\", \"Overwrite\")\n        .option(\"relationship.source.node.keys\", \"source.id:id\")\n        .option(\"relationship.target.labels\", \":Product\")\n        .option(\"relationship.target.save.mode\", \"Overwrite\")\n        .option(\"relationship.target.node.keys\", \"target.id:id\")\n        .option(\"batch.size\", \"11\")\n        .save()\n\n      val dfCopy = ss.read.format(classOf[DataSource].getName)\n        .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n        .option(\"database\", \"db2\")\n        .option(\"relationship\", \"SOLD\")\n        .option(\"relationship.nodes.map\", \"false\")\n        .option(\"relationship.source.labels\", \":Person\")\n        .option(\"relationship.target.labels\", \":Product\")\n        .load()\n\n      val dfOriginalCount = dfOriginal.count()\n      assertEquals(dfOriginalCount * 2, dfCopy.count())\n\n      val resSourceOrig = dfOriginal.select(\"`source.id`\").orderBy(\"`source.id`\").collectAsList()\n      val resSourceCopy = dfCopy.select(\"`source.id`\").orderBy(\"`source.id`\").collectAsList()\n      val resTargetOrig = dfOriginal.select(\"`target.id`\").orderBy(\"`target.id`\").collectAsList()\n      val resTargetCopy = dfCopy.select(\"`target.id`\").orderBy(\"`target.id`\").collectAsList()\n\n      for (i <- 0 until 1) {\n        assertEquals(\n          resSourceOrig.get(i).getLong(0),\n          resSourceCopy.get(i).getLong(0)\n        )\n        assertEquals(\n          resTargetOrig.get(i).getLong(0),\n          resTargetCopy.get(i).getLong(0)\n        )\n      }\n\n      assertEquals(\n        2,\n        dfCopy.where(\"`source.id` = 1\").count()\n      )\n    } finally {\n      SparkConnectorScalaSuiteIT.driver.session(SessionConfig.forDatabase(\"db2\"))\n        .writeTransaction(\n          new TransactionWork[Unit] {\n            override def execute(tx: Transaction): Unit = {\n              tx.run(\"DROP CONSTRAINT person_id\")\n              tx.run(\"DROP CONSTRAINT product_id\")\n            }\n          }\n        )\n    }\n  }\n\n  @Test\n  def `should read and write relations with overwrite mode`(): Unit = {\n    val total = 100\n    val fixtureQuery: String =\n      s\"\"\"UNWIND range(1, $total) as id\n         |CREATE (pr:Product {id: id * $total, name: 'Product ' + id})\n         |CREATE (pe:Person {id: id, fullName: 'Person ' + id})\n         |CREATE (pe)-[:BOUGHT{when: rand(), quantity: rand() * 1000}]->(pr)\n         |RETURN *\n    \"\"\".stripMargin\n\n    use(SparkConnectorScalaSuiteIT.session(\"system\")) { session =>\n      session.run(\"CREATE OR REPLACE DATABASE db1 WAIT 30 seconds\").consume()\n      session.run(\"CREATE OR REPLACE DATABASE db2 WAIT 30 seconds\").consume()\n    }\n\n    use(SparkConnectorScalaSuiteIT.session(\"db1\")) { session =>\n      session.run(fixtureQuery).consume()\n    }\n\n    use(SparkConnectorScalaSuiteIT.session(\"db2\")) { session =>\n      session\n        .writeTransaction(\n          new TransactionWork[Unit] {\n            override def execute(tx: Transaction): Unit = {\n              tx.run(\"CREATE CONSTRAINT person_id FOR (p:Person) REQUIRE p.id IS UNIQUE\")\n              tx.run(\"CREATE CONSTRAINT product_id FOR (p:Product) REQUIRE p.id IS UNIQUE\")\n            }\n          }\n        )\n    }\n\n    try {\n      val dfOriginal: DataFrame = ss.read.format(classOf[DataSource].getName)\n        .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n        .option(\"database\", \"db1\")\n        .option(\"relationship\", \"BOUGHT\")\n        .option(\"relationship.nodes.map\", \"false\")\n        .option(\"relationship.source.labels\", \":Person\")\n        .option(\"relationship.target.labels\", \":Product\")\n        .load()\n        .orderBy(\"`source.id`\", \"`target.id`\")\n\n      dfOriginal.write\n        .format(classOf[DataSource].getName)\n        .mode(SaveMode.Overwrite)\n        .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n        .option(\"database\", \"db2\")\n        .option(\"relationship\", \"SOLD\")\n        .option(\"relationship.save.strategy\", \"NATIVE\")\n        .option(\"relationship.source.labels\", \":Person\")\n        .option(\"relationship.source.save.mode\", \"Overwrite\")\n        .option(\"relationship.target.labels\", \":Product\")\n        .option(\"relationship.target.save.mode\", \"Overwrite\")\n        .option(\"batch.size\", \"11\")\n        .save()\n\n      // let's write the same thing again to prove there will be just one relation\n      dfOriginal.write\n        .format(classOf[DataSource].getName)\n        .mode(SaveMode.Overwrite)\n        .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n        .option(\"database\", \"db2\")\n        .option(\"relationship\", \"SOLD\")\n        .option(\"relationship.save.strategy\", \"NATIVE\")\n        .option(\"relationship.source.labels\", \":Person\")\n        .option(\"relationship.source.node.keys\", \"source.id:id\")\n        .option(\"relationship.source.save.mode\", \"Overwrite\")\n        .option(\"relationship.target.labels\", \":Product\")\n        .option(\"relationship.target.node.keys\", \"target.id:id\")\n        .option(\"relationship.target.save.mode\", \"Overwrite\")\n        .option(\"batch.size\", \"11\")\n        .save()\n\n      val dfCopy = ss.read.format(classOf[DataSource].getName)\n        .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n        .option(\"database\", \"db2\")\n        .option(\"relationship\", \"SOLD\")\n        .option(\"relationship.nodes.map\", \"false\")\n        .option(\"relationship.source.labels\", \":Person\")\n        .option(\"relationship.target.labels\", \":Product\")\n        .load()\n        .orderBy(\"`source.id`\", \"`target.id`\")\n\n      val dfOriginalCount = dfOriginal.count()\n      assertEquals(dfOriginalCount, dfCopy.count())\n\n      for (i <- 0 until 1) {\n        assertEquals(\n          dfOriginal.select(\"`source.id`\").collectAsList().get(i).getLong(0),\n          dfCopy.select(\"`source.id`\").collectAsList().get(i).getLong(0)\n        )\n        assertEquals(\n          dfOriginal.select(\"`target.id`\").collectAsList().get(i).getLong(0),\n          dfCopy.select(\"`target.id`\").collectAsList().get(i).getLong(0)\n        )\n      }\n\n      assertEquals(\n        1,\n        dfCopy.where(\"`source.id` = 1\").count()\n      )\n    } finally {\n      SparkConnectorScalaSuiteIT.driver.session(SessionConfig.forDatabase(\"db2\"))\n        .writeTransaction(\n          new TransactionWork[Unit] {\n            override def execute(tx: Transaction): Unit = {\n              tx.run(\"DROP CONSTRAINT person_id\")\n              tx.run(\"DROP CONSTRAINT product_id\")\n            }\n          }\n        )\n    }\n  }\n\n  @Test\n  def `should read and write relations with MATCH and node keys`(): Unit = {\n    val total = 100\n    val fixtureQuery: String =\n      s\"\"\"UNWIND range(1, $total) as id\n         |CREATE (pr:Product {id: id * $total, name: 'Product ' + id})\n         |CREATE (pe:Person {id: id, fullName: 'Person ' + id})\n         |CREATE (pe)-[:BOUGHT{when: rand(), quantity: rand() * 1000}]->(pr)\n         |RETURN *\n    \"\"\".stripMargin\n\n    use(SparkConnectorScalaSuiteIT.session(\"system\")) { session =>\n      session.run(\"CREATE OR REPLACE DATABASE db1 WAIT 30 seconds\").consume()\n      session.run(\"CREATE OR REPLACE DATABASE db2 WAIT 30 seconds\").consume()\n    }\n\n    use(SparkConnectorScalaSuiteIT.session(\"db1\")) { session =>\n      session.run(fixtureQuery).consume()\n    }\n\n    use(SparkConnectorScalaSuiteIT.session(\"db2\")) { session =>\n      session.run(fixtureQuery).consume()\n    }\n\n    val dfOriginal: DataFrame = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"database\", \"db1\")\n      .option(\"relationship\", \"BOUGHT\")\n      .option(\"relationship.nodes.map\", \"false\")\n      .option(\"relationship.source.labels\", \":Person\")\n      .option(\"relationship.target.labels\", \":Product\")\n      .load()\n      .orderBy(\"`source.id`\", \"`target.id`\")\n\n    dfOriginal.write\n      .format(classOf[DataSource].getName)\n      .mode(SaveMode.Overwrite)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"database\", \"db2\")\n      .option(\"relationship\", \"SOLD\")\n      .option(\"relationship.save.strategy\", \"NATIVE\")\n      .option(\"relationship.source.labels\", \":Person\")\n      .option(\"relationship.target.labels\", \":Product\")\n      .option(\"relationship.source.node.keys\", \"source.id:id\")\n      .option(\"relationship.target.node.keys\", \"target.id:id\")\n      .option(\"relationship.source.save.mode\", \"Match\")\n      .option(\"relationship.target.save.mode\", \"Match\")\n      .option(\"batch.size\", \"11\")\n      .save()\n\n    val dfCopy = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"database\", \"db2\")\n      .option(\"relationship\", \"SOLD\")\n      .option(\"relationship.nodes.map\", \"false\")\n      .option(\"relationship.source.labels\", \":Person\")\n      .option(\"relationship.target.labels\", \":Product\")\n      .load()\n      .orderBy(\"`source.id`\", \"`target.id`\")\n\n    for (i <- 0 until 1) {\n      assertEquals(\n        dfOriginal.select(\"`source.id`\").collectAsList().get(i).getLong(0),\n        dfCopy.select(\"`source.id`\").collectAsList().get(i).getLong(0)\n      )\n      assertEquals(\n        dfOriginal.select(\"`target.id`\").collectAsList().get(i).getLong(0),\n        dfCopy.select(\"`target.id`\").collectAsList().get(i).getLong(0)\n      )\n    }\n  }\n\n  @Test\n  def `should read and write relations with MERGE and node keys`(): Unit = {\n    val total = 100\n    val fixtureQuery: String =\n      s\"\"\"UNWIND range(1, $total) as id\n         |CREATE (pr:Product {id: id * $total, name: 'Product ' + id})\n         |CREATE (pe:Person {id: id, fullName: 'Person ' + id})\n         |CREATE (pe)-[:BOUGHT{when: rand(), quantity: rand() * 1000}]->(pr)\n         |RETURN *\n    \"\"\".stripMargin\n\n    use(SparkConnectorScalaSuiteIT.session(\"system\")) { session =>\n      session.run(\"CREATE OR REPLACE DATABASE db1 WAIT 30 seconds\").consume()\n      session.run(\"CREATE OR REPLACE DATABASE db2 WAIT 30 seconds\").consume()\n    }\n\n    use(SparkConnectorScalaSuiteIT.session(\"db1\")) { session =>\n      session.run(fixtureQuery).consume()\n    }\n\n    val dfOriginal: DataFrame = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"database\", \"db1\")\n      .option(\"relationship\", \"BOUGHT\")\n      .option(\"relationship.nodes.map\", \"false\")\n      .option(\"relationship.source.labels\", \":Person\")\n      .option(\"relationship.target.labels\", \":Product\")\n      .load()\n      .orderBy(\"`source.id`\", \"`target.id`\")\n\n    dfOriginal.write\n      .format(classOf[DataSource].getName)\n      .mode(SaveMode.Overwrite)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"database\", \"db2\")\n      .option(\"relationship\", \"SOLD\")\n      .option(\"relationship.save.strategy\", \"NATIVE\")\n      .option(\"relationship.source.labels\", \":Person\")\n      .option(\"relationship.target.labels\", \":Product\")\n      .option(\"relationship.source.node.keys\", \"source.id:id\")\n      .option(\"relationship.source.save.mode\", \"Overwrite\")\n      .option(\"relationship.target.node.keys\", \"target.id:id\")\n      .option(\"relationship.target.save.mode\", \"Overwrite\")\n      .option(\"batch.size\", \"11\")\n      .save()\n\n    val dfCopy = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"database\", \"db2\")\n      .option(\"relationship\", \"SOLD\")\n      .option(\"relationship.nodes.map\", \"false\")\n      .option(\"relationship.source.labels\", \":Person\")\n      .option(\"relationship.target.labels\", \":Product\")\n      .load()\n      .orderBy(\"`source.id`\", \"`target.id`\")\n\n    for (i <- 0 until 1) {\n      assertEquals(\n        dfOriginal.select(\"`source.id`\").collectAsList().get(i).getLong(0),\n        dfCopy.select(\"`source.id`\").collectAsList().get(i).getLong(0)\n      )\n      assertEquals(\n        dfOriginal.select(\"`target.id`\").collectAsList().get(i).getLong(0),\n        dfCopy.select(\"`target.id`\").collectAsList().get(i).getLong(0)\n      )\n    }\n  }\n\n  @Test\n  def `should read relations and write relation with match mode`(): Unit = {\n    val fixtureQuery: String =\n      s\"\"\"CREATE (m:Musician {name: \"John Bonham\", age: 32})\n         |CREATE (i:Instrument {name: \"Drums\"})\n         |RETURN *\n    \"\"\".stripMargin\n\n    SparkConnectorScalaSuiteIT.driver.session(SessionConfig.forDatabase(\"db1\"))\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(fixtureQuery).consume()\n        }\n      )\n\n    val musicDf = Seq(\n      (12, 32, \"John Bonham\", \"Drums\")\n    ).toDF(\"experience\", \"age\", \"name\", \"instrument\")\n\n    musicDf.write\n      .format(classOf[DataSource].getName)\n      .mode(SaveMode.Overwrite)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"database\", \"db1\")\n      .option(\"relationship.nodes.map\", \"false\")\n      .option(\"relationship\", \"PLAYS\")\n      .option(\"relationship.source.save.mode\", \"Match\")\n      .option(\"relationship.target.save.mode\", \"Match\")\n      .option(\"relationship.save.strategy\", \"keys\")\n      .option(\"relationship.source.labels\", \":Musician\")\n      .option(\"relationship.source.node.keys\", \"name,age\")\n      .option(\"relationship.target.labels\", \":Instrument\")\n      .option(\"relationship.target.node.keys\", \"instrument:name\")\n      .save()\n\n    val df2 = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"database\", \"db1\")\n      .option(\"relationship.nodes.map\", \"false\")\n      .option(\"relationship\", \"PLAYS\")\n      .option(\"relationship.source.labels\", \":Musician\")\n      .option(\"relationship.target.labels\", \":Instrument\")\n      .load()\n\n    val experience = df2.select(\"`source.age`\").where(\"`source.name` = 'John Bonham'\")\n      .collectAsList().get(0).getLong(0)\n\n    assertEquals(32, experience)\n  }\n\n  @Test\n  def `should give a more clear error if properties or keys are inverted`(): Unit = {\n    val musicDf = Seq(\n      (1, 12, \"John Henry Bonham\", \"Drums\"),\n      (2, 19, \"John Mayer\", \"Guitar\"),\n      (3, 32, \"John Scofield\", \"Guitar\"),\n      (4, 15, \"John Butler\", \"Guitar\")\n    ).toDF(\"id\", \"experience\", \"name\", \"instrument\")\n\n    try {\n      musicDf.write\n        .format(classOf[DataSource].getName)\n        .mode(SaveMode.Overwrite)\n        .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n        .option(\"database\", \"db1\")\n        .option(\"relationship\", \"PLAYS\")\n        .option(\"relationship.source.save.mode\", \"Overwrite\")\n        .option(\"relationship.target.save.mode\", \"Overwrite\")\n        .option(\"relationship.save.strategy\", \"keys\")\n        .option(\"relationship.source.labels\", \":Musician\")\n        .option(\"relationship.source.node.keys\", \"musician_name:name\")\n        .option(\"relationship.target.labels\", \":Instrument\")\n        .option(\"relationship.target.node.keys\", \"instrument:name\")\n        .save()\n    } catch {\n      case exception: IllegalArgumentException => {\n        val clientException = ExceptionUtils.getRootCause(exception)\n        assertTrue(clientException.getMessage.equals(\n          \"\"\"Write failed due to the following errors:\n            | - Schema is missing musician_name from option `relationship.source.node.keys`\n            |\n            |The option key and value might be inverted.\"\"\".stripMargin\n        ))\n      }\n      case generic: Throwable =>\n        fail(s\"should be thrown a ${classOf[IllegalArgumentException].getName}, got ${generic.getClass} instead\")\n    }\n  }\n\n  @Test\n  def `should give a more clear error if properties or keys are inverted on different options`(): Unit = {\n    val musicDf = Seq(\n      (1, 12, \"John Henry Bonham\", \"Drums\"),\n      (2, 19, \"John Mayer\", \"Guitar\"),\n      (3, 32, \"John Scofield\", \"Guitar\"),\n      (4, 15, \"John Butler\", \"Guitar\")\n    ).toDF(\"id\", \"experience\", \"name\", \"instrument\")\n\n    try {\n      musicDf.write\n        .format(classOf[DataSource].getName)\n        .mode(SaveMode.Overwrite)\n        .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n        .option(\"database\", \"db1\")\n        .option(\"relationship\", \"PLAYS\")\n        .option(\"relationship.source.save.mode\", \"Overwrite\")\n        .option(\"relationship.target.save.mode\", \"Overwrite\")\n        .option(\"relationship.save.strategy\", \"keys\")\n        .option(\"relationship.source.labels\", \":Musician\")\n        .option(\"relationship.source.node.keys\", \"musician_name:name,another_name:name\")\n        .option(\"relationship.target.labels\", \":Instrument\")\n        .option(\"relationship.target.node.keys\", \"instrument_name:name\")\n        .save()\n    } catch {\n      case exception: IllegalArgumentException => {\n        val clientException = ExceptionUtils.getRootCause(exception)\n        assertTrue(clientException.getMessage.equals(\n          \"\"\"Write failed due to the following errors:\n            | - Schema is missing instrument_name from option `relationship.target.node.keys`\n            | - Schema is missing musician_name, another_name from option `relationship.source.node.keys`\n            |\n            |The option key and value might be inverted.\"\"\".stripMargin\n        ))\n      }\n      case generic: Throwable =>\n        fail(s\"should be thrown a ${classOf[IllegalArgumentException].getName}, got ${generic.getClass} instead\")\n    }\n  }\n\n  @Test\n  def `should give a more clear error if node properties or keys are inverted`(): Unit = {\n    val musicDf = Seq(\n      (1, 12, \"John Henry Bonham\", \"Drums\"),\n      (2, 19, \"John Mayer\", \"Guitar\"),\n      (3, 32, \"John Scofield\", \"Guitar\"),\n      (4, 15, \"John Butler\", \"Guitar\")\n    ).toDF(\"id\", \"experience\", \"name\", \"instrument\")\n\n    try {\n      musicDf.write\n        .format(classOf[DataSource].getName)\n        .mode(SaveMode.Append)\n        .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n        .option(\"database\", \"db1\")\n        .option(\"labels\", \"Person\")\n        .option(\"node.properties\", \"musician_name:name,another_name:name\")\n        .save()\n    } catch {\n      case exception: IllegalArgumentException => {\n        val clientException = ExceptionUtils.getRootCause(exception)\n        assertTrue(clientException.getMessage.equals(\n          \"\"\"Write failed due to the following errors:\n            | - Schema is missing instrument_name from option `node.properties`\n            |\n            |The option key and value might be inverted.\"\"\".stripMargin\n        ))\n      }\n      case generic: Throwable => fail(\n          s\"should be thrown a ${classOf[IllegalArgumentException].getName}, got ${generic.getClass} instead: ${generic.getMessage}\"\n        )\n    }\n  }\n\n  @Test\n  def `exports write metrics`(): Unit = {\n    val input = List(\"Ali\", \"Andrea\", \"Eugene\", \"Florent\")\n    val query = \"CREATE (:Name {name: event.name})-[:STARTS_WITH]->(:Letter {value: left(event.name, 1)})\"\n    val expectedMetrics = Map(\n      DataWriterMetrics.RECORDS_WRITTEN_DESCRIPTION -> 4,\n      DataWriterMetrics.RELATIONSHIPS_CREATED_DESCRIPTION -> 4,\n      DataWriterMetrics.NODES_CREATED_DESCRIPTION -> 8,\n      DataWriterMetrics.PROPERTIES_SET_DESCRIPTION -> 8\n    )\n\n    val metrics = new AtomicReference[Map[String, Any]]()\n    val listener = new MetricsListener(expectedMetrics.keySet, metrics)\n    ss.sparkContext.addSparkListener(listener)\n\n    try {\n      input.toDF(\"name\")\n        .repartition(1)\n        .write\n        .format(classOf[DataSource].getName)\n        .mode(SaveMode.Append)\n        .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n        .option(\"database\", \"db1\")\n        .option(\"batch.size\", 1) // TODO: remove this when https://issues.apache.org/jira/browse/SPARK-45759 is fixed\n        .option(\"query\", query)\n        .save()\n\n      val db1Session = SparkConnectorScalaSuiteIT.driver.session(SessionConfig.forDatabase(\"db1\"))\n      Assert.assertEventually(\n        () => {\n          db1Session.run(\n            \"MATCH (:Name)-[r:STARTS_WITH]->(:Letter) RETURN count(r) as cnt\"\n          ).single().get(\"cnt\").asLong()\n        },\n        Matchers.equalTo(4L),\n        30L,\n        TimeUnit.SECONDS\n      )\n      assertNotNull(metrics.get())\n      assertEquals(metrics.get(), expectedMetrics)\n\n    } finally {\n      ss.sparkContext.removeSparkListener(listener)\n    }\n  }\n\n  @Test\n  def `does not create constraint if schema validation fails`(): Unit = {\n    val cities = Seq(\n      (1, \"Cherbourg en Cotentin\"),\n      (2, \"London\"),\n      (3, \"Malmö\")\n    ).toDF(\"id\", \"city\")\n\n    try {\n      cities.write\n        .format(classOf[DataSource].getName)\n        .mode(SaveMode.Overwrite)\n        .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n        .option(\"labels\", \":News\")\n        .option(\"node.keys\", \"newsId\")\n        .option(\"schema.optimization.node.keys\", \"UNIQUE\")\n        .save()\n    } catch {\n      case _: Exception => {}\n    }\n\n    var session: Session = null\n    try {\n      session = SparkConnectorScalaSuiteIT.driver.session()\n      val result =\n        session.run(\"SHOW CONSTRAINTS YIELD labelsOrTypes WHERE labelsOrTypes[0] = 'News' RETURN count(*) AS count\")\n          .single()\n          .get(\"count\")\n          .asLong()\n      assertEquals(0, result)\n    } finally {\n      if (session != null) {\n        session.close()\n      }\n    }\n  }\n\n  class MetricsListener(names: Set[String], captureMetrics: AtomicReference[Map[String, Any]])\n      extends SparkListener {\n\n    override def onStageSubmitted(stageSubmitted: SparkListenerStageSubmitted): Unit = {\n      stageSubmitted.stageInfo.accumulables.clear()\n    }\n\n    override def onStageCompleted(stageCompleted: SparkListenerStageCompleted): Unit = {\n      captureMetrics.set(stageCompleted\n        .stageInfo\n        .accumulables\n        .values\n        .filter(metric => metric.name.exists(names.contains))\n        .map(metric => (metric.name.get, metric.value.get))\n        .toMap)\n    }\n  }\n\n}\n"
  },
  {
    "path": "spark-3/src/test/scala/org/neo4j/spark/DataSourceWriterTSE.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark\n\nimport junitparams.JUnitParamsRunner\nimport junitparams.Parameters\nimport org.apache.commons.lang3.exception.ExceptionUtils\nimport org.apache.spark.SparkException\nimport org.apache.spark.sql.DataFrame\nimport org.apache.spark.sql.SaveMode\nimport org.apache.spark.sql.SparkSession\nimport org.apache.spark.sql.types.ArrayType\nimport org.apache.spark.sql.types.ByteType\nimport org.apache.spark.sql.types.DataType\nimport org.apache.spark.sql.types.DataTypes\nimport org.apache.spark.sql.types.DayTimeIntervalType\nimport org.apache.spark.sql.types.DecimalType\nimport org.apache.spark.sql.types.YearMonthIntervalType\nimport org.junit\nimport org.junit.Assert._\nimport org.junit.Ignore\nimport org.junit.Test\nimport org.junit.runner.RunWith\nimport org.neo4j.driver.Result\nimport org.neo4j.driver.Transaction\nimport org.neo4j.driver.TransactionWork\nimport org.neo4j.driver.Value\nimport org.neo4j.driver.exceptions.ClientException\nimport org.neo4j.driver.exceptions.value.Uncoercible\nimport org.neo4j.driver.internal.InternalPoint2D\nimport org.neo4j.driver.internal.InternalPoint3D\nimport org.neo4j.driver.internal.types.InternalTypeSystem\nimport org.neo4j.driver.summary.ResultSummary\nimport org.neo4j.driver.types.IsoDuration\nimport org.neo4j.driver.types.Type\nimport org.neo4j.spark.RowUtil.getByName\nimport org.neo4j.spark.util.Neo4jOptions\nimport org.scalatest.matchers.must.Matchers.be\nimport org.scalatest.matchers.must.Matchers.include\nimport org.scalatest.matchers.must.Matchers.the\nimport org.scalatest.matchers.should.Matchers.convertToAnyShouldWrapper\n\nimport java.time.LocalTime\nimport java.time.OffsetTime\nimport java.time.ZoneId\nimport java.time.ZoneOffset\nimport java.util.TimeZone\n\nimport scala.collection.JavaConverters._\nimport scala.collection.immutable.ListMap\nimport scala.language.postfixOps\nimport scala.math.Ordering.Implicits.infixOrderingOps\nimport scala.util.Random\n\nabstract class Neo4jType(`type`: String)\n\ncase class Duration(months: Long, days: Long, seconds: Long, nanoseconds: Long, `type`: String = \"duration\")\n    extends Neo4jType(`type`)\n\ncase class Point2d(`type`: String = \"point-2d\", srid: Int, x: Double, y: Double) extends Neo4jType(`type`)\n\ncase class Point3d(`type`: String = \"point-3d\", srid: Int, x: Double, y: Double, z: Double) extends Neo4jType(`type`)\n\ncase class Time(`type`: String = \"offset-time\", value: String) extends Neo4jType(`type`)\n\ncase class LocalTimeValue(`type`: String = \"local-time\", value: String) extends Neo4jType(`type`)\n\ncase class Person(name: String, surname: String, age: Int, livesIn: Point3d)\n\ncase class Person_TimeAndLocalTime(name: String, time: Time, localTime: LocalTimeValue)\n\ncase class SimplePerson(name: String, surname: String)\n\ncase class EmptyRow[T](data: T)\n\n@RunWith(classOf[JUnitParamsRunner])\nclass DataSourceWriterTSE extends SparkConnectorScalaBaseTSE {\n\n  val sparkSession = SparkSession.builder()\n    .master(\"local[*]\")\n    .appName(\"DataSourceWriterTSE\")\n    .getOrCreate()\n\n  import sparkSession.implicits._\n\n  private def testType[T](ds: DataFrame, neo4jType: Type): Unit = {\n    ds.write\n      .format(classOf[DataSource].getName)\n      .mode(SaveMode.Append)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"labels\", \":MyNode:MyLabel\")\n      .save()\n\n    val records = SparkConnectorScalaSuiteIT.session().run(\n      \"\"\"MATCH (p:MyNode:MyLabel)\n        |RETURN p.foo AS foo\n        |\"\"\".stripMargin\n    ).list().asScala\n      .filter(r => r.get(\"foo\").hasType(neo4jType))\n      .map(r => r.asMap().asScala)\n      .toSet\n\n    val expected = ds.collect()\n      .map(row =>\n        Map(\"foo\" -> {\n          val foo = row.getAs[T](\"foo\")\n          foo match {\n            case sqlDate: java.sql.Date           => sqlDate.toLocalDate\n            case sqlTimestamp: java.sql.Timestamp => sqlTimestamp.toInstant.atZone(ZoneOffset.UTC)\n            case _                                => foo\n          }\n        })\n      )\n      .toSet\n\n    assertEquals(expected, records)\n  }\n\n  private def testArray[T](ds: DataFrame): Unit = {\n    ds.write\n      .format(classOf[DataSource].getName)\n      .mode(SaveMode.Append)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"labels\", \":MyNode:MyLabel\")\n      .save()\n\n    val records = SparkConnectorScalaSuiteIT.session().run(\n      \"\"\"MATCH (p:MyNode:MyLabel)\n        |RETURN p.foo AS foo\n        |\"\"\".stripMargin\n    ).list().asScala\n      .filter(r => r.get(\"foo\").hasType(InternalTypeSystem.TYPE_SYSTEM.LIST()))\n      .map(r => r.get(\"foo\").asList())\n      .toSet\n    val expected = ds.collect()\n      .map(row => row.getList[T](0))\n      .toSet\n\n    assertEquals(expected, records)\n  }\n\n  private def testDurationType(ds: DataFrame, expected: Set[Duration]): Unit = {\n    ds.write\n      .format(classOf[DataSource].getName)\n      .mode(SaveMode.Append)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"labels\", \":Duration\")\n      .save()\n\n    val records = SparkConnectorScalaSuiteIT.session().run(\n      \"\"\"MATCH (d:Duration)\n        |RETURN d.duration AS duration\n        |\"\"\".stripMargin\n    ).list().asScala\n      .filter(r => r.get(\"duration\").hasType(InternalTypeSystem.TYPE_SYSTEM.DURATION()))\n      .map(r => r.get(\"duration\").asIsoDuration())\n      .map(data => Duration(data.months, data.days, data.seconds, data.nanoseconds))\n      .toSet\n\n    assertEquals(expected, records)\n  }\n\n  @Test\n  def testThrowsExceptionIfNoValidReadOptionIsSet(): Unit = {\n    try {\n      ss.read.format(classOf[DataSource].getName)\n        .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n        .load()\n        .show() // we need the action to be able to trigger the exception because of the changes in Spark 3\n    } catch {\n      case e: IllegalArgumentException =>\n        assertEquals(\"No valid option found. One of `GDS`, `LABELS`, `QUERY`, `RELATIONSHIP` is required\", e.getMessage)\n      case _: Throwable => fail(s\"should be thrown a ${classOf[IllegalArgumentException].getName}\")\n    }\n  }\n\n  @Test\n  def testThrowsExceptionIfTwoValidReadOptionAreSet(): Unit = {\n    try {\n      ss.read.format(classOf[DataSource].getName)\n        .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n        .option(\"labels\", \"Person\")\n        .option(\"relationship\", \"KNOWS\")\n        .load() // we need the action to be able to trigger the exception because of the changes in Spark 3\n    } catch {\n      case e: IllegalArgumentException =>\n        assertEquals(\n          \"You need to specify just one of these options: 'gds', 'labels', 'query', 'relationship'\",\n          e.getMessage\n        )\n      case _: Throwable => fail(s\"should be thrown a ${classOf[IllegalArgumentException].getName}\")\n    }\n  }\n\n  @Test\n  def testThrowsExceptionIfThreeValidReadOptionAreSet(): Unit = {\n    try {\n      ss.read.format(classOf[DataSource].getName)\n        .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n        .option(\"labels\", \"Person\")\n        .option(\"relationship\", \"KNOWS\")\n        .option(\"query\", \"MATCH (n) RETURN n\")\n        .load() // we need the action to be able to trigger the exception because of the changes in Spark 3\n    } catch {\n      case e: IllegalArgumentException =>\n        assertEquals(\n          \"You need to specify just one of these options: 'gds', 'labels', 'query', 'relationship'\",\n          e.getMessage\n        )\n      case _: Throwable => fail(s\"should be thrown a ${classOf[IllegalArgumentException].getName}\")\n    }\n  }\n\n  @Test\n  def `should write nodes with string values into Neo4j`(): Unit = {\n    val ds = (1 to 10)\n      .map(i => i.toString)\n      .toDF(\"foo\")\n\n    testType[String](ds, InternalTypeSystem.TYPE_SYSTEM.STRING())\n  }\n\n  @Test\n  def `should write nodes with string array values into Neo4j`(): Unit = {\n    val ds = (1 to 10)\n      .map(i => i.toString)\n      .map(i => Array(i, i))\n      .toDF(\"foo\")\n\n    testArray[String](ds)\n  }\n\n  @Test\n  def `should write nodes with int values into Neo4j`(): Unit = {\n    val ds = (1 to 10)\n      .map(i => i)\n      .toDF(\"foo\")\n\n    testType[Int](ds, InternalTypeSystem.TYPE_SYSTEM.INTEGER())\n  }\n\n  @Test\n  def `should write nodes with byte values into Neo4j`(): Unit = {\n    val ds = (1 to 10)\n      .map(_.toByte)\n      .toDF(\"foo\")\n\n    testType[Byte](ds, InternalTypeSystem.TYPE_SYSTEM.INTEGER())\n  }\n\n  @Test\n  def `should write nodes with short values into Neo4j`(): Unit = {\n    val ds = (1 to 10)\n      .map(_.toShort)\n      .toDF(\"foo\")\n\n    testType[Short](ds, InternalTypeSystem.TYPE_SYSTEM.INTEGER())\n  }\n\n  @Test\n  def `should write nodes with date values into Neo4j`(): Unit = {\n    val ds = (1 to 5)\n      .map(i => java.sql.Date.valueOf(\"2020-01-0\" + i))\n      .toDF(\"foo\")\n\n    testType[java.sql.Date](ds, InternalTypeSystem.TYPE_SYSTEM.DATE())\n  }\n\n  @Test\n  def `should write nodes with timestamp values into Neo4j`(): Unit = {\n    val ds = (1 to 5)\n      .map(i => java.sql.Timestamp.valueOf(s\"2020-01-0$i 11:11:11.11\"))\n      .toDF(\"foo\")\n\n    testType[java.sql.Timestamp](ds, InternalTypeSystem.TYPE_SYSTEM.DATE_TIME())\n  }\n\n  @Test\n  def `should write nodes with timestampNTZ values into Neo4j`(): Unit = {\n    val ds = (1 to 5)\n      .map(i => java.time.LocalDateTime.of(2020, 1, i, 11, 11, 11, 111000000))\n      .toDF(\"foo\")\n\n    testType[java.time.LocalDateTime](ds, InternalTypeSystem.TYPE_SYSTEM.LOCAL_DATE_TIME())\n  }\n\n  @Test\n  def `should write nodes with int array values into Neo4j`(): Unit = {\n    val ds = (1 to 10)\n      .map(i => i.toLong)\n      .map(i => Array(i, i))\n      .toDF(\"foo\")\n\n    testArray[Long](ds)\n  }\n\n  @Test\n  def `should write nodes with point-2d values into Neo4j`(): Unit = {\n    val ds = (1 to 10)\n      .map(i => EmptyRow(Point2d(srid = 4326, x = Random.nextDouble(), y = Random.nextDouble())))\n      .toDS()\n\n    ds.write\n      .format(classOf[DataSource].getName)\n      .mode(SaveMode.Append)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"labels\", \":MyNode:MyLabel\")\n      .save()\n\n    val records = SparkConnectorScalaSuiteIT.session().run(\n      \"\"\"MATCH (p:MyNode:MyLabel)\n        |RETURN p.data AS data\n        |\"\"\".stripMargin\n    ).list().asScala\n      .filter(r => r.get(\"data\").hasType(InternalTypeSystem.TYPE_SYSTEM.POINT()))\n      .map(r => {\n        val point = r.get(\"data\").asPoint()\n        (point.srid(), point.x(), point.y())\n      })\n      .toSet\n    val expected = ds.collect()\n      .map(point => (point.data.srid, point.data.x, point.data.y))\n      .toSet\n    assertEquals(expected, records)\n  }\n\n  @Test\n  def `should write nodes with point-2d array values into Neo4j`(): Unit = {\n    val ds = (1 to 10)\n      .map(i =>\n        EmptyRow(Seq(\n          Point2d(srid = 4326, x = Random.nextDouble(), y = Random.nextDouble()),\n          Point2d(srid = 4326, x = Random.nextDouble(), y = Random.nextDouble())\n        ))\n      )\n      .toDS()\n\n    ds.write\n      .format(classOf[DataSource].getName)\n      .mode(SaveMode.Append)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"labels\", \":MyNode:MyLabel\")\n      .save()\n\n    val records = SparkConnectorScalaSuiteIT.session().run(\n      \"\"\"MATCH (p:MyNode:MyLabel)\n        |RETURN p.data AS data\n        |\"\"\".stripMargin\n    ).list().asScala\n      .filter(r => r.get(\"data\").hasType(InternalTypeSystem.TYPE_SYSTEM.LIST()))\n      .map(r =>\n        r.get(\"data\")\n          .asList.asScala\n          .map(_.asInstanceOf[InternalPoint2D])\n          .map(point => (point.srid(), point.x(), point.y()))\n      )\n      .toSet\n    val expected = ds.collect()\n      .map(row => row.data.map(p => (p.srid, p.x, p.y)))\n      .toSet\n    assertEquals(expected, records)\n  }\n\n  @Test\n  def `should write nodes with point-3d values into Neo4j`(): Unit = {\n    val ds = (1 to 10)\n      .map(i =>\n        EmptyRow(Point3d(srid = 4979, x = Random.nextDouble(), y = Random.nextDouble(), z = Random.nextDouble()))\n      )\n      .toDS()\n\n    ds.write\n      .format(classOf[DataSource].getName)\n      .mode(SaveMode.Append)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"labels\", \":MyNode:MyLabel\")\n      .save()\n\n    val records = SparkConnectorScalaSuiteIT.session().run(\n      \"\"\"MATCH (p:MyNode:MyLabel)\n        |RETURN p.data AS data\n        |\"\"\".stripMargin\n    ).list().asScala\n      .filter(r => r.get(\"data\").hasType(InternalTypeSystem.TYPE_SYSTEM.POINT()))\n      .map(r => {\n        val point = r.get(\"data\").asPoint()\n        (point.srid(), point.x(), point.y())\n      })\n      .toSet\n    val expected = ds.collect()\n      .map(point => (point.data.srid, point.data.x, point.data.y))\n      .toSet\n    assertEquals(expected, records)\n  }\n\n  @Test\n  def `should write nodes with point-3d array values into Neo4j`(): Unit = {\n    val ds = (1 to 10)\n      .map(i =>\n        EmptyRow(Seq(\n          Point3d(srid = 4979, x = Random.nextDouble(), y = Random.nextDouble(), z = Random.nextDouble()),\n          Point3d(srid = 4979, x = Random.nextDouble(), y = Random.nextDouble(), z = Random.nextDouble())\n        ))\n      )\n      .toDS()\n\n    ds.write\n      .format(classOf[DataSource].getName)\n      .mode(SaveMode.Append)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"labels\", \":MyNode:MyLabel\")\n      .save()\n\n    val records = SparkConnectorScalaSuiteIT.session().run(\n      \"\"\"MATCH (p:MyNode:MyLabel)\n        |RETURN p.data AS data\n        |\"\"\".stripMargin\n    ).list().asScala\n      .filter(r => r.get(\"data\").hasType(InternalTypeSystem.TYPE_SYSTEM.LIST()))\n      .map(r =>\n        r.get(\"data\")\n          .asList.asScala\n          .map(_.asInstanceOf[InternalPoint3D])\n          .map(point => (point.srid(), point.x(), point.y(), point.z()))\n      )\n      .toSet\n    val expected = ds.collect()\n      .map(row => row.data.map(p => (p.srid, p.x, p.y, p.z)))\n      .toSet\n    assertEquals(expected, records)\n  }\n\n  @Test\n  def `should write nodes with map values into Neo4j`(): Unit = {\n    val ds = (1 to 10)\n      .map(i => Map(\"field\" + i -> i))\n      .toDF(\"foo\")\n\n    ds.write\n      .format(classOf[DataSource].getName)\n      .mode(SaveMode.Append)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"labels\", \":MyNode:MyLabel\")\n      .save()\n\n    val records = SparkConnectorScalaSuiteIT.session().run(\n      \"\"\"MATCH (p:MyNode:MyLabel)\n        |RETURN p\n        |\"\"\".stripMargin\n    ).list().asScala\n      .filter(r => r.get(\"p\").hasType(InternalTypeSystem.TYPE_SYSTEM.MAP()))\n      .map(r => r.get(\"p\").asMap().asScala)\n      .toSet\n    val expected = ds.collect().map(row => row.getMap[String, AnyRef](0))\n      .map(map => map.map(t => (s\"foo.${t._1}\", t._2)).toMap)\n      .toSet\n    assertEquals(expected, records)\n  }\n\n  @Test\n  def `should write nodes with duration values into Neo4j from java period`(): Unit = {\n    val range = 1 to 10\n    val ds = range\n      .map(i => java.time.Period.ofMonths(i))\n      .toDF(\"duration\")\n\n    val expected = range\n      .map(i => Duration(i, 0, 0, 0))\n      .toSet\n\n    testDurationType(ds, expected)\n  }\n\n  @Test\n  def `should write nodes with duration values into Neo4j from java duration`(): Unit = {\n    val range = 1 to 10\n    val ds = range\n      .map(i => java.time.Duration.ofDays(i.toLong))\n      .toDF(\"duration\")\n\n    val expected = range\n      .map(i => Duration(0, i, 0, 0))\n      .toSet\n\n    testDurationType(ds, expected)\n  }\n\n  @Test\n  def `should write nodes with duration values into Neo4j from struct`(): Unit = {\n    val range = 1 to 10\n    val ds = range\n      .map(i => i.toLong)\n      .map(i => EmptyRow(Duration(i, i, i, i)))\n      .toDF(\"duration\")\n\n    val expected = range\n      .map(i => Duration(i, i, i, i))\n      .toSet\n\n    testDurationType(ds, expected)\n  }\n\n  @Test\n  def `should write nodes with duration array values into Neo4j from struct`(): Unit = {\n    val ds = (1 to 10)\n      .map(i => i.toLong)\n      .map(i =>\n        EmptyRow(Seq(\n          Duration(i, i, i, i),\n          Duration(i, i, i, i)\n        ))\n      )\n      .toDS()\n\n    ds.write\n      .format(classOf[DataSource].getName)\n      .mode(SaveMode.Append)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"labels\", \"BeanWithDuration\")\n      .save()\n\n    val records = SparkConnectorScalaSuiteIT.session().run(\n      \"\"\"MATCH (p:BeanWithDuration)\n        |RETURN p.data AS data\n        |\"\"\".stripMargin\n    ).list().asScala\n      .map(r =>\n        r.get(\"data\")\n          .asList.asScala\n          .map(_.asInstanceOf[IsoDuration])\n          .map(data => (data.months, data.days, data.seconds, data.nanoseconds))\n      )\n      .toSet\n\n    val expected = ds.collect()\n      .map(row => row.data.map(data => (data.months, data.days, data.seconds, data.nanoseconds)))\n      .toSet\n\n    assertEquals(expected, records)\n  }\n\n  private case class DurationCase(\n    intervalExpression: String,\n    expectedDuration: Duration,\n    expectedDt: Class[_ <: DataType] = classOf[DayTimeIntervalType]\n  ) {\n    private val isArithmetic = intervalExpression.startsWith(\"timestamp\")\n\n    val sql: String = if (isArithmetic) {\n      intervalExpression\n    } else {\n      s\"INTERVAL $intervalExpression\"\n    }\n  }\n\n  private def sqlDurationCases: java.util.List[DurationCase] = java.util.Arrays.asList(\n    // DAY/TIME -> DayTimeIntervalType\n    DurationCase(\"'3' DAY\", Duration(0, 3, 0, 0)),\n    DurationCase(\"'10 05' DAY TO HOUR\", Duration(0, 10, 5L * 3600, 0)),\n    DurationCase(\"'10 05:30' DAY TO MINUTE\", Duration(0, 10, 5L * 3600 + 30L * 60, 0)),\n    DurationCase(\"'10 05:30:15.123456' DAY TO SECOND\", Duration(0, 10, 5L * 3600 + 30L * 60 + 15L, 123456000)),\n    DurationCase(\"'12' HOUR\", Duration(0, 0, 12L * 3600, 0)),\n    DurationCase(\"'12:34' HOUR TO MINUTE\", Duration(0, 0, 12L * 3600 + 34L * 60, 0)),\n    DurationCase(\"'12:34:56.123456' HOUR TO SECOND\", Duration(0, 0, 12L * 3600 + 34L * 60 + 56L, 123456000)),\n    DurationCase(\"'42' MINUTE\", Duration(0, 0, 42L * 60, 0)),\n    DurationCase(\"'42:07.001002' MINUTE TO SECOND\", Duration(0, 0, 42L * 60 + 7L, 1002000)),\n    DurationCase(\"'59.000001' SECOND\", Duration(0, 0, 59L, 1000)),\n    DurationCase(\n      \"timestamp('2025-01-02 18:30:00.454') - timestamp('2024-01-01 00:00:00')\",\n      Duration(0, 367, 66600L, 454000000)\n    ),\n    // YEAR/MONTH -> YearMonthIntervalType\n    DurationCase(\"'3' YEAR\", Duration(36, 0, 0, 0), classOf[YearMonthIntervalType]),\n    DurationCase(\"'7' MONTH\", Duration(7, 0, 0, 0), classOf[YearMonthIntervalType]),\n    DurationCase(\"'4-5' YEAR TO MONTH\", Duration(53, 0, 0, 0), classOf[YearMonthIntervalType])\n  )\n\n  @Test\n  @Parameters(method = \"sqlDurationCases\")\n  def `interval SQL literals map to native neo4j durations`(testCase: DurationCase): Unit = {\n    val id = java.util.UUID.randomUUID().toString\n    val df = sparkSession.sql(s\"SELECT '$id' AS id, ${testCase.sql} AS duration\")\n\n    df.write\n      .format(classOf[DataSource].getName)\n      .mode(SaveMode.Append)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"labels\", \"Dur\")\n      .save()\n\n    val wantType = testCase.expectedDt.getSimpleName\n    val gotType = df.schema(\"duration\").dataType\n    assertTrue(s\"expected Spark to pick $wantType but it was $gotType\", testCase.expectedDt.isInstance(gotType))\n\n    val gotDuration = SparkConnectorScalaSuiteIT.session().run(\n      s\"\"\"MATCH (d:Dur {id: '$id'})\n         |RETURN d.duration AS duration\n         |\"\"\".stripMargin\n    ).single().get(\"duration\").asIsoDuration()\n\n    assertEquals(s\"${testCase.sql} -> months\", testCase.expectedDuration.months, gotDuration.months)\n    assertEquals(s\"${testCase.sql} -> days\", testCase.expectedDuration.days, gotDuration.days)\n    assertEquals(s\"${testCase.sql} -> seconds\", testCase.expectedDuration.seconds, gotDuration.seconds)\n    assertEquals(s\"${testCase.sql} -> nanos\", testCase.expectedDuration.nanoseconds, gotDuration.nanoseconds)\n  }\n\n  private val sqlDurationArrayCases: java.util.List[Seq[DurationCase]] = java.util.Arrays.asList(\n    Seq(\n      DurationCase(\"'10 05:30:15.123' DAY TO SECOND\", null),\n      DurationCase(\"'0 00:00:01.000' DAY TO SECOND\", null)\n    ),\n    Seq(\n      DurationCase(\"timestamp('2024-01-02 00:00:00') - timestamp('2024-01-01 00:00:00')\", null),\n      DurationCase(\"timestamp('2024-01-01 00:00:00') - current_timestamp()\", null)\n    ),\n    Seq(\n      DurationCase(\"'1-02' YEAR TO MONTH\", null, classOf[YearMonthIntervalType]),\n      DurationCase(\"'0-11' YEAR TO MONTH\", null, classOf[YearMonthIntervalType])\n    )\n  )\n\n  @Test\n  @Parameters(method = \"sqlDurationArrayCases\")\n  def `interval SQL arrays map to native neo4j durations arrays`(testCase: Seq[DurationCase]): Unit = {\n    val id = java.util.UUID.randomUUID().toString\n    val expectedDt = testCase.head.expectedDt\n    val sqlArray = testCase.map(_.sql).mkString(\"array(\", \", \", \")\")\n    val df = sparkSession.sql(s\"SELECT '$id' AS id, $sqlArray AS durations\")\n\n    df.write\n      .format(classOf[DataSource].getName)\n      .mode(SaveMode.Append)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"labels\", \"DurArr\")\n      .save()\n\n    val gotType = df.schema(\"durations\").dataType\n\n    assertTrue(\n      s\"expected Spark to infer ArrayType(${expectedDt.getSimpleName}) but it was $gotType\",\n      gotType match {\n        case ArrayType(et, _) if expectedDt.isInstance(et) => true\n        case _                                             => false\n      }\n    )\n\n    val result = SparkConnectorScalaSuiteIT.session().run(\n      s\"\"\"MATCH (d:DurArr {id: '$id'})\n         |RETURN d.durations AS durations\n         |\"\"\".stripMargin\n    ).single().get(\"durations\")\n\n    assertTrue(\n      s\"expected successful conversion to IsoDuration array, but it failed: $result\",\n      try {\n        val _ = result.asList((v: Value) => v.asIsoDuration())\n        true\n      } catch {\n        case _: Uncoercible => false\n        case e              => throw e\n      }\n    )\n  }\n\n  @Test\n  def `should write TINYINT as neo4j integer`(): Unit = {\n    val id = java.util.UUID.randomUUID().toString\n    val df = sparkSession.sql(s\"SELECT '$id' AS id, CAST(5 AS TINYINT) AS byte\")\n\n    df.write\n      .format(classOf[DataSource].getName)\n      .mode(SaveMode.Append)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"labels\", \"Byte\")\n      .save()\n\n    val wantType = DataTypes.ByteType\n    val gotType = df.schema(\"byte\").dataType\n    assertTrue(s\"expected Spark to pick ${wantType.simpleString} but it was $gotType\", wantType == gotType)\n\n    val gotByte = SparkConnectorScalaSuiteIT.session().run(\n      s\"\"\"MATCH (b:Byte {id: '$id'})\n         |RETURN b.byte AS byte\n         |\"\"\".stripMargin\n    ).single().get(\"byte\").asInt()\n\n    assertEquals(5, gotByte)\n  }\n\n  @Test\n  def `should write BINARY (byte array) as neo4j ByteArray`(): Unit = {\n    val id = java.util.UUID.randomUUID().toString\n    val sqlArray = (1 to 10).map(i => s\"CAST($i AS TINYINT)\").mkString(\"array(\", \", \", \")\")\n    val df = sparkSession.sql(s\"SELECT '$id' AS id, $sqlArray AS binary\")\n\n    df.write\n      .format(classOf[DataSource].getName)\n      .mode(SaveMode.Append)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"labels\", \"Binary\")\n      .save()\n\n    val wantType: DataType = DataTypes.ByteType\n    val gotType = df.schema(\"binary\").dataType\n\n    assertTrue(\n      s\"expected Spark to infer ArrayType(${wantType.simpleString}) but it was $gotType\",\n      gotType match {\n        case ArrayType(_: ByteType, _) => true\n        case _                         => false\n      }\n    )\n\n    val gotByteArray = SparkConnectorScalaSuiteIT.session().run(\n      s\"\"\"MATCH (b:Binary {id: '$id'})\n         |RETURN b.binary AS binary\n         |\"\"\".stripMargin\n    ).single().get(\"binary\").asByteArray()\n\n    assertEquals(10, gotByteArray.length)\n\n    for (b <- gotByteArray.indices) {\n      val expectedValue = (b + 1).toByte\n      assertEquals(expectedValue, gotByteArray(b))\n    }\n  }\n\n  @Test\n  def `should write SMALLINT as neo4j integer`(): Unit = {\n    val id = java.util.UUID.randomUUID().toString\n    val df = sparkSession.sql(s\"SELECT '$id' AS id, CAST(5 AS SMALLINT) AS short\")\n\n    df.write\n      .format(classOf[DataSource].getName)\n      .mode(SaveMode.Append)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"labels\", \"Short\")\n      .save()\n\n    val wantType = DataTypes.ShortType\n    val gotType = df.schema(\"short\").dataType\n    assertTrue(s\"expected Spark to pick ${wantType.simpleString} but it was $gotType\", wantType == gotType)\n\n    val gotByte = SparkConnectorScalaSuiteIT.session().run(\n      s\"\"\"MATCH (b:Short {id: '$id'})\n         |RETURN b.short AS short\n         |\"\"\".stripMargin\n    ).single().get(\"short\").asInt()\n\n    assertEquals(5, gotByte)\n  }\n\n  @Test\n  def `should write DECIMAL as neo4j string`(): Unit = {\n    val id = java.util.UUID.randomUUID().toString\n    val df = sparkSession.sql(s\"SELECT '$id' AS id, CAST(5.42 AS DECIMAL(10, 2)) AS decimal\")\n\n    df.write\n      .format(classOf[DataSource].getName)\n      .mode(SaveMode.Append)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"labels\", \"Decimal\")\n      .save()\n\n    val wantType = DecimalType(10, 2)\n    val gotType = df.schema(\"decimal\").dataType\n    assertTrue(s\"expected Spark to pick $wantType but it was $gotType\", wantType.typeName == gotType.simpleString)\n\n    val gotDecimal = SparkConnectorScalaSuiteIT.session().run(\n      s\"\"\"MATCH (b:Decimal {id: '$id'})\n         |RETURN b.decimal AS decimal\n         |\"\"\".stripMargin\n    ).single().get(\"decimal\").asString\n\n    assertEquals(\"5.42\", gotDecimal)\n  }\n\n  @Test\n  def `should write nodes into Neo4j with points`(): Unit = {\n    val total = 10\n    val rand = Random\n    val ds = (1 to total)\n      .map(i =>\n        Person(\n          name = \"Andrea \" + i,\n          \"Santurbano \" + i,\n          rand.nextInt(100),\n          Point3d(srid = 4979, x = 12.5811776, y = 41.9579492, z = 1.3)\n        )\n      ).toDS()\n\n    ds.write\n      .format(classOf[DataSource].getName)\n      .mode(SaveMode.Append)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"labels\", \":Person: Customer\")\n      .save()\n\n    val count = SparkConnectorScalaSuiteIT.session().run(\n      \"\"\"MATCH (p:Person:Customer)\n        |WHERE p.name STARTS WITH 'Andrea'\n        |AND p.surname STARTS WITH 'Santurbano'\n        |RETURN count(p) AS count\n        |\"\"\".stripMargin\n    ).single().get(\"count\").asInt()\n    assertEquals(total, count)\n\n    val records = SparkConnectorScalaSuiteIT.session().run(\n      \"\"\"MATCH (p:Person:Customer)\n        |WHERE p.name STARTS WITH 'Andrea'\n        |AND p.surname STARTS WITH 'Santurbano'\n        |RETURN p.name AS name, p.surname AS surname, p.age AS age,\n        | p.bornIn AS bornIn, p.livesIn AS livesIn\n        |\"\"\".stripMargin\n    ).list().asScala\n      .filter(r => {\n        val map: java.util.Map[String, Object] = r.asMap()\n        (map.get(\"name\").isInstanceOf[String]\n        && map.get(\"surname\").isInstanceOf[String]\n        && map.get(\"livesIn\").isInstanceOf[InternalPoint3D]\n        && map.get(\"age\").isInstanceOf[Long])\n      })\n    assertEquals(total, records.size)\n  }\n\n  @Test\n  def `should write nodes into Neo4j with Time and LocalTime Types`(): Unit = {\n    val total = 1\n    val rand = Random\n    val ds = (1 to total)\n      .map(i =>\n        Person_TimeAndLocalTime(\n          name = \"Andrea\",\n          time = Time(value = \"12:50:35.556000000+01:00\"),\n          localTime = LocalTimeValue(value = \"12:50:35.556000000\")\n        )\n      ).toDS()\n\n    ds.write\n      .format(classOf[DataSource].getName)\n      .mode(SaveMode.Overwrite)\n      .option(\"node.keys\", \"name\")\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"labels\", \":Person_TimeAndLocalTime\")\n      .save()\n\n    val count = SparkConnectorScalaSuiteIT.session().run(\n      \"\"\"MATCH (p:Person_TimeAndLocalTime)\n        |WHERE p.name STARTS WITH 'Andrea'        \n        |RETURN count(p) AS count\n        |\"\"\".stripMargin\n    ).single().get(\"count\").asInt()\n    assertEquals(total, count)\n\n    val records = SparkConnectorScalaSuiteIT.session().run(\n      \"\"\"MATCH (p:Person_TimeAndLocalTime)\n        |WHERE p.name STARTS WITH 'Andrea'\n        |RETURN p.name AS name, p.time AS time, p.localTime AS localTime\n        |\"\"\".stripMargin\n    ).list().asScala\n      .filter(r => {\n        val map: java.util.Map[String, Object] = r.asMap()\n        (map.get(\"name\").isInstanceOf[String]\n        && map.get(\"time\").isInstanceOf[OffsetTime]\n        && map.get(\"localTime\").isInstanceOf[LocalTime])\n      })\n    assertEquals(total, records.size)\n  }\n\n  @Test\n  def `should throw an error because the node already exists`(): Unit = {\n    SparkConnectorScalaSuiteIT.session()\n      .writeTransaction(new TransactionWork[Result] {\n        override def execute(transaction: Transaction): Result =\n          transaction.run(\"CREATE CONSTRAINT person_surname FOR (p:Person) REQUIRE p.surname IS UNIQUE\")\n      })\n    SparkConnectorScalaSuiteIT.session()\n      .writeTransaction(new TransactionWork[Result] {\n        override def execute(transaction: Transaction): Result =\n          transaction.run(\"CREATE (p:Person{name: 'Andrea', surname: 'Santurbano'})\")\n      })\n\n    val ds = Seq(SimplePerson(\"Andrea\", \"Santurbano\")).toDS()\n\n    try {\n      val thrown = the[SparkException] thrownBy {\n        ds.write\n          .format(classOf[DataSource].getName)\n          .mode(SaveMode.Append)\n          .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n          .option(\"labels\", \"Person\")\n          .save() // we need the action to be able to trigger the exception because of the changes in Spark 3\n      }\n\n      thrown.getMessage should include(\"org.neo4j.driver.exceptions.ClientException\")\n      val rootCause = ExceptionUtils.getRootCause(thrown)\n      // root cause is not always returned as a ClientException so we pass it through pattern matching to remove flakiness\n      rootCause match {\n        case c: ClientException =>\n          c.code() should be(\"Neo.ClientError.Schema.ConstraintValidationFailed\")\n        case _ =>\n      }\n    } finally {\n      SparkConnectorScalaSuiteIT.session()\n        .writeTransaction(new TransactionWork[Result] {\n          override def execute(transaction: Transaction): Result = transaction.run(\"DROP CONSTRAINT person_surname\")\n        })\n    }\n  }\n\n  @Test\n  def `should update the node that already exists`(): Unit = {\n    SparkConnectorScalaSuiteIT.session()\n      .writeTransaction(new TransactionWork[Result] {\n        override def execute(transaction: Transaction): Result =\n          transaction.run(\"CREATE CONSTRAINT person_surname FOR (p:Person) REQUIRE p.surname IS UNIQUE\")\n      })\n    SparkConnectorScalaSuiteIT.session()\n      .writeTransaction(new TransactionWork[Result] {\n        override def execute(transaction: Transaction): Result =\n          transaction.run(\"CREATE (p:Person{name: 'Federico', surname: 'Santurbano'})\")\n      })\n\n    val ds = Seq(SimplePerson(\"Andrea\", \"Santurbano\")).toDS()\n\n    ds.write\n      .format(classOf[DataSource].getName)\n      .mode(SaveMode.Overwrite)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"labels\", \"Person\")\n      .option(\"node.keys\", \"surname\")\n      .save()\n\n    val nodeList = SparkConnectorScalaSuiteIT.session()\n      .run(\n        \"\"\"MATCH (n:Person{surname: 'Santurbano'})\n          |RETURN n\n          |\"\"\".stripMargin\n      )\n      .list()\n      .asScala\n    assertEquals(1, nodeList.size)\n    assertEquals(\"Andrea\", nodeList.head.get(\"n\").asNode().get(\"name\").asString())\n\n    SparkConnectorScalaSuiteIT.session()\n      .writeTransaction(new TransactionWork[Result] {\n        override def execute(transaction: Transaction): Result = transaction.run(\"DROP CONSTRAINT person_surname\")\n      })\n  }\n\n  @Test\n  def `should skip null properties`(): Unit = {\n    val ds = Seq(SimplePerson(\"Andrea\", null)).toDS()\n\n    ds.write\n      .format(classOf[DataSource].getName)\n      .mode(SaveMode.Append)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"labels\", \"Person\")\n      .save()\n\n    val nodeList = SparkConnectorScalaSuiteIT.session()\n      .run(\n        \"\"\"MATCH (n:Person{name: 'Andrea'})\n          |RETURN n\n          |\"\"\".stripMargin\n      )\n      .list()\n      .asScala\n    assertEquals(1, nodeList.size)\n    val node = nodeList.head.get(\"n\").asNode()\n    assertFalse(\"surname should not exist\", node.asMap().containsKey(\"surname\"))\n  }\n\n  @Test\n  def `should throw an error because SaveMode.Overwrite need node.keys`(): Unit = {\n    val ds = Seq(SimplePerson(\"Andrea\", \"Santurbano\")).toDS()\n    try {\n      ds.write\n        .format(classOf[DataSource].getName)\n        .mode(SaveMode.Overwrite)\n        .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n        .option(\"labels\", \"Person\")\n        .save() // we need the action to be able to trigger the exception because of the changes in Spark 3\n    } catch {\n      case illegalArgumentException: IllegalArgumentException => {\n        assertTrue(illegalArgumentException.getMessage.equals(\n          s\"${Neo4jOptions.NODE_KEYS} is required when Save Mode is Overwrite\"\n        ))\n      }\n      case e: Throwable =>\n        fail(s\"should be thrown a ${classOf[IllegalArgumentException].getName} but is ${e.getClass.getSimpleName}\")\n    }\n  }\n\n  @Test\n  def `should write within partitions`(): Unit = {\n    val ds = (1 to 100).map(i => Person(\"Andrea \" + i, \"Santurbano \" + i, 36, null)).toDS()\n      .repartition(10)\n\n    ds.write\n      .format(classOf[DataSource].getName)\n      .mode(SaveMode.Append)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"labels\", \":Person:Customer\")\n      .option(\"batch.size\", \"11\")\n      .save()\n\n    val count = SparkConnectorScalaSuiteIT.session().run(\n      \"\"\"\n        |MATCH (p:Person:Customer)\n        |WHERE p.name STARTS WITH 'Andrea'\n        |AND p.surname STARTS WITH 'Santurbano'\n        |RETURN count(p) AS count\n        |\"\"\".stripMargin\n    ).single().get(\"count\").asInt()\n    assertEquals(100, count)\n\n    val keys = SparkConnectorScalaSuiteIT.session().run(\n      \"\"\"\n        |MATCH (p:Person:Customer)\n        |WHERE p.name STARTS WITH 'Andrea'\n        |AND p.surname STARTS WITH 'Santurbano'\n        |RETURN DISTINCT keys(p) AS keys\n        |\"\"\".stripMargin\n    ).single().get(\"keys\").asList()\n    assertEquals(Set(\"name\", \"surname\", \"age\"), keys.asScala.toSet)\n  }\n\n  @Test\n  @Ignore(\"This won't work right now because we can't know if we are in a Write or Read context\")\n  def `should throw an exception for a read only query`(): Unit = {\n    val ds = (1 to 100).map(i => Person(\"Andrea \" + i, \"Santurbano \" + i, 36, null)).toDS()\n\n    try {\n      ds.write\n        .mode(SaveMode.Overwrite)\n        .format(classOf[DataSource].getName)\n        .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n        .option(\"query\", \"MATCH (r:Read) RETURN r\")\n        .option(\"batch.size\", \"11\")\n        .save() // we need the action to be able to trigger the exception because of the changes in Spark 3\n    } catch {\n      case illegalArgumentException: IllegalArgumentException =>\n        assertTrue(illegalArgumentException.getMessage.equals(\"Please provide a valid WRITE query\"))\n      case t: Throwable => fail(\n          s\"should be thrown a ${classOf[IllegalArgumentException].getName}, but it's ${t.getClass.getSimpleName}: ${t.getMessage}\"\n        )\n    }\n  }\n\n  @Test\n  def `should insert data with a custom query`(): Unit = {\n    val ds = (1 to 100).map(i => Person(\"Andrea \" + i, \"Santurbano \" + i, 36, null)).toDS()\n\n    ds.write\n      .format(classOf[DataSource].getName)\n      .mode(SaveMode.Append)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"query\", \"CREATE (n:MyNode{fullName: event.name + event.surname, age: event.age - 10})\")\n      .option(\"batch.size\", \"11\")\n      .save()\n\n    val count = SparkConnectorScalaSuiteIT.session().run(\n      \"\"\"\n        |MATCH (p:MyNode)\n        |WHERE p.fullName CONTAINS 'Andrea'\n        |AND p.fullName CONTAINS 'Santurbano'\n        |AND p.age = 26\n        |RETURN count(p) AS count\n        |\"\"\".stripMargin\n    ).single().get(\"count\").asLong()\n    assertEquals(ds.count(), count)\n  }\n\n  @Test\n  def `should handle unusual column names`(): Unit = {\n    SparkConnectorScalaSuiteIT.session()\n      .writeTransaction(new TransactionWork[Result] {\n        override def execute(transaction: Transaction): Result =\n          transaction.run(\"CREATE CONSTRAINT instrument_name FOR (i:Instrument) REQUIRE i.name IS UNIQUE\")\n      })\n\n    val musicDf = Seq(\n      (12, \"John Bonham\", \"Drums\", \"f``````oo\"),\n      (19, \"John Mayer\", \"Guitar\", \"bar\"),\n      (32, \"John Scofield\", \"Guitar\", \"ba` z\"),\n      (15, \"John Butler\", \"Guitar\", \"qu   ux\")\n    ).toDF(\"experience\", \"name\", \"instrument\", \"fi``(╯°□°)╯︵ ┻━┻eld\")\n\n    musicDf.write\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .format(classOf[DataSource].getName)\n      .mode(SaveMode.Overwrite)\n      .option(\"relationship\", \"PLAYS\")\n      .option(\"relationship.save.strategy\", \"keys\")\n      .option(\"relationship.source.labels\", \":Musician\")\n      .option(\"relationship.source.save.mode\", \"Overwrite\")\n      .option(\"relationship.source.node.keys\", \"name\")\n      .option(\"relationship.source.node.properties\", \"fi``(╯°□°)╯︵ ┻━┻eld:field\")\n      .option(\"relationship.target.labels\", \":Instrument\")\n      .option(\"relationship.target.node.keys\", \"instrument:name\")\n      .option(\"relationship.target.save.mode\", \"Overwrite\")\n      .save()\n\n    SparkConnectorScalaSuiteIT.session()\n      .writeTransaction(new TransactionWork[Result] {\n        override def execute(transaction: Transaction): Result = transaction.run(\"DROP CONSTRAINT instrument_name\")\n      })\n\n    val musicDfCheck = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"relationship\", \"PLAYS\")\n      .option(\"relationship.nodes.map\", \"false\")\n      .option(\"relationship.source.labels\", \":Musician\")\n      .option(\"relationship.target.labels\", \":Instrument\")\n      .load()\n\n    val size = musicDfCheck.count\n    assertEquals(4, size)\n\n    val res = musicDfCheck.orderBy(\"`source.name`\").collectAsList()\n\n    assertEquals(\"John Bonham\", res.get(0).getString(4))\n    assertEquals(\"f``````oo\", res.get(0).getString(5))\n    assertEquals(\"Drums\", res.get(0).getString(8))\n\n    assertEquals(\"John Butler\", res.get(1).getString(4))\n    assertEquals(\"qu   ux\", res.get(1).getString(5))\n    assertEquals(\"Guitar\", res.get(1).getString(8))\n\n    assertEquals(\"John Mayer\", res.get(2).getString(4))\n    assertEquals(\"bar\", res.get(2).getString(5))\n    assertEquals(\"Guitar\", res.get(2).getString(8))\n\n    assertEquals(\"John Scofield\", res.get(3).getString(4))\n    assertEquals(\"ba` z\", res.get(3).getString(5))\n    assertEquals(\"Guitar\", res.get(3).getString(8))\n  }\n\n  @Test(expected = classOf[SparkException])\n  def `should give error if native mode doesn't find a valid schema`(): Unit = {\n    val musicDf = Seq(\n      (12, \"John Bonham\", \"Drums\"),\n      (19, \"John Mayer\", \"Guitar\"),\n      (32, \"John Scofield\", \"Guitar\"),\n      (15, \"John Butler\", \"Guitar\")\n    ).toDF(\"experience\", \"name\", \"instrument\")\n\n    try {\n      musicDf.write\n        .format(classOf[DataSource].getName)\n        .mode(SaveMode.Append)\n        .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n        .option(\"relationship\", \"PLAYS\")\n        .option(\"relationship.save.strategy\", \"NATIVE\")\n        .option(\"relationship.source.labels\", \":Person\")\n        .option(\"relationship.source.save.mode\", \"Overwrite\")\n        .option(\"relationship.target.labels\", \":Instrument\")\n        .option(\"relationship.target.save.mode\", \"Overwrite\")\n        .save() // we need the action to be able to trigger the exception because of the changes in Spark 3\n    } catch {\n      case sparkException: SparkException => {\n        val clientException = ExceptionUtils.getRootCause(sparkException)\n        assertTrue(clientException.getMessage.equals(\n          \"NATIVE write strategy requires a schema like: rel.[props], source.[props], target.[props]. \" +\n            \"All of these columns are empty in the current schema.\"\n        ))\n        throw sparkException\n      }\n      case _: Throwable => fail(s\"should be thrown a ${classOf[SparkException].getName}\")\n    }\n  }\n\n  @Test\n  def `should write relations with KEYS mode`(): Unit = {\n    val musicDf = Seq(\n      (12, \"John Bonham\", \"Drums\"),\n      (19, \"John Mayer\", \"Guitar\"),\n      (32, \"John Scofield\", \"Guitar\"),\n      (15, \"John Butler\", \"Guitar\")\n    ).toDF(\"experience\", \"name\", \"instrument\")\n\n    musicDf.repartition(1).write\n      .format(classOf[DataSource].getName)\n      .mode(SaveMode.Overwrite)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"relationship\", \"PLAYS\")\n      .option(\"relationship.source.save.mode\", \"Overwrite\")\n      .option(\"relationship.target.save.mode\", \"Overwrite\")\n      .option(\"relationship.save.strategy\", \"keys\")\n      .option(\"relationship.source.labels\", \":Musician\")\n      .option(\"relationship.source.node.keys\", \"name:name\")\n      .option(\"relationship.target.labels\", \":Instrument\")\n      .option(\"relationship.target.node.keys\", \"instrument:name\")\n      .save()\n\n    val df2 = ss.read.format(classOf[DataSource].getName)\n      .option(\"batch.size\", 100)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"relationship.nodes.map\", \"false\")\n      .option(\"relationship\", \"PLAYS\")\n      .option(\"relationship.source.labels\", \":Musician\")\n      .option(\"relationship.target.labels\", \":Instrument\")\n      .load()\n\n    assertEquals(4, df2.count())\n\n    val res = df2.orderBy(\"`source.name`\").collectAsList()\n\n    assertEquals(\"John Bonham\", res.get(0).getString(4))\n    assertEquals(\"Drums\", res.get(0).getString(7))\n\n    assertEquals(\"John Butler\", res.get(1).getString(4))\n    assertEquals(\"Guitar\", res.get(1).getString(7))\n\n    assertEquals(\"John Mayer\", res.get(2).getString(4))\n    assertEquals(\"Guitar\", res.get(2).getString(7))\n\n    assertEquals(\"John Scofield\", res.get(3).getString(4))\n    assertEquals(\"Guitar\", res.get(3).getString(7))\n  }\n\n  @Test\n  def `should fail validating options if ErrorIfExists is used`(): Unit = {\n    val musicDf = Seq(\n      (12, \"John Bonham\", \"Drums\"),\n      (19, \"John Mayer\", \"Guitar\"),\n      (32, \"John Scofield\", \"Guitar\"),\n      (15, \"John Butler\", \"Guitar\")\n    ).toDF(\"experience\", \"name\", \"instrument\")\n\n    try {\n      musicDf.repartition(1).write\n        .format(classOf[DataSource].getName)\n        .mode(SaveMode.Overwrite)\n        .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n        .option(\"relationship\", \"PLAYS\")\n        .option(\"relationship.source.save.mode\", \"ErrorIfExists\")\n        .option(\"relationship.target.save.mode\", \"Overwrite\")\n        .option(\"relationship.save.strategy\", \"keys\")\n        .option(\"relationship.source.labels\", \":Musician\")\n        .option(\"relationship.source.node.keys\", \"name:name\")\n        .option(\"relationship.target.labels\", \":Instrument\")\n        .option(\"relationship.target.node.keys\", \"instrument:name\")\n        .save()\n    } catch {\n      case e: IllegalArgumentException =>\n        assertEquals(\"Save mode 'ErrorIfExists' is not supported on Spark 3.0, use 'Append' instead.\", e.getMessage)\n      case _: Throwable => fail(s\"should be thrown a ${classOf[IllegalArgumentException].getName}\")\n    }\n  }\n\n  @Test\n  @Ignore(\"trying to recreate the deadlock issue\")\n  def `should give better errors if transaction fails`(): Unit = {\n    val df = List.fill(200)((\"John Bonham\", \"Drums\")).toDF(\"name\", \"instrument\")\n\n    df.write\n      .format(classOf[DataSource].getName)\n      .mode(SaveMode.Overwrite)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"relationship\", \"PLAYS\")\n      .option(\"relationship.source.save.mode\", \"Overwrite\")\n      .option(\"relationship.target.save.mode\", \"Overwrite\")\n      .option(\"relationship.save.strategy\", \"keys\")\n      .option(\"relationship.source.labels\", \":Musician\")\n      .option(\"relationship.source.node.keys\", \"name:name\")\n      .option(\"relationship.target.labels\", \":Instrument\")\n      .option(\"relationship.target.node.keys\", \"instrument:name\")\n      .save()\n\n    df.write\n      .format(classOf[DataSource].getName)\n      .mode(SaveMode.Overwrite)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"transaction.retries\", 0)\n      .option(\"partitions\", \"10\")\n      .option(\"relationship\", \"PLAYS\")\n      .option(\"relationship.source.save.mode\", \"Overwrite\")\n      .option(\"relationship.target.save.mode\", \"Overwrite\")\n      .option(\"relationship.save.strategy\", \"keys\")\n      .option(\"relationship.source.labels\", \":Musician\")\n      .option(\"relationship.source.node.keys\", \"name:name\")\n      .option(\"relationship.target.labels\", \":Instrument\")\n      .option(\"relationship.target.node.keys\", \"instrument:name\")\n      .save()\n  }\n\n  def writeKeyModeRelationshipWriteDataSet(\n    optionModifier: Map[String, String] => Map[String, String] = { m => m }\n  ): DataFrame = {\n    val musicDf = Seq(\n      (12, \"John Bonham\", \"Drums\", 2, true),\n      (19, \"John Mayer\", \"Guitar\", 1, false),\n      (32, \"John Scofield\", \"Guitar\", 3, true),\n      (15, \"John Butler\", \"Guitar\", 4, false)\n    ).toDF(\"experience\", \"name\", \"instrument\", \"rating\", \"hasDiploma\")\n\n    val options = Map(\n      \"url\" -> SparkConnectorScalaSuiteIT.server.getBoltUrl,\n      \"relationship\" -> \"PLAYS\",\n      \"relationship.source.save.mode\" -> \"Overwrite\",\n      \"relationship.target.save.mode\" -> \"Overwrite\",\n      \"relationship.save.strategy\" -> \"keys\",\n      \"relationship.source.labels\" -> \":Musician\",\n      \"relationship.source.node.keys\" -> \"name\",\n      \"relationship.target.labels\" -> \":Instrument\",\n      \"relationship.target.node.keys\" -> \"instrument:name\"\n    )\n    val modifiedOptions = optionModifier(options)\n\n    musicDf.repartition(1).write\n      .format(classOf[DataSource].getName)\n      .mode(SaveMode.Overwrite)\n      .options(modifiedOptions)\n      .save()\n\n    ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"relationship.nodes.map\", \"false\")\n      .option(\"relationship\", \"PLAYS\")\n      .option(\"relationship.source.labels\", \":Musician\")\n      .option(\"relationship.target.labels\", \":Instrument\")\n      .load()\n  }\n\n  @Test\n  def `should write relations with KEYS mode with explicitly listed properties`(): Unit = {\n    val resultDf = writeKeyModeRelationshipWriteDataSet({ options =>\n      options + (\"relationship.properties\" -> \"experience, rating:avgRating, instrument\")\n    })\n\n    resultDf.show(false)\n    assertEquals(4, resultDf.count())\n\n    val res = resultDf.orderBy(\"`source.name`\").collectAsList()\n\n    assertEquals(\"John Bonham\", getByName[String](res.get(0), \"source.name\"))\n    assertEquals(\"Drums\", getByName[String](res.get(0), \"target.name\"))\n    assertEquals(\"Drums\", getByName[String](res.get(0), \"rel.instrument\"))\n    assertEquals(12, getByName[Long](res.get(0), \"rel.experience\"))\n    assertEquals(2, getByName[Long](res.get(0), \"rel.avgRating\"))\n    assertThrows[IllegalArgumentException](\n      \"relationship should not have hasDiploma field\",\n      res.get(0).fieldIndex(\"rel.hasDiploma\")\n    )\n    assertThrows[IllegalArgumentException](\n      \"relationship should not have rating field\",\n      res.get(0).fieldIndex(\"rel.rating\")\n    )\n    assertThrows[IllegalArgumentException](\"relationship should not have name field\", res.get(0).fieldIndex(\"rel.name\"))\n\n    assertEquals(\"John Butler\", getByName[String](res.get(1), \"source.name\"))\n    assertEquals(\"Guitar\", getByName[String](res.get(1), \"target.name\"))\n    assertEquals(\"Guitar\", getByName[String](res.get(1), \"rel.instrument\"))\n    assertEquals(15, getByName[Long](res.get(1), \"rel.experience\"))\n    assertEquals(4, getByName[Long](res.get(1), \"rel.avgRating\"))\n    assertThrows[IllegalArgumentException](\n      \"relationship should not have hasDiploma field\",\n      res.get(1).fieldIndex(\"rel.hasDiploma\")\n    )\n    assertThrows[IllegalArgumentException](\n      \"relationship should not have rating field\",\n      res.get(1).fieldIndex(\"rel.rating\")\n    )\n    assertThrows[IllegalArgumentException](\"relationship should not have name field\", res.get(1).fieldIndex(\"rel.name\"))\n\n    assertEquals(\"John Mayer\", getByName[String](res.get(2), \"source.name\"))\n    assertEquals(\"Guitar\", getByName[String](res.get(2), \"target.name\"))\n    assertEquals(\"Guitar\", getByName[String](res.get(2), \"rel.instrument\"))\n    assertEquals(19, getByName[Long](res.get(2), \"rel.experience\"))\n    assertEquals(1, getByName[Long](res.get(2), \"rel.avgRating\"))\n    assertThrows[IllegalArgumentException](\n      \"relationship should not have hasDiploma field\",\n      res.get(2).fieldIndex(\"rel.hasDiploma\")\n    )\n    assertThrows[IllegalArgumentException](\n      \"relationship should not have rating field\",\n      res.get(2).fieldIndex(\"rel.rating\")\n    )\n    assertThrows[IllegalArgumentException](\"relationship should not have name field\", res.get(2).fieldIndex(\"rel.name\"))\n\n    assertEquals(\"John Scofield\", getByName[String](res.get(3), \"source.name\"))\n    assertEquals(\"Guitar\", getByName[String](res.get(3), \"target.name\"))\n    assertEquals(\"Guitar\", getByName[String](res.get(3), \"rel.instrument\"))\n    assertEquals(32, getByName[Long](res.get(3), \"rel.experience\"))\n    assertEquals(3, getByName[Long](res.get(3), \"rel.avgRating\"))\n    assertThrows[IllegalArgumentException](\n      \"relationship should not have hasDiploma field\",\n      res.get(3).fieldIndex(\"rel.hasDiploma\")\n    )\n    assertThrows[IllegalArgumentException](\n      \"relationship should not have rating field\",\n      res.get(3).fieldIndex(\"rel.rating\")\n    )\n    assertThrows[IllegalArgumentException](\"relationship should not have name field\", res.get(3).fieldIndex(\"rel.name\"))\n  }\n\n  @Test\n  def `should write relations with KEYS mode with explicitly listed empty properties`(): Unit = {\n    val resultDf = writeKeyModeRelationshipWriteDataSet({ options =>\n      options + (\"relationship.properties\" -> \"\")\n    })\n\n    resultDf.show(false)\n    assertEquals(4, resultDf.count())\n\n    val res = resultDf.orderBy(\"`source.name`\").collectAsList()\n\n    assertEquals(\"John Bonham\", getByName[String](res.get(0), \"source.name\"))\n    assertEquals(\"Drums\", getByName[String](res.get(0), \"target.name\"))\n    assertThrows[IllegalArgumentException](\n      \"relationship should not have experience field\",\n      res.get(0).fieldIndex(\"rel.experience\")\n    )\n    assertThrows[IllegalArgumentException](\n      \"relationship should not have hasDiploma field\",\n      res.get(0).fieldIndex(\"rel.hasDiploma\")\n    )\n    assertThrows[IllegalArgumentException](\n      \"relationship should not have rating field\",\n      res.get(0).fieldIndex(\"rel.rating\")\n    )\n    assertThrows[IllegalArgumentException](\"relationship should not have name field\", res.get(0).fieldIndex(\"rel.name\"))\n    assertThrows[IllegalArgumentException](\n      \"relationship should not have instrument field\",\n      res.get(0).fieldIndex(\"rel.instrument\")\n    )\n\n    assertEquals(\"John Butler\", getByName[String](res.get(1), \"source.name\"))\n    assertEquals(\"Guitar\", getByName[String](res.get(1), \"target.name\"))\n    assertThrows[IllegalArgumentException](\n      \"relationship should not have experience field\",\n      res.get(1).fieldIndex(\"rel.experience\")\n    )\n    assertThrows[IllegalArgumentException](\n      \"relationship should not have hasDiploma field\",\n      res.get(1).fieldIndex(\"rel.hasDiploma\")\n    )\n    assertThrows[IllegalArgumentException](\n      \"relationship should not have rating field\",\n      res.get(1).fieldIndex(\"rel.rating\")\n    )\n    assertThrows[IllegalArgumentException](\"relationship should not have name field\", res.get(1).fieldIndex(\"rel.name\"))\n    assertThrows[IllegalArgumentException](\n      \"relationship should not have instrument field\",\n      res.get(1).fieldIndex(\"rel.instrument\")\n    )\n\n    assertEquals(\"John Mayer\", getByName[String](res.get(2), \"source.name\"))\n    assertEquals(\"Guitar\", getByName[String](res.get(2), \"target.name\"))\n    assertThrows[IllegalArgumentException](\n      \"relationship should not have experience field\",\n      res.get(2).fieldIndex(\"rel.experience\")\n    )\n    assertThrows[IllegalArgumentException](\n      \"relationship should not have hasDiploma field\",\n      res.get(2).fieldIndex(\"rel.hasDiploma\")\n    )\n    assertThrows[IllegalArgumentException](\n      \"relationship should not have rating field\",\n      res.get(2).fieldIndex(\"rel.rating\")\n    )\n    assertThrows[IllegalArgumentException](\"relationship should not have name field\", res.get(2).fieldIndex(\"rel.name\"))\n    assertThrows[IllegalArgumentException](\n      \"relationship should not have instrument field\",\n      res.get(2).fieldIndex(\"rel.instrument\")\n    )\n\n    assertEquals(\"John Scofield\", getByName[String](res.get(3), \"source.name\"))\n    assertEquals(\"Guitar\", getByName[String](res.get(3), \"target.name\"))\n    assertThrows[IllegalArgumentException](\n      \"relationship should not have experience field\",\n      res.get(3).fieldIndex(\"rel.experience\")\n    )\n    assertThrows[IllegalArgumentException](\n      \"relationship should not have hasDiploma field\",\n      res.get(3).fieldIndex(\"rel.hasDiploma\")\n    )\n    assertThrows[IllegalArgumentException](\n      \"relationship should not have rating field\",\n      res.get(3).fieldIndex(\"rel.rating\")\n    )\n    assertThrows[IllegalArgumentException](\"relationship should not have name field\", res.get(3).fieldIndex(\"rel.name\"))\n    assertThrows[IllegalArgumentException](\n      \"relationship should not have instrument field\",\n      res.get(3).fieldIndex(\"rel.instrument\")\n    )\n  }\n\n  @Test\n  def `should write relations with KEYS mode with default properties`(): Unit = {\n    val resultDf = writeKeyModeRelationshipWriteDataSet()\n\n    resultDf.show(false)\n    assertEquals(4, resultDf.count())\n\n    val res = resultDf.orderBy(\"`source.name`\").collectAsList()\n\n    assertEquals(\"John Bonham\", getByName[String](res.get(0), \"source.name\"))\n    assertEquals(\"Drums\", getByName[String](res.get(0), \"target.name\"))\n    assertEquals(12, getByName[Long](res.get(0), \"rel.experience\"))\n    assertEquals(true, getByName[Boolean](res.get(0), \"rel.hasDiploma\"))\n    assertEquals(2, getByName[Long](res.get(0), \"rel.rating\"))\n    assertThrows[IllegalArgumentException](\"relationship should not have name field\", res.get(0).fieldIndex(\"rel.name\"))\n    assertThrows[IllegalArgumentException](\n      \"relationship should not have instrument field\",\n      res.get(0).fieldIndex(\"rel.instrument\")\n    )\n\n    assertEquals(\"John Butler\", getByName[String](res.get(1), \"source.name\"))\n    assertEquals(\"Guitar\", getByName[String](res.get(1), \"target.name\"))\n    assertEquals(15, getByName[Long](res.get(1), \"rel.experience\"))\n    assertEquals(false, getByName[Boolean](res.get(1), \"rel.hasDiploma\"))\n    assertEquals(4, getByName[Long](res.get(1), \"rel.rating\"))\n    assertThrows[IllegalArgumentException](\"relationship should not have name field\", res.get(1).fieldIndex(\"rel.name\"))\n    assertThrows[IllegalArgumentException](\n      \"relationship should not have instrument field\",\n      res.get(1).fieldIndex(\"rel.instrument\")\n    )\n\n    assertEquals(\"John Mayer\", getByName[String](res.get(2), \"source.name\"))\n    assertEquals(\"Guitar\", getByName[String](res.get(2), \"target.name\"))\n    assertEquals(19, getByName[Long](res.get(2), \"rel.experience\"))\n    assertEquals(false, getByName[Boolean](res.get(2), \"rel.hasDiploma\"))\n    assertEquals(1, getByName[Long](res.get(2), \"rel.rating\"))\n    assertThrows[IllegalArgumentException](\"relationship should not have name field\", res.get(2).fieldIndex(\"rel.name\"))\n    assertThrows[IllegalArgumentException](\n      \"relationship should not have instrument field\",\n      res.get(2).fieldIndex(\"rel.instrument\")\n    )\n\n    assertEquals(\"John Scofield\", getByName[String](res.get(3), \"source.name\"))\n    assertEquals(\"Guitar\", getByName[String](res.get(3), \"target.name\"))\n    assertEquals(32, getByName[Long](res.get(3), \"rel.experience\"))\n    assertEquals(true, getByName[Boolean](res.get(3), \"rel.hasDiploma\"))\n    assertEquals(3, getByName[Long](res.get(3), \"rel.rating\"))\n    assertThrows[IllegalArgumentException](\"relationship should not have name field\", res.get(3).fieldIndex(\"rel.name\"))\n    assertThrows[IllegalArgumentException](\n      \"relationship should not have instrument field\",\n      res.get(3).fieldIndex(\"rel.instrument\")\n    )\n  }\n\n  @Test\n  def `should read and write relations with node overwrite mode`(): Unit = {\n    val fixtureQuery: String =\n      s\"\"\"CREATE (m:Musician {id: 1, name: \"John Bonham\"})\n         |CREATE (i:Instrument {name: \"Drums\"})\n         |CREATE (m)-[:PLAYS {experience: 10}]->(i)\n         |RETURN *\n    \"\"\".stripMargin\n\n    SparkConnectorScalaSuiteIT.driver.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(fixtureQuery).consume()\n        }\n      )\n\n    val musicDf = Seq(\n      (1, 12, \"John Henry Bonham\", \"Drums\"),\n      (2, 19, \"John Mayer\", \"Guitar\"),\n      (3, 32, \"John Scofield\", \"Guitar\"),\n      (4, 15, \"John Butler\", \"Guitar\")\n    ).toDF(\"id\", \"experience\", \"name\", \"instrument\")\n\n    musicDf.write\n      .format(classOf[DataSource].getName)\n      .mode(SaveMode.Overwrite)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"relationship.nodes.map\", \"false\")\n      .option(\"relationship.source.save.mode\", \"Overwrite\")\n      .option(\"relationship.target.save.mode\", \"Overwrite\")\n      .option(\"relationship\", \"PLAYS\")\n      .option(\"relationship.properties\", \"experience\")\n      .option(\"relationship.save.strategy\", \"keys\")\n      .option(\"relationship.source.labels\", \":Musician\")\n      .option(\"relationship.source.node.keys\", \"id\")\n      .option(\"relationship.source.node.properties\", \"name\")\n      .option(\"relationship.target.labels\", \":Instrument\")\n      .option(\"relationship.target.node.keys\", \"instrument:name\")\n      .save()\n\n    val df2 = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"relationship.nodes.map\", \"false\")\n      .option(\"relationship\", \"PLAYS\")\n      .option(\"relationship.source.labels\", \":Musician\")\n      .option(\"relationship.target.labels\", \":Instrument\")\n      .load()\n\n    val result = df2.where(\"`source.id` = 1\")\n      .collectAsList().get(0)\n\n    assertEquals(12, result.getLong(9))\n    assertEquals(\"John Henry Bonham\", result.getString(4))\n  }\n\n  @Test\n  def `should insert index while insert nodes`(): Unit = {\n    val ds = (1 to 10)\n      .map(i => i.toString)\n      .toDF(\"surname\")\n\n    ds.write\n      .format(classOf[DataSource].getName)\n      .mode(SaveMode.Overwrite)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"labels\", \":Person:Customer\")\n      .option(\"node.keys\", \"surname\")\n      .option(\"schema.optimization.type\", \"INDEX\")\n      .save()\n\n    val records = SparkConnectorScalaSuiteIT.session().run(\n      \"\"\"MATCH (p:Person:Customer)\n        |RETURN p.surname AS surname\n        |\"\"\".stripMargin\n    ).list().asScala\n      .map(r => r.asMap().asScala)\n      .toSet\n    val expected = ds.collect().map(row => Map(\"surname\" -> row.getAs[String](\"surname\")))\n      .toSet\n    assertEquals(expected, records)\n\n    val indexCount = SparkConnectorScalaSuiteIT.session().run(\n      getIndexQueryCount\n    )\n      .single()\n      .get(\"count\")\n      .asLong()\n    assertEquals(1, indexCount)\n\n    SparkConnectorScalaSuiteIT.session().run(\"DROP INDEX spark_INDEX_Person_surname\")\n  }\n\n  private def getIndexQueryCount: String = {\n    val (uniqueKey, uniqueCondition) =\n      if (TestUtil.neo4jVersion(SparkConnectorScalaSuiteIT.session()) >= Versions.NEO4J_5) {\n        (\"owningConstraint\", \"owningConstraint IS NULL\")\n      } else {\n        (\"uniqueness\", \"uniqueness = 'NONUNIQUE'\")\n      }\n\n    s\"\"\"SHOW INDEXES YIELD labelsOrTypes, properties, $uniqueKey\n       |WHERE labelsOrTypes = ['Person'] AND properties = ['surname'] AND $uniqueCondition\n       |RETURN count(*) AS count\n       |\"\"\".stripMargin\n  }\n\n  private def getConstraintQueryCount: String = {\n    val (uniqueKey, uniqueCondition) =\n      if (TestUtil.neo4jVersion(SparkConnectorScalaSuiteIT.session()) >= Versions.NEO4J_5) {\n        (\"owningConstraint\", \"owningConstraint IS NOT NULL\")\n      } else {\n        (\"uniqueness\", \"uniqueness = 'UNIQUE'\")\n      }\n    s\"\"\"SHOW INDEXES YIELD labelsOrTypes, properties, $uniqueKey\n       |WHERE labelsOrTypes = ['Person'] AND properties = ['surname'] AND $uniqueCondition\n       |RETURN count(*) AS count\n       |\"\"\".stripMargin\n  }\n\n  @Test\n  def `should create constraint when insert nodes`(): Unit = {\n    val ds = (1 to 10)\n      .map(i => i.toString)\n      .toDF(\"surname\")\n\n    ds.write\n      .format(classOf[DataSource].getName)\n      .mode(SaveMode.Overwrite)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"labels\", \":Person:Customer\")\n      .option(\"node.keys\", \"surname\")\n      .option(\"schema.optimization.type\", \"NODE_CONSTRAINTS\")\n      .save()\n\n    val records = SparkConnectorScalaSuiteIT.session().run(\n      \"\"\"MATCH (p:Person:Customer)\n        |RETURN p.surname AS surname\n        |\"\"\".stripMargin\n    ).list().asScala\n      .map(r => r.asMap().asScala)\n      .toSet\n    val expected = ds.collect().map(row => Map(\"surname\" -> row.getAs[String](\"surname\")))\n      .toSet\n    assertEquals(expected, records)\n\n    val constraintCount = SparkConnectorScalaSuiteIT.session().run(\n      getConstraintQueryCount\n    )\n      .single()\n      .get(\"count\")\n      .asLong()\n    assertEquals(1, constraintCount)\n    SparkConnectorScalaSuiteIT.session().run(\"DROP CONSTRAINT spark_NODE_CONSTRAINTS_Person_surname\")\n  }\n\n  @Test\n  def `should not create constraint when insert nodes because they already exist`(): Unit = {\n    SparkConnectorScalaSuiteIT.session().run(\n      \"CREATE CONSTRAINT person_surname FOR (p:Person) REQUIRE (p.surname) IS UNIQUE\"\n    )\n\n    val ds = (1 to 10)\n      .map(i => i.toString)\n      .toDF(\"surname\")\n\n    ds.write\n      .format(classOf[DataSource].getName)\n      .mode(SaveMode.Overwrite)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"labels\", \":Person:Customer\")\n      .option(\"node.keys\", \"surname\")\n      .option(\"schema.optimization.type\", \"NODE_CONSTRAINTS\")\n      .save()\n\n    val records = SparkConnectorScalaSuiteIT.session().run(\n      \"\"\"MATCH (p:Person:Customer)\n        |RETURN p.surname AS surname\n        |\"\"\".stripMargin\n    ).list().asScala\n      .map(r => r.asMap().asScala)\n      .toSet\n    val expected = ds.collect().map(row => Map(\"surname\" -> row.getAs[String](\"surname\")))\n      .toSet\n    assertEquals(expected, records)\n\n    val constraintCount = SparkConnectorScalaSuiteIT.session().run(\n      getConstraintQueryCount\n    )\n      .single()\n      .get(\"count\")\n      .asLong()\n    assertEquals(1, constraintCount)\n    SparkConnectorScalaSuiteIT.session().run(\"DROP CONSTRAINT person_surname\")\n  }\n\n  @Test\n  def `should insert indexes while insert with query`(): Unit = {\n    val ds = (1 to 10)\n      .map(i => i.toString)\n      .toDF(\"surname\")\n\n    ds.write\n      .format(classOf[DataSource].getName)\n      .mode(SaveMode.Overwrite)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"labels\", \":Person:Customer\")\n      .option(\"node.keys\", \"surname\")\n      .option(\"schema.optimization.type\", \"INDEX\")\n      .save()\n\n    ds.write\n      .format(classOf[DataSource].getName)\n      .mode(SaveMode.Append)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"query\", \"CREATE (n:MyNode{fullName: event.name + event.surname, age: event.age - 10})\")\n      .option(\"batch.size\", \"11\")\n      .save()\n\n    val records = SparkConnectorScalaSuiteIT.session().run(\n      \"\"\"MATCH (p:Person:Customer)\n        |RETURN p.surname AS surname\n        |\"\"\".stripMargin\n    ).list().asScala\n      .map(r => r.asMap().asScala)\n      .toSet\n    val expected = ds.collect().map(row => Map(\"surname\" -> row.getAs[String](\"surname\")))\n      .toSet\n    assertEquals(expected, records)\n\n    val indexCount = SparkConnectorScalaSuiteIT.session()\n      .run(getIndexQueryCount)\n      .single()\n      .get(\"count\")\n      .asLong()\n    assertEquals(1, indexCount)\n\n    SparkConnectorScalaSuiteIT.session().run(\"DROP INDEX spark_INDEX_Person_surname\")\n  }\n\n  @Test\n  def `should manage script passing the data to the executors`(): Unit = {\n    val ds = Seq(SimplePerson(\"Andrea\", \"Santurbano\"), SimplePerson(\"Davide\", \"Fantuzzi\")).toDS()\n      .repartition(2)\n\n    ds.write\n      .format(classOf[DataSource].getName)\n      .mode(SaveMode.Append)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\n        \"query\",\n        \"CREATE (n:Person{fullName: event.name + ' ' + event.surname, age: scriptResult[0].age[event.name]})\"\n      )\n      .option(\n        \"script\",\n        \"\"\"CREATE INDEX person_surname FOR (p:Person) ON (p.surname);\n          |CREATE CONSTRAINT product_name_sku FOR (p:Product)\n          | REQUIRE (p.name, p.sku)\n          | IS NODE KEY;\n          |RETURN {Andrea: 36, Davide: 32} AS age;\n          |\"\"\".stripMargin\n      )\n      .save()\n\n    val records = SparkConnectorScalaSuiteIT.session().run(\n      \"\"\"MATCH (p:Person)\n        |WHERE (p.fullName = 'Andrea Santurbano' AND p.age = 36)\n        |OR (p.fullName = 'Davide Fantuzzi' AND p.age = 32)\n        |RETURN count(p) AS count\n        |\"\"\".stripMargin\n    )\n      .single()\n      .get(\"count\")\n      .asLong()\n    val expected = ds.count\n    assertEquals(expected, records)\n\n    val uniqueFieldName = if (TestUtil.neo4jVersion(SparkConnectorScalaSuiteIT.session()) >= Versions.NEO4J_5)\n      \"owningConstraint\"\n    else \"uniqueness\"\n    val (indexCondition, uniqueCondition) =\n      if (TestUtil.neo4jVersion(SparkConnectorScalaSuiteIT.session()) >= Versions.NEO4J_5) {\n        (s\"$uniqueFieldName IS NULL\", s\"$uniqueFieldName IS NOT NULL\")\n      } else {\n        (s\"$uniqueFieldName = 'NONUNIQUE'\", s\"$uniqueFieldName = 'UNIQUE'\")\n      }\n    val query =\n      s\"\"\"SHOW INDEXES YIELD labelsOrTypes, properties, $uniqueFieldName\n         |WHERE (labelsOrTypes = ['Person'] AND properties = ['surname'] AND $indexCondition)\n         |OR (labelsOrTypes = ['Product'] AND properties = ['name', 'sku'] AND $uniqueCondition)\n         |RETURN count(*) AS count\n         |\"\"\".stripMargin\n    val constraintCount = SparkConnectorScalaSuiteIT.session()\n      .run(query)\n      .single()\n      .get(\"count\")\n      .asLong()\n    assertEquals(2, constraintCount)\n    SparkConnectorScalaSuiteIT.session().run(\"DROP INDEX person_surname\")\n    SparkConnectorScalaSuiteIT.session().run(\"DROP CONSTRAINT product_name_sku\")\n  }\n\n  @Test\n  def `should work create source node and match target node`() {\n    val data = Seq(\n      (12, \"John Bonham\", \"Drums\"),\n      (19, \"John Mayer\", \"Guitar\"),\n      (32, \"John Scofield\", \"Guitar\"),\n      (15, \"John Butler\", \"Guitar\")\n    )\n    SparkConnectorScalaSuiteIT.session().run(\"CREATE \" + data\n      .map(_._3)\n      .toSet[String]\n      .map(instrument => s\"(:Instrument{name: '$instrument'})\")\n      .mkString(\", \"))\n    val musicDf = data.toDF(\"experience\", \"name\", \"instrument\")\n\n    musicDf.write\n      .mode(SaveMode.Overwrite)\n      .format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"relationship\", \"PLAYS\")\n      .option(\"relationship.save.strategy\", \"keys\")\n      .option(\"relationship.source.save.mode\", \"Overwrite\")\n      .option(\"relationship.source.labels\", \":Musician\")\n      .option(\"relationship.source.node.keys\", \"name\")\n      .option(\"relationship.target.save.mode\", \"match\")\n      .option(\"relationship.target.labels\", \":Instrument\")\n      .option(\"relationship.target.node.keys\", \"instrument:name\")\n      .save\n\n    val count = SparkConnectorScalaSuiteIT.session().run(\n      \"\"\"MATCH p = (:Musician)-[:PLAYS]->(:Instrument)\n        |RETURN count(p) AS count\"\"\".stripMargin\n    )\n      .single()\n      .get(\"count\")\n      .asLong()\n\n    assertEquals(data.size, count)\n  }\n\n  @Test\n  def `should work match source node and merge target node`() {\n    SparkConnectorScalaSuiteIT.session().run(\n      \"CREATE CONSTRAINT musician_name FOR (m:Musician) REQUIRE (m.name) IS UNIQUE\"\n    )\n    val data = Seq(\n      (12, \"John Bonham\", \"Drums\"),\n      (19, \"John Mayer\", \"Guitar\"),\n      (32, \"John Scofield\", \"Guitar\"),\n      (15, \"John Butler\", \"Guitar\")\n    )\n    SparkConnectorScalaSuiteIT.session().run(\"CREATE \" + data\n      .map(_._2)\n      .toSet[String]\n      .map(name => s\"(:Musician{name: '$name'})\")\n      .mkString(\", \"))\n    val musicDf = data.toDF(\"experience\", \"name\", \"instrument\")\n\n    musicDf.repartition(1).write\n      .mode(SaveMode.Overwrite)\n      .format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"relationship\", \"PLAYS\")\n      .option(\"relationship.save.strategy\", \"keys\")\n      .option(\"relationship.source.save.mode\", \"match\")\n      .option(\"relationship.source.labels\", \":Musician\")\n      .option(\"relationship.source.node.keys\", \"name\")\n      .option(\"relationship.target.save.mode\", \"overwrite\")\n      .option(\"relationship.target.labels\", \":Instrument\")\n      .option(\"relationship.target.node.keys\", \"instrument:name\")\n      .save\n\n    val count = SparkConnectorScalaSuiteIT.session().run(\n      \"\"\"MATCH p = (:Musician)-[:PLAYS]->(:Instrument)\n        |RETURN count(p) AS count\"\"\".stripMargin\n    )\n      .single()\n      .get(\"count\")\n      .asLong()\n\n    assertEquals(data.size, count)\n\n    SparkConnectorScalaSuiteIT.session().run(\"DROP CONSTRAINT musician_name\")\n  }\n\n  @Test\n  def `should work match source node and merge target node with odd chars`() {\n    val data = Seq(\n      (12, \"John Bonham\", \"Drums\"),\n      (19, \"John Mayer\", \"Guitar\"),\n      (32, \"John Scofield\", \"Guitar\"),\n      (15, \"John Butler\", \"Guitar\")\n    )\n    val musicDf = data.toDF(\"experience\", \"who:name\", \"instrument\")\n\n    musicDf.repartition(1).write\n      .mode(SaveMode.Overwrite)\n      .format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"relationship\", \"PLAYS\")\n      .option(\"relationship.save.strategy\", \"keys\")\n      .option(\"relationship.source.save.mode\", \"overwrite\")\n      .option(\"relationship.source.labels\", \":Musician\")\n      .option(\"relationship.source.node.keys\", \"`who:name`\")\n      .option(\"relationship.target.save.mode\", \"overwrite\")\n      .option(\"relationship.target.labels\", \":Instrument\")\n      .option(\"relationship.target.node.keys\", \"instrument:name\")\n      .save\n\n    val count = SparkConnectorScalaSuiteIT.session().run(\n      \"\"\"MATCH p = (:Musician)-[:PLAYS]->(:Instrument)\n        |RETURN count(p) AS count\"\"\".stripMargin\n    )\n      .single()\n      .get(\"count\")\n      .asLong()\n\n    assertEquals(data.size, count)\n  }\n\n  @Test\n  def shouldWriteComplexDF(): Unit = {\n    val data = Seq(\n      (\n        \"Cuba Gooding Jr.\",\n        1,\n        \"2022-06-07 00:00:00\",\n        Seq(Map(\"product_id\" -> 1, \"quantity\" -> 2), Map(\"product_id\" -> 2, \"quantity\" -> 4))\n      ),\n      (\n        \"Tom Hanks\",\n        2,\n        \"2022-07-07 00:00:00\",\n        Seq(Map(\"product_id\" -> 11, \"quantity\" -> 2), Map(\"product_id\" -> 22, \"quantity\" -> 4))\n      )\n    ).toDF(\"actor_name\", \"order_id\", \"order_date\", \"products\")\n    data.write\n      .mode(SaveMode.Overwrite)\n      .format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\n        \"query\",\n        \"\"\"\n          |MERGE (person:Person {name: event.actor_name})\n          |CREATE (order:Order {id: event.order_id, date: datetime(replace(event.order_date, ' ', 'T'))})\n          |MERGE (person)-[:CREATED]->(order)\n          |WITH event, person, order\n          |UNWIND event.products AS product_order\n          |MERGE (product:Product {id: product_order.product_id})\n          |CREATE (order)-[:CONTAINS{quantityOrdered: product_order.quantity}]->(product)\n          |\"\"\".stripMargin\n      )\n      .save()\n\n    val actual = SparkConnectorScalaSuiteIT.session().run(\n      \"\"\"\n        |MATCH (p:Person)-[cr:CREATED]->(o:Order)-[co:CONTAINS]->(pr:Product)\n        |WITH p, pr, o, co\n        |ORDER BY p.name, pr.id\n        |RETURN p.name AS name, o.id AS order, collect({id: pr.id, quantity: co.quantityOrdered}) AS products\n        |\"\"\".stripMargin\n    )\n      .list()\n      .asScala\n      .map(_.asMap())\n      .toSet\n      .asJava\n    val expected = Set(\n      Map(\n        \"name\" -> \"Cuba Gooding Jr.\",\n        \"order\" -> 1L,\n        \"products\" -> List(\n          Map(\"id\" -> 1L, \"quantity\" -> 2L).asJava,\n          Map(\"id\" -> 2L, \"quantity\" -> 4L).asJava\n        ).asJava\n      ).asJava,\n      Map(\n        \"name\" -> \"Tom Hanks\",\n        \"order\" -> 2L,\n        \"products\" -> List(\n          Map(\"id\" -> 11L, \"quantity\" -> 2L).asJava,\n          Map(\"id\" -> 22L, \"quantity\" -> 4L).asJava\n        ).asJava\n      ).asJava\n    ).asJava\n    assertEquals(expected, actual)\n  }\n\n  @Test\n  def shouldFix502(): Unit = {\n    val data = Seq(\n      (\"Foo\", 1, Map(\"inner\" -> Map(\"key\" -> \"innerValue\"))),\n      (\"Bar\", 1, Map(\"inner\" -> Map(\"key\" -> \"innerValue1\")))\n    ).toDF(\"id\", \"time\", \"table\")\n    data.write\n      .mode(SaveMode.Append)\n      .format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"labels\", \":MyNodeWithMapFlattend\")\n      .save()\n    val count: Long = SparkConnectorScalaSuiteIT.session().run(\n      \"\"\"\n        |MATCH (n:MyNodeWithMapFlattend)\n        |WHERE (\n        | properties(n) = {id: 'Foo', time: 1, `table.inner.key`: 'innerValue'}\n        | OR properties(n) = {id: 'Bar', time: 1, `table.inner.key`: 'innerValue1'}\n        |)\n        |RETURN count(n)\n        |\"\"\".stripMargin\n    )\n      .single()\n      .get(0)\n      .asLong()\n    junit.Assert.assertEquals(2L, count)\n  }\n\n  @Test\n  def shouldFix502WithCollisions(): Unit = {\n    val data = Seq(\n      (\"Foo\", 1, ListMap(\"key.inner\" -> Map(\"key\" -> \"innerValue\"), \"key\" -> Map(\"inner.key\" -> \"value\"))),\n      (\"Bar\", 1, ListMap(\"key.inner\" -> Map(\"key\" -> \"innerValue1\"), \"key\" -> Map(\"inner.key\" -> \"value1\")))\n    ).toDF(\"id\", \"time\", \"table\")\n    data.write\n      .mode(SaveMode.Append)\n      .format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"labels\", \":MyNodeWithMapFlattend\")\n      .save()\n    val count: Long = SparkConnectorScalaSuiteIT.session().run(\n      \"\"\"\n        |MATCH (n:MyNodeWithMapFlattend)\n        |WHERE (\n        | properties(n) = {id: 'Foo', time: 1, `table.key.inner.key`: 'value'}\n        | OR properties(n) = {id: 'Bar', time: 1, `table.key.inner.key`: 'value1'}\n        |)\n        |RETURN count(n)\n        |\"\"\".stripMargin\n    )\n      .single()\n      .get(0)\n      .asLong()\n    junit.Assert.assertEquals(2L, count)\n  }\n\n  @Test\n  def shouldFix502WithCollisionsAndAggregateValues(): Unit = {\n    val data = Seq(\n      (\"Foo\", 1, ListMap(\"key.inner\" -> Map(\"key\" -> \"innerValue\"), \"key\" -> Map(\"inner.key\" -> \"value\"))),\n      (\"Bar\", 1, ListMap(\"key.inner\" -> Map(\"key\" -> \"innerValue1\"), \"key\" -> Map(\"inner.key\" -> \"value1\")))\n    ).toDF(\"id\", \"time\", \"table\")\n    data.write\n      .mode(SaveMode.Append)\n      .format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"labels\", \":MyNodeWithMapFlattend\")\n      .option(\"schema.map.group.duplicate.keys\", true)\n      .save()\n    val count: Long = SparkConnectorScalaSuiteIT.session().run(\n      \"\"\"\n        |MATCH (n:MyNodeWithMapFlattend)\n        |WHERE (\n        | properties(n) = {id: 'Foo', time: 1, `table.key.inner.key`: ['innerValue', 'value']}\n        | OR properties(n) = {id: 'Bar', time: 1, `table.key.inner.key`: ['innerValue1', 'value1']}\n        |)\n        |RETURN count(n)\n        |\"\"\".stripMargin\n    )\n      .single()\n      .get(0)\n      .asLong()\n    junit.Assert.assertEquals(2L, count)\n  }\n\n  @Test\n  def doesNotWriteNodePropertiesToRelationship(): Unit = {\n    val data = Seq(\n      (\"john\", \"The Matrix\", \"today\"),\n      (\"jane\", \"Oppenheimer\", \"yesterday\"),\n      (\"şaban\", \"Hababam Sınıfı\", \"two days ago\")\n    ).toDF(\"username\", \"movie_title\", \"watch_time\")\n    data.write\n      .mode(SaveMode.Append)\n      .format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n      .option(\"relationship\", \"WATCHED\")\n      .option(\"relationship.save.strategy\", \"keys\")\n      .option(\"relationship.source.save.mode\", \"Overwrite\")\n      .option(\"relationship.source.labels\", \":User\")\n      .option(\"relationship.source.node.keys\", \"username:name\")\n      .option(\"relationship.target.save.mode\", \"Overwrite\")\n      .option(\"relationship.target.labels\", \":Movie\")\n      .option(\"relationship.target.node.keys\", \"movie_title:title\")\n      .save()\n    val rows = SparkConnectorScalaSuiteIT.session().run(\n      \"\"\"\n        |MATCH (:User)-[r:WATCHED]->(:Movie)\n        |WITH r\n        |ORDER BY r.watch_time ASC\n        |RETURN collect(r{.*})\n        |\"\"\".stripMargin\n    )\n      .single()\n      .get(0)\n      .asList((value: Value) => value.asMap().asScala)\n      .asScala\n    junit.Assert.assertEquals(\n      List(\n        Map(\"watch_time\" -> \"today\"),\n        Map(\"watch_time\" -> \"two days ago\"),\n        Map(\"watch_time\" -> \"yesterday\")\n      ),\n      rows\n    )\n  }\n}\n"
  },
  {
    "path": "spark-3/src/test/scala/org/neo4j/spark/DefaultConfigTSE.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark\n\nimport org.junit.Assert.assertEquals\nimport org.junit.Test\nimport org.neo4j.driver.Transaction\nimport org.neo4j.driver.TransactionWork\nimport org.neo4j.driver.summary.ResultSummary\n\nclass DefaultConfigTSE extends SparkConnectorScalaBaseTSE {\n\n  @Test\n  def `when session has default parameters it should use those instead of requiring options`(): Unit = {\n\n    SparkConnectorScalaSuiteIT.session()\n      .writeTransaction(\n        new TransactionWork[ResultSummary] {\n          override def execute(tx: Transaction): ResultSummary = tx.run(\"CREATE (p:Person {name: 'Foobar'})\").consume()\n        }\n      )\n\n    ss.conf.set(\"neo4j.url\", SparkConnectorScalaSuiteIT.server.getBoltUrl)\n\n    val df = ss.read.format(classOf[DataSource].getName)\n      .option(\"labels\", \"Person\")\n      .load()\n\n    assertEquals(df.count(), 1)\n  }\n\n}\n"
  },
  {
    "path": "spark-3/src/test/scala/org/neo4j/spark/GraphDataScienceIT.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark\n\nimport org.apache.spark.sql.types.ArrayType\nimport org.apache.spark.sql.types.DoubleType\nimport org.apache.spark.sql.types.LongType\nimport org.apache.spark.sql.types.MapType\nimport org.apache.spark.sql.types.StringType\nimport org.apache.spark.sql.types.StructField\nimport org.apache.spark.sql.types.StructType\nimport org.junit.After\nimport org.junit.Assert.assertEquals\nimport org.junit.Assert.assertTrue\nimport org.junit.Assert.fail\nimport org.junit.Assume\nimport org.junit.Test\nimport org.neo4j.Closeables.use\nimport org.neo4j.driver.Transaction\n\nimport scala.math.Ordering.Implicits.infixOrderingOps\n\nclass GraphDataScienceIT extends SparkConnectorScalaSuiteWithGdsBase {\n\n  @After\n  def cleanData(): Unit = {\n    use(SparkConnectorScalaSuiteWithGdsBase.session(\"system\")) { session =>\n      session.run(\"CREATE OR REPLACE DATABASE neo4j WAIT 30 seconds\").consume()\n    }\n\n    use(SparkConnectorScalaSuiteWithGdsBase.session()) { session =>\n      session\n        .writeTransaction((tx: Transaction) => {\n          tx.run(\n            \"\"\"\n              |CALL gds.graph.list() YIELD graphName\n              |WITH graphName AS g\n              |CALL gds.graph.drop(g) YIELD graphName\n              |RETURN *\n              |\"\"\".stripMargin\n          ).consume()\n        })\n    }\n  }\n\n  @Test\n  def shouldReturnThePageRank(): Unit = {\n    initForPageRank()\n\n    val df = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteWithGdsBase.server.getBoltUrl)\n      .option(\"gds\", \"gds.pageRank.stream\")\n      .option(\"gds.graphName\", \"myGraph\")\n      .option(\"gds.configuration.concurrency\", \"2\")\n      .load()\n    assertEquals(df.count(), 8)\n    df.show(false)\n\n    assertEquals(StructType(Array(StructField(\"nodeId\", LongType), StructField(\"score\", DoubleType))), df.schema)\n\n    val dfEstimate = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteWithGdsBase.server.getBoltUrl)\n      .option(\"gds\", \"gds.pageRank.stream.estimate\")\n      .option(\"gds.graphNameOrConfiguration\", \"myGraph\")\n      .option(\"gds.algoConfiguration.concurrency\", \"2\")\n      .load()\n    assertEquals(dfEstimate.count(), 1)\n    dfEstimate.show(false)\n\n    assertEquals(\n      StructType(\n        Array(\n          StructField(\"requiredMemory\", StringType),\n          StructField(\"treeView\", StringType),\n          StructField(\"mapView\", MapType(StringType, StringType)),\n          StructField(\"bytesMin\", LongType),\n          StructField(\"bytesMax\", LongType),\n          StructField(\"nodeCount\", LongType),\n          StructField(\"relationshipCount\", LongType),\n          StructField(\"heapPercentageMin\", DoubleType),\n          StructField(\"heapPercentageMax\", DoubleType)\n        )\n      ),\n      dfEstimate.schema\n    )\n  }\n\n  @Test\n  def shouldFailWithUnsupportedOptions(): Unit = {\n    initForPageRank()\n\n    def run(options: Map[String, String], error: String): Unit = {\n      try {\n        ss.read.format(classOf[DataSource].getName)\n          .option(\"url\", SparkConnectorScalaSuiteWithGdsBase.server.getBoltUrl)\n          .options(options)\n          .load()\n          .show(false)\n        fail(\"Expected to throw an exception\")\n      } catch {\n        case iae: IllegalArgumentException =>\n          assertTrue(iae.getMessage.equals(error))\n        case _: Throwable =>\n          fail(s\"should be thrown a ${classOf[IllegalArgumentException].getName}\")\n      }\n    }\n\n    run(\n      Map(\n        \"gds\" -> \"gds.pageRank.stream\",\n        \"gds.graphName\" -> \"myGraph\",\n        \"gds.configuration.concurrency\" -> \"2\",\n        \"partitions\" -> \"2\"\n      ),\n      \"For GDS queries we support only one partition\"\n    )\n\n    run(\n      Map(\n        \"gds\" -> \"gds.pageRank.write\",\n        \"gds.graphName\" -> \"myGraph\",\n        \"gds.configuration.concurrency\" -> \"2\"\n      ),\n      \"You cannot execute GDS mutate or write procedure in a read query\"\n    )\n\n    run(\n      Map(\n        \"gds\" -> \"gds.pageRank.mutate\",\n        \"gds.graphName\" -> \"myGraph\",\n        \"gds.configuration.concurrency\" -> \"2\"\n      ),\n      \"You cannot execute GDS mutate or write procedure in a read query\"\n    )\n  }\n\n  @Test\n  def shouldWorkWithMapReturn(): Unit = {\n    initForHits()\n\n    val procName = if (TestUtil.gdsVersion(SparkConnectorScalaSuiteWithGdsBase.session()) >= Versions.GDS_2_5)\n      \"gds.hits.stream\"\n    else \"gds.alpha.hits.stream\"\n    val df = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteWithGdsBase.server.getBoltUrl)\n      .option(\"gds\", procName)\n      .option(\"gds.graphName\", \"myGraph\")\n      .option(\"gds.configuration.hitsIterations\", \"20\")\n      .load()\n    assertEquals(df.count(), 9)\n    df.show(false)\n\n    assertEquals(\n      StructType(Array(StructField(\"nodeId\", LongType), StructField(\"values\", MapType(StringType, StringType)))),\n      df.schema\n    )\n  }\n\n  @Test\n  def shouldWorkWithPathReturn(): Unit = {\n    initForYens()\n\n    val sourceTargetNodes = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteWithGdsBase.server.getBoltUrl)\n      .option(\"labels\", \"Location\")\n      .load()\n      .where(\"name IN ('A', 'F')\")\n      .orderBy(\"name\")\n      .collect()\n\n    val (sourceId, targetId) = (sourceTargetNodes(0).getAs[Long](\"<id>\"), sourceTargetNodes(1).getAs[Long](\"<id>\"))\n\n    val df = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteWithGdsBase.server.getBoltUrl)\n      .option(\"gds\", \"gds.shortestPath.yens.stream\")\n      .option(\"gds.graphName\", \"myGraph\")\n      .option(\"gds.configuration.sourceNode\", sourceId)\n      .option(\"gds.configuration.targetNode\", targetId)\n      .option(\"gds.configuration.k\", 3)\n      .option(\"gds.configuration.relationshipWeightProperty\", \"cost\")\n      .load()\n    assertEquals(df.count(), 3)\n    df.show(false)\n\n    assertEquals(\n      StructType(\n        Array(\n          StructField(\"index\", LongType),\n          StructField(\"sourceNode\", LongType),\n          StructField(\"targetNode\", LongType),\n          StructField(\"totalCost\", DoubleType),\n          StructField(\"nodeIds\", ArrayType(LongType)),\n          StructField(\"costs\", ArrayType(DoubleType)),\n          StructField(\"path\", StringType)\n        )\n      ),\n      df.schema\n    )\n\n    val (graphNameParam, algoConfigurationParam) =\n      if (TestUtil.gdsVersion(SparkConnectorScalaSuiteWithGdsBase.session()) >= Versions.GDS_2_4)\n        (\"graphName\", \"configuration\")\n      else (\"graphNameOrConfiguration\", \"algoConfiguration\")\n    val dfEstimate = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteWithGdsBase.server.getBoltUrl)\n      .option(\"gds\", \"gds.shortestPath.yens.stream.estimate\")\n      .option(s\"gds.$graphNameParam\", \"myGraph\")\n      .option(s\"gds.$algoConfigurationParam.sourceNode\", sourceId)\n      .option(s\"gds.$algoConfigurationParam.targetNode\", targetId)\n      .option(s\"gds.$algoConfigurationParam.k\", 3)\n      .option(s\"gds.$algoConfigurationParam.relationshipWeightProperty\", \"cost\")\n      .load()\n    assertEquals(dfEstimate.count(), 1)\n    dfEstimate.show(false)\n\n    assertEquals(\n      StructType(\n        Array(\n          StructField(\"requiredMemory\", StringType),\n          StructField(\"treeView\", StringType),\n          StructField(\"mapView\", MapType(StringType, StringType)),\n          StructField(\"bytesMin\", LongType),\n          StructField(\"bytesMax\", LongType),\n          StructField(\"nodeCount\", LongType),\n          StructField(\"relationshipCount\", LongType),\n          StructField(\"heapPercentageMin\", DoubleType),\n          StructField(\"heapPercentageMax\", DoubleType)\n        )\n      ),\n      dfEstimate.schema\n    )\n  }\n\n  private def initForYens(): Unit = {\n    SparkConnectorScalaSuiteWithGdsBase.session()\n      .writeTransaction((tx: Transaction) => {\n        tx.run(\n          \"\"\"\n            |CREATE (a:Location {name: 'A'}),\n            |       (b:Location {name: 'B'}),\n            |       (c:Location {name: 'C'}),\n            |       (d:Location {name: 'D'}),\n            |       (e:Location {name: 'E'}),\n            |       (f:Location {name: 'F'}),\n            |       (a)-[:ROAD {cost: 50}]->(b),\n            |       (a)-[:ROAD {cost: 50}]->(c),\n            |       (a)-[:ROAD {cost: 100}]->(d),\n            |       (b)-[:ROAD {cost: 40}]->(d),\n            |       (c)-[:ROAD {cost: 40}]->(d),\n            |       (c)-[:ROAD {cost: 80}]->(e),\n            |       (d)-[:ROAD {cost: 30}]->(e),\n            |       (d)-[:ROAD {cost: 80}]->(f),\n            |       (e)-[:ROAD {cost: 40}]->(f);\n            |\"\"\".stripMargin\n        ).consume()\n      })\n    ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteWithGdsBase.server.getBoltUrl)\n      .option(\"gds\", \"gds.graph.project\")\n      .option(\"gds.graphName\", \"myGraph\")\n      .option(\"gds.nodeProjection\", \"Location\")\n      .option(\"gds.relationshipProjection\", \"ROAD\")\n      .option(\"gds.configuration.relationshipProperties\", \"cost\")\n      .load()\n      .show(false)\n  }\n\n  @Test\n  def shouldWorkWithKNearest(): Unit = {\n    SparkConnectorScalaSuiteWithGdsBase.session()\n      .writeTransaction((tx: Transaction) => {\n        tx.run(\n          \"\"\"\n            |CREATE (alice:Person {name: 'Alice', age: 24, lotteryNumbers: [1, 3], embedding: [1.0, 3.0]})\n            |CREATE (bob:Person {name: 'Bob', age: 73, lotteryNumbers: [1, 2, 3], embedding: [2.1, 1.6]})\n            |CREATE (carol:Person {name: 'Carol', age: 24, lotteryNumbers: [3], embedding: [1.5, 3.1]})\n            |CREATE (dave:Person {name: 'Dave', age: 48, lotteryNumbers: [2, 4], embedding: [0.6, 0.2]})\n            |CREATE (eve:Person {name: 'Eve', age: 67, lotteryNumbers: [1, 5], embedding: [1.8, 2.7]});\n            |\"\"\".stripMargin\n        ).consume()\n      })\n\n    ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteWithGdsBase.server.getBoltUrl)\n      .option(\"gds\", \"gds.graph.project\")\n      .option(\"gds.graphName\", \"myGraph\")\n      .option(\"gds.nodeProjection.Person.properties\", \"['age','lotteryNumbers','embedding']\")\n      .option(\"gds.relationshipProjection\", \"*\")\n      .load()\n      .show(false)\n\n    val df = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteWithGdsBase.server.getBoltUrl)\n      .option(\"gds\", \"gds.knn.stream\")\n      .option(\"gds.graphName\", \"myGraph\")\n      .option(\"gds.configuration.topK\", 1)\n      .option(\"gds.configuration.nodeProperties\", \"['age']\")\n      .option(\"gds.configuration.randomSeed\", 1337)\n      .option(\"gds.configuration.concurrency\", 1)\n      .option(\"gds.configuration.sampleRate\", 1.0)\n      .option(\"gds.configuration.deltaThreshold\", 0.0)\n      .load()\n\n    assertEquals(df.count(), 5)\n    df.show(false)\n\n    assertEquals(\n      StructType(\n        Array(\n          StructField(\"node1\", LongType),\n          StructField(\"node2\", LongType),\n          StructField(\"similarity\", DoubleType)\n        )\n      ),\n      df.schema\n    )\n\n    val dfEstimate = ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteWithGdsBase.server.getBoltUrl)\n      .option(\"gds\", \"gds.knn.stream.estimate\")\n      .option(\"gds.graphNameOrConfiguration\", \"myGraph\")\n      .option(\"gds.algoConfiguration.topK\", 1)\n      .option(\"gds.algoConfiguration.nodeProperties\", \"['age']\")\n      .option(\"gds.algoConfiguration.randomSeed\", 1337)\n      .option(\"gds.algoConfiguration.concurrency\", 1)\n      .option(\"gds.algoConfiguration.sampleRate\", 1.0)\n      .option(\"gds.algoConfiguration.deltaThreshold\", 0.0)\n      .load()\n    assertEquals(dfEstimate.count(), 1)\n    dfEstimate.show(false)\n\n    assertEquals(\n      StructType(\n        Array(\n          StructField(\"requiredMemory\", StringType),\n          StructField(\"treeView\", StringType),\n          StructField(\"mapView\", MapType(StringType, StringType)),\n          StructField(\"bytesMin\", LongType),\n          StructField(\"bytesMax\", LongType),\n          StructField(\"nodeCount\", LongType),\n          StructField(\"relationshipCount\", LongType),\n          StructField(\"heapPercentageMin\", DoubleType),\n          StructField(\"heapPercentageMax\", DoubleType)\n        )\n      ),\n      dfEstimate.schema\n    )\n  }\n\n  private def initForPageRank(): Unit = {\n    SparkConnectorScalaSuiteWithGdsBase.session()\n      .writeTransaction((tx: Transaction) => {\n        tx.run(\n          \"\"\"\n            |CREATE\n            |  (home:Page {name:'Home'}),\n            |  (about:Page {name:'About'}),\n            |  (product:Page {name:'Product'}),\n            |  (links:Page {name:'Links'}),\n            |  (a:Page {name:'Site A'}),\n            |  (b:Page {name:'Site B'}),\n            |  (c:Page {name:'Site C'}),\n            |  (d:Page {name:'Site D'}),\n            |\n            |  (home)-[:LINKS {weight: 0.2}]->(about),\n            |  (home)-[:LINKS {weight: 0.2}]->(links),\n            |  (home)-[:LINKS {weight: 0.6}]->(product),\n            |  (about)-[:LINKS {weight: 1.0}]->(home),\n            |  (product)-[:LINKS {weight: 1.0}]->(home),\n            |  (a)-[:LINKS {weight: 1.0}]->(home),\n            |  (b)-[:LINKS {weight: 1.0}]->(home),\n            |  (c)-[:LINKS {weight: 1.0}]->(home),\n            |  (d)-[:LINKS {weight: 1.0}]->(home),\n            |  (links)-[:LINKS {weight: 0.8}]->(home),\n            |  (links)-[:LINKS {weight: 0.05}]->(a),\n            |  (links)-[:LINKS {weight: 0.05}]->(b),\n            |  (links)-[:LINKS {weight: 0.05}]->(c),\n            |  (links)-[:LINKS {weight: 0.05}]->(d);\n            |\"\"\".stripMargin\n        ).consume()\n      })\n    ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteWithGdsBase.server.getBoltUrl)\n      .option(\"gds\", \"gds.graph.project\")\n      .option(\"gds.graphName\", \"myGraph\")\n      .option(\"gds.nodeProjection\", \"Page\")\n      .option(\"gds.relationshipProjection\", \"LINKS\")\n      .option(\"gds.configuration.relationshipProperties\", \"weight\")\n      .load()\n      .show(false)\n  }\n\n  private def initForHits(): Unit = {\n    Assume.assumeTrue(TestUtil.neo4jVersion(SparkConnectorScalaSuiteWithGdsBase.session()) >= Versions.NEO4J_5)\n    SparkConnectorScalaSuiteWithGdsBase.session()\n      .writeTransaction((tx: Transaction) => {\n        tx.run(\n          \"\"\"\n              CREATE\n            |  (a:Website {name: 'A'}),\n            |  (b:Website {name: 'B'}),\n            |  (c:Website {name: 'C'}),\n            |  (d:Website {name: 'D'}),\n            |  (e:Website {name: 'E'}),\n            |  (f:Website {name: 'F'}),\n            |  (g:Website {name: 'G'}),\n            |  (h:Website {name: 'H'}),\n            |  (i:Website {name: 'I'}),\n            |\n            |  (a)-[:LINK]->(b),\n            |  (a)-[:LINK]->(c),\n            |  (a)-[:LINK]->(d),\n            |  (b)-[:LINK]->(c),\n            |  (b)-[:LINK]->(d),\n            |  (c)-[:LINK]->(d),\n            |\n            |  (e)-[:LINK]->(b),\n            |  (e)-[:LINK]->(d),\n            |  (e)-[:LINK]->(f),\n            |  (e)-[:LINK]->(h),\n            |\n            |  (f)-[:LINK]->(g),\n            |  (f)-[:LINK]->(i),\n            |  (f)-[:LINK]->(h),\n            |  (g)-[:LINK]->(h),\n            |  (g)-[:LINK]->(i),\n            |  (h)-[:LINK]->(i);\n            |\"\"\".stripMargin\n        ).consume()\n      })\n    ss.read.format(classOf[DataSource].getName)\n      .option(\"url\", SparkConnectorScalaSuiteWithGdsBase.server.getBoltUrl)\n      .option(\"gds\", \"gds.graph.project\")\n      .option(\"gds.graphName\", \"myGraph\")\n      .option(\"gds.nodeProjection\", \"Website\")\n      .option(\"gds.relationshipProjection.LINK.indexInverse\", \"true\")\n      .load()\n      .show(false)\n  }\n}\n"
  },
  {
    "path": "spark-3/src/test/scala/org/neo4j/spark/ReauthenticationIT.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark\n\nimport org.junit.AfterClass\nimport org.junit.Assert.assertEquals\nimport org.junit.BeforeClass\nimport org.junit.Test\nimport org.neo4j.Neo4jContainerExtension\nimport org.neo4j.driver.AuthTokens\nimport org.neo4j.driver.Driver\nimport org.neo4j.driver.GraphDatabase\nimport org.neo4j.spark.ReauthenticationIT.KEYCLOAK\nimport org.neo4j.spark.ReauthenticationIT.NEO4J\nimport org.neo4j.spark.SparkConnectorScalaSuiteIT.ss\nimport org.slf4j.LoggerFactory\nimport org.testcontainers.containers.GenericContainer\nimport org.testcontainers.containers.Network\nimport org.testcontainers.containers.output.Slf4jLogConsumer\nimport org.testcontainers.containers.wait.strategy.Wait\nimport org.testcontainers.containers.wait.strategy.WaitAllStrategy\nimport org.testcontainers.utility.MountableFile\n\nimport java.time.Duration.ofMinutes\n\nobject ReauthenticationIT {\n\n  private val log = LoggerFactory.getLogger(classOf[ReauthenticationIT])\n\n  private class TestKeycloakContainer(image: String) extends GenericContainer[TestKeycloakContainer](image) {\n    def getHttpPort: Integer = this.getMappedPort(8080)\n  }\n\n  private val NETWORK = Network.newNetwork\n\n  private val KEYCLOAK = new TestKeycloakContainer(\"quay.io/keycloak/keycloak:26.2.5\")\n    .withNetwork(NETWORK)\n    .withEnv(\"KC_BOOTSTRAP_ADMIN_USERNAME\", \"admin\")\n    .withEnv(\"KC_BOOTSTRAP_ADMIN_PASSWORD\", \"admin\")\n    .withNetworkAliases(\"keycloak\")\n    .withExposedPorts(8080, 9000, 8443)\n    .withCopyFileToContainer(\n      MountableFile.forClasspathResource(\"/neo4j-keycloak.jks\"),\n      \"/opt/keycloak/conf/server.keystore\"\n    )\n    .withEnv(\"KC_HTTPS_KEY_STORE_FILE\", \"/opt/keycloak/conf/server.keystore\")\n    .withEnv(\"KC_HTTPS_KEY_STORE_PASSWORD\", \"testpwd\")\n    .withEnv(\"KC_HTTPS_KEY_PASSWORD\", \"testpwd\")\n    .withEnv(\"KC_HEALTH_ENABLED\", \"true\")\n    .withCopyFileToContainer(\n      MountableFile.forClasspathResource(\"/neo4j-sso-test-realm.json\"),\n      \"/opt/keycloak/data/import/neo4j-sso-test-realm.json\"\n    )\n    .withEnv(\"KC_HOSTNAME\", \"https://keycloak:8443\")\n    .withEnv(\"KC_HOSTNAME_BACKCHANNEL_DYNAMIC\", \"true\")\n    .waitingFor(\n      new WaitAllStrategy(WaitAllStrategy.Mode.WITH_INDIVIDUAL_TIMEOUTS_ONLY)\n        .withStrategy(Wait.forListeningPort().withStartupTimeout(ofMinutes(2)))\n        .withStrategy(\n          Wait.forHttp(\"/health/started\")\n            .forPort(9000)\n            .usingTls()\n            .allowInsecure()\n            .forStatusCode(200)\n            .withStartupTimeout(java.time.Duration.ofMinutes(5))\n        )\n    )\n    .withStartupAttempts(3)\n    .withLogConsumer(new Slf4jLogConsumer(log))\n    .withCommand(\"start-dev --import-realm\")\n\n  private val NEO4J = new Neo4jContainerExtension()\n    .withNetwork(NETWORK)\n    .withEnv(\"NEO4J_ACCEPT_LICENSE_AGREEMENT\", \"yes\")\n    .withCopyFileToContainer(MountableFile.forClasspathResource(\"/neo4j-keycloak.jks\"), \"/tmp/keycloak.jks\")\n    .withEnv(\n      \"_JAVA_OPTIONS\",\n      \"-Djavax.net.ssl.keyStore=/tmp/keycloak.jks -Djavax.net.ssl.keyStorePassword=testpwd -Djavax.net.ssl.trustStore=/tmp/keycloak.jks -Djavax.net.ssl.trustStorePassword=testpwd\"\n    )\n    .withNeo4jConfig(\"dbms.security.authentication_providers\", \"oidc-keycloak,native\")\n    .withNeo4jConfig(\"dbms.security.authorization_providers\", \"oidc-keycloak,native\")\n    .withNeo4jConfig(\"dbms.security.oidc.keycloak.display_name\", \"Keycloak\")\n    .withNeo4jConfig(\"dbms.security.oidc.keycloak.auth_flow\", \"pkce\")\n    .withNeo4jConfig(\n      \"dbms.security.oidc.keycloak.well_known_discovery_uri\",\n      \"https://keycloak:8443/realms/neo4j-sso-test/.well-known/openid-configuration\"\n    )\n    .withNeo4jConfig(\n      \"dbms.security.oidc.keycloak.params\",\n      \"client_id=neo4j-commons-client;response_type=code;scope=openid email roles\"\n    )\n    .withNeo4jConfig(\"dbms.security.oidc.keycloak.audience\", \"account\")\n    .withNeo4jConfig(\"dbms.security.oidc.keycloak.issuer\", \"https://keycloak:8443/realms/neo4j-sso-test\")\n    .withNeo4jConfig(\"dbms.security.oidc.keycloak.client_id\", \"neo4j-commons-client\")\n    .withNeo4jConfig(\"dbms.security.oidc.keycloak.claims.username\", \"preferred_username\")\n    .withNeo4jConfig(\"dbms.security.oidc.keycloak.claims.groups\", \"groups\")\n    .withNeo4jConfig(\"dbms.security.auth_cache_ttl\", \"1s\")\n\n  @BeforeClass\n  def setUp(): Unit = {\n    KEYCLOAK.start()\n    NEO4J.start()\n  }\n\n  @AfterClass\n  def tearDown() = {\n    TestUtil.closeSafely(NEO4J)\n    TestUtil.closeSafely(KEYCLOAK)\n    TestUtil.closeSafely(NETWORK)\n  }\n}\n\nclass ReauthenticationIT extends SparkConnectorScalaSuiteIT {\n\n  @Test\n  def createAnInstanceOfReAuthDriver(): Unit = {\n    val options = Map(\n      \"url\" -> NEO4J.getBoltUrl,\n      \"authentication.type\" -> \"keycloak\",\n      \"authentication.keycloak.username\" -> \"john-tester\",\n      \"authentication.keycloak.password\" -> \"testerpwd\",\n      \"authentication.keycloak.authServerUrl\" ->\n        s\"http://${KEYCLOAK.getHost}:${KEYCLOAK.getHttpPort}\",\n      \"authentication.keycloak.realm\" -> \"neo4j-sso-test\",\n      \"authentication.keycloak.clientId\" -> \"neo4j-commons-client\",\n      \"authentication.keycloak.clientSecret\" -> \"QNrSpbh0mxhnlYlI21UcBaz3Htb734vi\"\n    )\n\n    var driver: Driver = null\n    try {\n      driver = GraphDatabase.driver(NEO4J.getBoltUrl, AuthTokens.basic(\"neo4j\", NEO4J.getAdminPassword))\n      driver.session().run(\" CREATE (n:Test {field: 42}) CREATE (t:Test {field: 45})\").consume()\n    } finally {\n      driver.close()\n    }\n\n    val df = ss.read.format(classOf[DataSource].getName)\n      .options(options)\n      .option(\"query\", \"MATCH (t:Test {field: 42}) RETURN t.field\")\n      .load()\n      .toDF()\n    assertEquals(42, df.first().getLong(0))\n\n    Thread.sleep(4000)\n    val df2 = ss.read.format(classOf[DataSource].getName)\n      .options(options)\n      .option(\"query\", \"MATCH (t:Test {field: 45}) RETURN t.field\")\n      .load()\n      .toDF()\n    assertEquals(45, df2.first().getLong(0))\n  }\n\n}\n"
  },
  {
    "path": "spark-3/src/test/scala/org/neo4j/spark/SparkConnector30ScalaSuiteIT.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark\n\nimport org.junit.runner.RunWith\nimport org.junit.runners.Suite\n\n@RunWith(classOf[Suite])\n@Suite.SuiteClasses(Array(\n  classOf[DataSourceReaderTSE],\n  classOf[DataSourceReaderNeo4jTSE],\n  classOf[DataSourceWriterNeo4jTSE],\n  classOf[DataSourceWriterTSE],\n  classOf[DataSourceSchemaWriterTSE],\n  classOf[DefaultConfigTSE],\n  classOf[DataSourceStreamingReaderTSE],\n  classOf[DataSourceStreamingWriterTSE],\n  classOf[DataSourceReaderAggregationTSE]\n))\nclass SparkConnector30ScalaSuiteIT extends SparkConnectorScalaSuiteIT {}\n"
  },
  {
    "path": "spark-3/src/test/scala/org/neo4j/spark/SparkConnector30ScalaSuiteWithApocIT.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark\n\nimport org.junit.runner.RunWith\nimport org.junit.runners.Suite\n\n@RunWith(classOf[Suite])\n@Suite.SuiteClasses(Array(\n  classOf[DataSourceReaderWithApocTSE],\n  classOf[DataSourceReaderNeo4jWithApocTSE],\n  classOf[DataSourceReaderAggregationTSE]\n))\nclass SparkConnector30ScalaSuiteWithApocIT extends SparkConnectorScalaSuiteWithApocIT {}\n"
  },
  {
    "path": "spark-3/src/test/scala/org/neo4j/spark/SparkConnectorAuraTest.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark\n\nimport org.apache.spark.SparkConf\nimport org.apache.spark.sql.SparkSession\nimport org.junit.AfterClass\nimport org.junit.Assert._\nimport org.junit.Assume.assumeTrue\nimport org.junit.Before\nimport org.junit.BeforeClass\nimport org.junit.Test\nimport org.neo4j.Closeables.use\nimport org.neo4j.driver._\nimport org.neo4j.spark.SparkConnectorAuraTest._\n\nobject SparkConnectorAuraTest {\n  private var neo4j: Driver = _\n  private val username: Option[String] = Option[String](System.getenv(\"AURA_USER\"))\n  private val password: Option[String] = Option[String](System.getenv(\"AURA_PASSWORD\"))\n  private val url: Option[String] = Option[String](System.getenv(\"AURA_URI\"))\n\n  var sparkSession: SparkSession = _\n\n  @BeforeClass\n  def setUpClass(): Unit = {\n    assumeTrue(username.isDefined)\n    assumeTrue(password.isDefined)\n    assumeTrue(url.isDefined)\n\n    sparkSession = SparkSession.builder()\n      .config(new SparkConf()\n        .setAppName(\"neoTest\")\n        .setMaster(\"local[*]\")\n        .set(\"spark.driver.host\", \"127.0.0.1\"))\n      .getOrCreate()\n\n    neo4j = GraphDatabase.driver(url.get, AuthTokens.basic(username.get, password.get))\n  }\n\n  @AfterClass\n  def tearDown(): Unit = {\n    TestUtil.closeSafely(neo4j)\n    TestUtil.closeSafely(sparkSession)\n  }\n}\n\nclass SparkConnectorAuraTest {\n\n  val ss: SparkSession = SparkSession.builder().getOrCreate()\n\n  import ss.implicits._\n\n  @Before\n  def setUp(): Unit = {\n    use(neo4j.session(SessionConfig.forDatabase(\"system\"))) {\n      session =>\n        session.run(\"CREATE OR REPLACE DATABASE neo4j WAIT 30 seconds\").consume()\n    }\n  }\n\n  @Test\n  def shouldWriteToAndReadFromAura(): Unit = {\n    val df = Seq((\"John Bonham\", \"Drums\", 12), (\"John Mayer\", \"Guitar\", 8))\n      .toDF(\"name\", \"instrument\", \"experience\")\n\n    df.write\n      .mode(\"Overwrite\")\n      .format(classOf[DataSource].getName)\n      .option(\"url\", url.get)\n      .option(\"authentication.type\", \"basic\")\n      .option(\"authentication.basic.username\", username.get)\n      .option(\"authentication.basic.password\", password.get)\n      .option(\"relationship\", \"PLAYS\")\n      .option(\"relationship.source.save.mode\", \"Append\")\n      .option(\"relationship.target.save.mode\", \"Append\")\n      .option(\"relationship.save.strategy\", \"keys\")\n      .option(\"relationship.source.labels\", \":Musician\")\n      .option(\"relationship.source.node.keys\", \"name:name\")\n      .option(\"relationship.target.labels\", \":Instrument\")\n      .option(\"relationship.target.node.keys\", \"instrument:name\")\n      .save()\n\n    val results = sparkSession.read.format(classOf[DataSource].getName)\n      .option(\"url\", url.get)\n      .option(\"authentication.type\", \"basic\")\n      .option(\"authentication.basic.username\", username.get)\n      .option(\"authentication.basic.password\", password.get)\n      .option(\"labels\", \"Musician\")\n      .load()\n      .collectAsList()\n\n    assertEquals(2, results.size())\n  }\n}\n"
  },
  {
    "path": "spark-3/src/test/scala/org/neo4j/spark/TransactionTimeoutIT.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark\n\nimport org.apache.spark.SparkException\nimport org.apache.spark.sql.SparkSession\nimport org.junit.AfterClass\nimport org.junit.Assert.assertEquals\nimport org.junit.Assert.assertThrows\nimport org.junit.Assert.assertTrue\nimport org.junit.BeforeClass\nimport org.junit.Test\nimport org.neo4j.Neo4jContainerExtension\nimport org.neo4j.driver.exceptions.ClientException\nimport org.neo4j.spark.SparkConnectorScalaSuiteWithApocIT.conf\nimport org.neo4j.spark.SparkConnectorScalaSuiteWithApocIT.server\nimport org.neo4j.spark.SparkConnectorScalaSuiteWithApocIT.ss\nimport org.neo4j.spark.TransactionTimeoutIT.NEO4J_LOW_TX_TIMEOUT\n\nimport java.util.TimeZone\n\nclass TransactionTimeoutIT extends SparkConnectorScalaSuiteWithApocIT {\n\n  @Test\n  def sparkConnectorRespectsTransactionTimeout(): Unit = {\n    val cypher = \"UNWIND range(1, 3) AS i \" +\n      \"CALL apoc.util.sleep(1000) \" +\n      \"RETURN i as number\"\n    val df = ss.read.format(\"org.neo4j.spark.DataSource\")\n      .option(\"url\", server.getBoltUrl)\n      .option(\"authentication.basic.username\", \"neo4j\")\n      .option(\"authentication.basic.password\", server.getAdminPassword)\n      .option(\"db.transaction.timeout\", \"4000\")\n      .option(\"query\", cypher)\n      .load()\n      .toDF()\n\n    val results = df.select(\"number\").rdd.map(_.getLong(0)).collect().toList\n    val expected = Range.inclusive(1, 3).map(_.toLong).toList\n\n    assertEquals(expected, results)\n  }\n\n  @Test\n  def sparkConnectorFailsWithTransactionTimeoutWhenSetOnSessionLevel(): Unit = {\n    val newConf = conf.clone().set(\"neo4j.url\", server.getBoltUrl)\n      .set(\"neo4j.authentication.basic.username\", \"neo4j\")\n      .set(\"neo4j.authentication.basic.password\", server.getAdminPassword)\n      .set(\"neo4j.db.transaction.timeout\", \"1000\")\n    val session = SparkSession.builder.config(newConf).getOrCreate()\n\n    val cypher = \"UNWIND range(1, 20) AS i \" +\n      \"CALL apoc.util.sleep(1000) \" +\n      \"RETURN i as number\"\n\n    val df = session.read.format(\"org.neo4j.spark.DataSource\")\n      .option(\"query\", cypher)\n\n    val exc = assertThrows(\n      classOf[ClientException],\n      () => {\n        df.load()\n          .toDF()\n          .select(\"number\").rdd.map(_.getLong(0)).collect().toList\n      }\n    )\n    assertTrue(exc.getMessage.contains(\"The transaction has been terminated\"))\n  }\n\n  @Test\n  def sparkConnectorFailsWithTransactionTimeoutWhenSetOnDatasourceLevel(): Unit = {\n    val newConf = conf.clone().set(\"neo4j.url\", server.getBoltUrl)\n      .set(\"neo4j.authentication.basic.username\", \"neo4j\")\n      .set(\"neo4j.authentication.basic.password\", server.getAdminPassword)\n    val session = SparkSession.builder.config(newConf).getOrCreate()\n\n    val cypher = \"UNWIND range(1, 20) AS i \" +\n      \"CALL apoc.util.sleep(1000) \" +\n      \"RETURN i as number\"\n\n    val df = session.read.format(\"org.neo4j.spark.DataSource\")\n      .option(\"query\", cypher)\n      .option(\"db.transaction.timeout\", \"1000\")\n\n    val exc = assertThrows(\n      classOf[ClientException],\n      () => {\n        df.load()\n          .toDF()\n          .select(\"number\").rdd.map(_.getLong(0)).collect().toList\n      }\n    )\n    assertTrue(exc.getMessage.contains(\"The transaction has been terminated\"))\n  }\n\n  @Test\n  def sparkConnectorExtendsDefaultTimeout(): Unit = {\n    val cypher = \"UNWIND range(1, 6) AS i \" +\n      \"CALL apoc.util.sleep(2000) \" +\n      \"RETURN i as number\"\n    val df = ss.read.format(\"org.neo4j.spark.DataSource\")\n      .option(\"url\", NEO4J_LOW_TX_TIMEOUT.getBoltUrl)\n      .option(\"authentication.basic.username\", \"neo4j\")\n      .option(\"authentication.basic.password\", NEO4J_LOW_TX_TIMEOUT.getAdminPassword)\n      .option(\"db.transaction.timeout\", \"15000\")\n      .option(\"query\", cypher)\n      .load()\n      .toDF()\n\n    val results = df.select(\"number\").rdd.map(_.getLong(0)).collect().toList\n    val expected = Range.inclusive(1, 6).map(_.toLong).toList\n\n    assertEquals(expected, results)\n  }\n\n}\n\nobject TransactionTimeoutIT {\n\n  private val NEO4J_LOW_TX_TIMEOUT = new Neo4jContainerExtension {\n    withNeo4jConfig(\"dbms.security.auth_enabled\", \"false\")\n    withEnv(\"NEO4J_ACCEPT_LICENSE_AGREEMENT\", \"yes\")\n    withEnv(\"NEO4JLABS_PLUGINS\", \"[\\\"apoc\\\"]\")\n    withEnv(\"NEO4J_db_temporal_timezone\", TimeZone.getDefault.getID)\n    withNeo4jConfig(\"db.transaction.timeout\", \"10s\")\n    withDatabases(Seq(\"db1\", \"db2\"))\n  }\n\n  @BeforeClass\n  def setUp(): Unit = {\n    NEO4J_LOW_TX_TIMEOUT.start()\n  }\n\n  @AfterClass\n  def tearDown() = {\n    TestUtil.closeSafely(NEO4J_LOW_TX_TIMEOUT)\n  }\n}\n"
  },
  {
    "path": "test-support/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n        xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.neo4j</groupId>\n        <artifactId>neo4j-connector-apache-spark_parent</artifactId>\n        <version>5.4.3-SNAPSHOT</version>\n    </parent>\n    <artifactId>neo4j-connector-apache-spark_test-support</artifactId>\n    <packaging>jar</packaging>\n    <name>neo4j-connector-apache-spark-test-support</name>\n    <description>Test Utilities for Neo4j Connector for Apache Spark using the binary Bolt Driver</description>\n    <properties>\n        <licensing.skip>true</licensing.skip>\n        <powermock.version>2.0.9</powermock.version>\n    </properties>\n    <dependencyManagement>\n        <dependencies>\n            <dependency>\n                <groupId>org.objenesis</groupId>\n                <artifactId>objenesis</artifactId>\n                <version>3.5</version>\n            </dependency>\n        </dependencies>\n    </dependencyManagement>\n    <dependencies>\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.hamcrest</groupId>\n            <artifactId>hamcrest</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.neo4j</groupId>\n            <artifactId>caniuse-core</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.neo4j</groupId>\n            <artifactId>caniuse-neo4j-detection</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.neo4j.driver</groupId>\n            <artifactId>neo4j-java-driver-slim</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.powermock</groupId>\n            <artifactId>powermock-api-mockito2</artifactId>\n            <version>${powermock.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.powermock</groupId>\n            <artifactId>powermock-module-junit4</artifactId>\n            <version>${powermock.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.scalatest</groupId>\n            <artifactId>scalatest_${scala.binary.version}</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.scalatestplus</groupId>\n            <artifactId>junit-4-13_${scala.binary.version}</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.testcontainers</groupId>\n            <artifactId>testcontainers</artifactId>\n            <exclusions>\n                <exclusion>\n                    <groupId>org.jetbrains</groupId>\n                    <artifactId>annotations</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n        <dependency>\n            <groupId>org.testcontainers</groupId>\n            <artifactId>testcontainers-neo4j</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.spark</groupId>\n            <artifactId>spark-core_${scala.binary.version}</artifactId>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.spark</groupId>\n            <artifactId>spark-sql_${scala.binary.version}</artifactId>\n            <scope>provided</scope>\n        </dependency>\n    </dependencies>\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>net.alchim31.maven</groupId>\n                <artifactId>scala-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-failsafe-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-deploy-plugin</artifactId>\n                <configuration>\n                    <skip>true</skip>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "test-support/src/main/java/org/neo4j/spark/Assert.java",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark;//\n// Source code recreated from a .class file by IntelliJ IDEA\n// (powered by Fernflower decompiler)\n//\n\nimport java.util.Arrays;\nimport java.util.concurrent.TimeUnit;\nimport java.util.function.Function;\nimport java.util.function.Supplier;\n\nimport org.hamcrest.Description;\nimport org.hamcrest.Matcher;\nimport org.hamcrest.MatcherAssert;\nimport org.hamcrest.StringDescription;\nimport org.hamcrest.core.StringContains;\n\npublic final class Assert {\n    private Assert() {\n    }\n\n    public interface ThrowingSupplier<T, E extends Exception> {\n        T get() throws E;\n\n        static <TYPE> ThrowingSupplier<TYPE, RuntimeException> throwingSupplier(final Supplier<TYPE> supplier) {\n            return new ThrowingSupplier<TYPE, RuntimeException>() {\n                public TYPE get() {\n                    return supplier.get();\n                }\n\n                public String toString() {\n                    return supplier.toString();\n                }\n            };\n        }\n    }\n\n    public interface ThrowingAction<E extends Exception> {\n        void apply() throws E;\n\n        static <E extends Exception> ThrowingAction<E> noop() {\n            return () -> {\n            };\n        }\n    }\n\n    public static <E extends Exception> void assertException(ThrowingAction<E> f, Class<?> typeOfException) {\n        assertException(f, typeOfException, (String) null);\n    }\n\n    public static <E extends Exception> void assertException(ThrowingAction<E> f, Class<?> typeOfException, String partOfErrorMessage) {\n        try {\n            f.apply();\n            org.junit.Assert.fail(\"Expected exception of type \" + typeOfException + \", but no exception was thrown\");\n        } catch (Exception var4) {\n            if (typeOfException.isInstance(var4)) {\n                if (partOfErrorMessage != null) {\n                    MatcherAssert.assertThat(var4.getMessage(), StringContains.containsString(partOfErrorMessage));\n                }\n            } else {\n                org.junit.Assert.fail(\"Got unexpected exception \" + var4.getClass() + \"\\nExpected: \" + typeOfException);\n            }\n        }\n\n    }\n\n    public static <T, E extends Exception> void assertEventually(ThrowingSupplier<T, E> actual, Matcher<? super T> matcher, long timeout, TimeUnit timeUnit) throws E, InterruptedException {\n        assertEventually((ignored) -> {\n            return \"\";\n        }, actual, matcher, timeout, timeUnit);\n    }\n\n    public static <T, E extends Exception> void assertEventually(String reason, ThrowingSupplier<T, E> actual, Matcher<? super T> matcher, long timeout, TimeUnit timeUnit) throws E, InterruptedException {\n        assertEventually((ignored) -> {\n            return reason;\n        }, actual, matcher, timeout, timeUnit);\n    }\n\n    public static <T, E extends Exception> void assertEventually(Function<T, String> reason, ThrowingSupplier<T, E> actual, Matcher<? super T> matcher, long timeout, TimeUnit timeUnit) throws E, InterruptedException {\n        long endTimeMillis = System.currentTimeMillis() + timeUnit.toMillis(timeout);\n\n        while (true) {\n            long sampleTime = System.currentTimeMillis();\n            T last = actual.get();\n            boolean matched = matcher.matches(last);\n            if (matched || sampleTime > endTimeMillis) {\n                if (!matched) {\n                    Description description = new StringDescription();\n                    description.appendText((String) reason.apply(last)).appendText(\"\\nExpected: \").appendDescriptionOf(matcher).appendText(\"\\n     but: \");\n                    matcher.describeMismatch(last, description);\n                    throw new AssertionError(\"Timeout hit (\" + timeout + \" \" + timeUnit.toString().toLowerCase() + \") while waiting for condition to match: \" + description.toString());\n                } else {\n                    return;\n                }\n            }\n\n            Thread.sleep(100L);\n        }\n    }\n\n    private static AssertionError newAssertionError(String message, Object expected, Object actual) {\n        return new AssertionError((message != null && !message.isEmpty() ? message + \"\\n\" : \"\") + \"Expected: \" + prettyPrint(expected) + \", actual: \" + prettyPrint(actual));\n    }\n\n    private static String prettyPrint(Object o) {\n        if (o == null) {\n            return \"null\";\n        }\n\n        Class<?> clazz = o.getClass();\n        if (clazz.isArray()) {\n            if (clazz == byte[].class) {\n                return Arrays.toString((byte[]) o);\n            } else if (clazz == short[].class) {\n                return Arrays.toString((short[]) o);\n            } else if (clazz == int[].class) {\n                return Arrays.toString((int[]) o);\n            } else if (clazz == long[].class) {\n                return Arrays.toString((long[]) o);\n            } else if (clazz == float[].class) {\n                return Arrays.toString((float[]) o);\n            } else if (clazz == double[].class) {\n                return Arrays.toString((double[]) o);\n            } else if (clazz == char[].class) {\n                return Arrays.toString((char[]) o);\n            } else if (clazz == boolean[].class) {\n                return Arrays.toString((boolean[]) o);\n            } else {\n                return Arrays.deepToString((Object[]) o);\n            }\n        } else {\n            return String.valueOf(o);\n        }\n    }\n}\n\n"
  },
  {
    "path": "test-support/src/main/resources/simplelogger.properties",
    "content": "org.slf4j.simpleLogger.defaultLogLevel=error\norg.slf4j.simpleLogger.showDateTime=true\norg.slf4j.simpleLogger.dateTimeFormat=yyyy-MM-dd'T'HH:mm:ss.SSS\n"
  },
  {
    "path": "test-support/src/main/scala/org/neo4j/Closeables.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j\n\nobject Closeables {\n\n  def use[A <: AutoCloseable, B](resource: A)(code: A ⇒ B): B =\n    try\n      code(resource)\n    finally\n      resource.close()\n\n}\n"
  },
  {
    "path": "test-support/src/main/scala/org/neo4j/Neo4jContainerExtension.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j\n\nimport org.neo4j.driver.AuthToken\nimport org.neo4j.driver.AuthTokens\nimport org.neo4j.driver.GraphDatabase\nimport org.neo4j.driver.SessionConfig\nimport org.neo4j.spark.TestUtil\nimport org.rnorth.ducttape.unreliables.Unreliables\nimport org.testcontainers.containers.wait.strategy.AbstractWaitStrategy\nimport org.testcontainers.containers.wait.strategy.WaitAllStrategy\nimport org.testcontainers.neo4j.Neo4jContainer\n\nimport java.time.Duration\nimport java.util.concurrent.Callable\nimport java.util.concurrent.TimeUnit\n\nimport scala.collection.JavaConverters._\nimport scala.io.Source\n\nclass DatabasesWaitStrategy(private val auth: AuthToken) extends AbstractWaitStrategy {\n  private var databases = Seq.empty[String]\n\n  def forDatabases(dbs: Seq[String]): DatabasesWaitStrategy = {\n    databases ++= dbs\n    this\n  }\n\n  override def waitUntilReady(): Unit = {\n    val boltUrl = s\"bolt://${waitStrategyTarget.getHost}:${waitStrategyTarget.getMappedPort(7687)}\"\n    val driver = GraphDatabase.driver(boltUrl, auth)\n    try {\n      Unreliables.retryUntilSuccess(\n        startupTimeout.getSeconds.toInt,\n        TimeUnit.SECONDS,\n        new Callable[Unit] {\n          override def call(): Unit = {\n            val session = driver.session(SessionConfig.forDatabase(\"system\"))\n            try {\n              databases.foreach { db =>\n                session.writeTransaction(tx => tx.run(s\"CREATE DATABASE $db IF NOT EXISTS WAIT 30 SECONDS\").consume())\n\n                val status = session.readTransaction(tx => {\n                  tx.run(s\"SHOW DATABASE $db YIELD currentStatus\").single().get(\"currentStatus\").asString()\n                })\n                if (status != \"online\") {\n                  throw new RuntimeException(s\"Database $db is not online yet, current status: $status\")\n                }\n              }\n            } finally {\n              session.close()\n            }\n          }\n        }\n      )\n    } finally {\n      driver.close()\n    }\n  }\n}\n\n// docker pull neo4j/neo4j-experimental:4.0.0-rc01-enterprise\nclass Neo4jContainerExtension\n    extends Neo4jContainer(\n      TestUtil.neo4jImage()\n    ) {\n  private var databases: Seq[String] = Seq.empty\n\n  private var fixture: Set[(String, String)] = Set.empty\n\n  def withDatabases(dbs: Seq[String]): Neo4jContainerExtension = {\n    databases ++= dbs\n    this\n  }\n\n  def withFixture(database: String, path: String): Neo4jContainerExtension = {\n    fixture ++= Set((database, path))\n    this\n  }\n\n  private def createAuth(): AuthToken =\n    if (getAdminPassword.nonEmpty) AuthTokens.basic(\"neo4j\", getAdminPassword) else AuthTokens.none()\n\n  override def start(): Unit = {\n    if (databases.nonEmpty) {\n      val waitAllStrategy = waitStrategy.asInstanceOf[WaitAllStrategy]\n      waitAllStrategy.withStrategy(\n        new DatabasesWaitStrategy(createAuth()).forDatabases(databases).withStartupTimeout(Duration.ofMinutes(2))\n      )\n    }\n    addEnv(\"NEO4J_ACCEPT_LICENSE_AGREEMENT\", \"yes\")\n    super.start()\n\n    if (fixture.nonEmpty) {\n      val driver = GraphDatabase.driver(this.getBoltUrl, createAuth())\n      try {\n        fixture.foreach(t => {\n          val session = driver.session(SessionConfig.forDatabase(t._1))\n          try {\n            val lines = Source.fromResource(t._2)\n              .mkString(\"\\n\")\n              .split(\";\")\n            lines.foreach(line => session.run(line))\n          } finally {\n            TestUtil.closeSafely(session)\n          }\n        })\n      } finally {\n        TestUtil.closeSafely(driver)\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "test-support/src/main/scala/org/neo4j/spark/RowUtil.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark\n\nimport org.apache.spark.sql.Row\n\nobject RowUtil {\n  def getByName[T](row: Row, name: String): T = row.getAs[T](row.fieldIndex(name))\n}\n"
  },
  {
    "path": "test-support/src/main/scala/org/neo4j/spark/SparkConnectorScalaBaseTSE.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark\n\nimport org.apache.spark.SparkConf\nimport org.apache.spark.sql.SparkSession\nimport org.junit._\nimport org.junit.rules.TestName\nimport org.neo4j.Closeables.use\nimport org.scalatestplus.junit.AssertionsForJUnit\n\nimport scala.annotation.meta.getter\n\nobject SparkConnectorScalaBaseTSE {\n\n  private var startedFromSuite = true\n\n  @BeforeClass\n  def setUpContainer() = {\n    if (!SparkConnectorScalaSuiteIT.server.isRunning) {\n      startedFromSuite = false\n      SparkConnectorScalaSuiteIT.setUpContainer()\n    }\n  }\n\n  @AfterClass\n  def tearDownContainer() = {\n    if (!startedFromSuite) {\n      SparkConnectorScalaSuiteIT.tearDownContainer()\n    }\n  }\n\n}\n\nclass SparkConnectorScalaBaseTSE extends AssertionsForJUnit {\n  val conf: SparkConf = SparkConnectorScalaSuiteIT.conf\n  val ss: SparkSession = SparkConnectorScalaSuiteIT.ss\n\n  @(Rule @getter)\n  val testName: TestName = new TestName\n\n  @Before\n  def before(): Unit = {\n    use(SparkConnectorScalaSuiteIT.session(\"system\")) { session =>\n      session\n        .run(\"CREATE OR REPLACE DATABASE neo4j WAIT 30 seconds\").consume()\n    }\n  }\n\n  @After\n  def after(): Unit = {\n    ss.catalog.listTables()\n      .collect()\n      .foreach(t => ss.catalog.dropTempView(t.name))\n    ss.catalog.listTables()\n      .collect()\n      .foreach(t => ss.catalog.dropGlobalTempView(t.name))\n  }\n}\n"
  },
  {
    "path": "test-support/src/main/scala/org/neo4j/spark/SparkConnectorScalaBaseWithApocTSE.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark\n\nimport org.apache.spark.SparkConf\nimport org.apache.spark.sql.SparkSession\nimport org.hamcrest.Matchers\nimport org.junit._\nimport org.junit.rules.TestName\nimport org.neo4j.Closeables.use\nimport org.neo4j.driver.Transaction\nimport org.neo4j.driver.TransactionWork\nimport org.neo4j.driver.summary.ResultSummary\nimport org.neo4j.spark\n\nimport java.util.concurrent.TimeUnit\n\nimport scala.annotation.meta.getter\n\nobject SparkConnectorScalaBaseWithApocTSE {\n\n  private var startedFromSuite = true\n\n  @BeforeClass\n  def setUpContainer() = {\n    if (!SparkConnectorScalaSuiteWithApocIT.server.isRunning) {\n      startedFromSuite = false\n      SparkConnectorScalaSuiteWithApocIT.setUpContainer()\n    }\n  }\n\n  @AfterClass\n  def tearDownContainer() = {\n    if (!startedFromSuite) {\n      SparkConnectorScalaSuiteWithApocIT.tearDownContainer()\n    }\n  }\n\n}\n\nclass SparkConnectorScalaBaseWithApocTSE {\n\n  val conf: SparkConf = SparkConnectorScalaSuiteWithApocIT.conf\n  val ss: SparkSession = SparkConnectorScalaSuiteWithApocIT.ss\n\n  @(Rule @getter)\n  val testName: TestName = new TestName\n\n  @Before\n  def before() {\n    use(SparkConnectorScalaSuiteWithApocIT.session(\"system\")) {\n      session =>\n        session.run(\"CREATE OR REPLACE DATABASE neo4j WAIT 30 seconds\")\n          .consume()\n    }\n  }\n\n}\n"
  },
  {
    "path": "test-support/src/main/scala/org/neo4j/spark/SparkConnectorScalaSuiteIT.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark\n\nimport org.apache.spark.SparkConf\nimport org.apache.spark.sql.SparkSession\nimport org.junit.AfterClass\nimport org.junit.Assume\nimport org.junit.BeforeClass\nimport org.neo4j.Neo4jContainerExtension\nimport org.neo4j.caniuse.Neo4j\nimport org.neo4j.caniuse.Neo4jDetector\nimport org.neo4j.driver._\n\nimport java.io.File\nimport java.nio.file.Files\nimport java.util.TimeZone\n\nobject SparkConnectorScalaSuiteIT {\n\n  val server: Neo4jContainerExtension = new Neo4jContainerExtension {\n    withNeo4jConfig(\"dbms.security.auth_enabled\", \"false\")\n    withEnv(\"NEO4J_ACCEPT_LICENSE_AGREEMENT\", \"yes\")\n    withEnv(\"NEO4J_db_temporal_timezone\", TimeZone.getDefault.getID)\n    withDatabases(Seq(\"db1\", \"db2\"))\n  }\n\n  var conf: SparkConf = _\n  var ss: SparkSession = _\n  var driver: Driver = _\n  var tmpDir: File = _\n  var neo4j: Neo4j = _\n\n  @BeforeClass\n  def setUpContainer(): Unit = {\n    if (!server.isRunning) {\n      try {\n        server.start()\n      } catch {\n        case _: Throwable => //\n      }\n      Assume.assumeTrue(\"Neo4j container is not started\", server.isRunning)\n      tmpDir = Files.createTempDirectory(\"spark-warehouse\").toFile\n      tmpDir.deleteOnExit()\n      conf = new SparkConf()\n        .setAppName(\"neoTest\")\n        .setMaster(\"local[*]\")\n        .set(\"spark.driver.host\", \"127.0.0.1\")\n        .set(\"spark.sql.warehouse.dir\", tmpDir.getAbsolutePath)\n      ss = SparkSession.builder.config(conf).getOrCreate()\n      driver = GraphDatabase.driver(server.getBoltUrl, AuthTokens.none())\n      neo4j = Neo4jDetector.INSTANCE.detect(driver)\n    }\n  }\n\n  @AfterClass\n  def tearDownContainer() = {\n    TestUtil.closeSafely(driver)\n    TestUtil.closeSafely(server)\n    TestUtil.closeSafely(ss)\n  }\n\n  def session(database: String = \"\"): Session = {\n    if (database.isEmpty) {\n      driver.session()\n    } else {\n      driver.session(SessionConfig.forDatabase(database))\n    }\n  }\n}\n\nclass SparkConnectorScalaSuiteIT {}\n"
  },
  {
    "path": "test-support/src/main/scala/org/neo4j/spark/SparkConnectorScalaSuiteWithApocIT.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark\n\nimport org.apache.spark.SparkConf\nimport org.apache.spark.sql.SparkSession\nimport org.junit.AfterClass\nimport org.junit.Assume\nimport org.junit.BeforeClass\nimport org.neo4j.Neo4jContainerExtension\nimport org.neo4j.caniuse.Neo4j\nimport org.neo4j.caniuse.Neo4jDetector\nimport org.neo4j.driver._\n\nimport java.util.TimeZone\n\nobject SparkConnectorScalaSuiteWithApocIT {\n\n  val server: Neo4jContainerExtension = new Neo4jContainerExtension {\n    withNeo4jConfig(\"dbms.security.auth_enabled\", \"false\")\n    withEnv(\"NEO4J_ACCEPT_LICENSE_AGREEMENT\", \"yes\")\n    withEnv(\"NEO4JLABS_PLUGINS\", \"[\\\"apoc\\\"]\")\n    withEnv(\"NEO4J_db_temporal_timezone\", TimeZone.getDefault.getID)\n    withDatabases(Seq(\"db1\", \"db2\"))\n  }\n\n  var conf: SparkConf = _\n  var ss: SparkSession = _\n  var driver: Driver = _\n  var neo4j: Neo4j = _\n\n  @BeforeClass\n  def setUpContainer(): Unit = {\n    if (!server.isRunning) {\n      try {\n        server.start()\n      } catch {\n        case _: Throwable => //\n      }\n      Assume.assumeTrue(\"Neo4j container is not started\", server.isRunning)\n      conf = new SparkConf()\n        .setAppName(\"neoTest\")\n        .setMaster(\"local[*]\")\n        .set(\"spark.driver.host\", \"127.0.0.1\")\n      ss = SparkSession.builder.config(conf).getOrCreate()\n      driver = GraphDatabase.driver(server.getBoltUrl, AuthTokens.none())\n      neo4j = Neo4jDetector.INSTANCE.detect(driver)\n    }\n    Assume.assumeTrue(\"Neo4j Preview versions doesn't have APOC\", TestUtil.hasApoc(session()))\n  }\n\n  @AfterClass\n  def tearDownContainer() = {\n    TestUtil.closeSafely(driver)\n    TestUtil.closeSafely(server)\n    TestUtil.closeSafely(ss)\n  }\n\n  def session(database: String = \"\"): Session = {\n    if (database.isEmpty) {\n      driver.session()\n    } else {\n      driver.session(SessionConfig.forDatabase(database))\n    }\n  }\n}\n\nclass SparkConnectorScalaSuiteWithApocIT {}\n"
  },
  {
    "path": "test-support/src/main/scala/org/neo4j/spark/SparkConnectorScalaSuiteWithGdsBase.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark\n\nimport org.apache.spark.SparkConf\nimport org.apache.spark.sql.SparkSession\nimport org.junit.AfterClass\nimport org.junit.Assume\nimport org.junit.Before\nimport org.junit.BeforeClass\nimport org.junit.Rule\nimport org.junit.rules.TestName\nimport org.neo4j.Closeables.use\nimport org.neo4j.Neo4jContainerExtension\nimport org.neo4j.caniuse.Neo4j\nimport org.neo4j.caniuse.Neo4jDetector\nimport org.neo4j.driver._\n\nimport java.util.TimeZone\n\nimport scala.annotation.meta.getter\n\nobject SparkConnectorScalaSuiteWithGdsBase {\n\n  val server: Neo4jContainerExtension = new Neo4jContainerExtension {\n    withNeo4jConfig(\"dbms.security.auth_enabled\", \"false\")\n    withEnv(\"NEO4J_ACCEPT_LICENSE_AGREEMENT\", \"yes\")\n    withEnv(\"NEO4JLABS_PLUGINS\", \"[\\\"graph-data-science\\\"]\")\n    withEnv(\"NEO4J_db_temporal_timezone\", TimeZone.getDefault.getID)\n    withDatabases(Seq(\"db1\", \"db2\"))\n  }\n\n  var conf: SparkConf = _\n  var ss: SparkSession = _\n  var driver: Driver = _\n  var neo4j: Neo4j = _\n\n  @BeforeClass\n  def setUpContainer(): Unit = {\n    if (!server.isRunning) {\n      try {\n        server.start()\n      } catch {\n        case _: Throwable => //\n      }\n      Assume.assumeTrue(\"Neo4j container is not started\", server.isRunning)\n      conf = new SparkConf()\n        .setAppName(\"neoTest\")\n        .setMaster(\"local[*]\")\n        .set(\"spark.driver.host\", \"127.0.0.1\")\n      ss = SparkSession.builder.config(conf).getOrCreate()\n      driver = GraphDatabase.driver(server.getBoltUrl, AuthTokens.none())\n      neo4j = Neo4jDetector.INSTANCE.detect(driver)\n    }\n  }\n\n  @AfterClass\n  def tearDownContainer(): Unit = {\n    TestUtil.closeSafely(driver)\n    TestUtil.closeSafely(server)\n    TestUtil.closeSafely(ss)\n  }\n\n  def session(database: String = \"\"): Session = {\n    if (database.isEmpty) {\n      driver.session()\n    } else {\n      driver.session(SessionConfig.forDatabase(database))\n    }\n  }\n}\n\nclass SparkConnectorScalaSuiteWithGdsBase {\n\n  val conf: SparkConf = SparkConnectorScalaSuiteWithGdsBase.conf\n  val ss: SparkSession = SparkConnectorScalaSuiteWithGdsBase.ss\n\n  @(Rule @getter)\n  val testName: TestName = new TestName\n\n  @Before\n  def before(): Unit = {\n    use(SparkConnectorScalaSuiteWithGdsBase.session(\"system\")) {\n      session =>\n        session.run(\"CREATE OR REPLACE DATABASE neo4j WAIT 30 seconds\")\n          .consume()\n    }\n  }\n}\n"
  },
  {
    "path": "test-support/src/main/scala/org/neo4j/spark/TestUtil.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark\n\nimport org.neo4j.driver.Session\nimport org.neo4j.driver.Transaction\nimport org.slf4j.Logger\nimport org.testcontainers.utility.DockerImageName\n\nimport java.util.Properties\n\ncase class Version(major: Int, minor: Int, patch: Int) {\n\n  override def toString: String = s\"${major}.${minor}.${patch}\"\n}\n\nobject Version {\n  implicit val ordering: Ordering[Version] = Ordering.by(v => (v.major, v.minor, v.patch))\n\n  def parse(version: String): Version = {\n    val fields = version.split(\"\\\\.\")\n      .map(field => {\n        val additionalInfoIndex = field.indexOf('-')\n        if (additionalInfoIndex.equals(-1)) field\n        else field.substring(0, additionalInfoIndex)\n      })\n      .map(_.toInt)\n      .toList\n\n    Version(fields.head, fields(1), fields(2))\n  }\n\n}\n\nobject Versions {\n\n  val GDS_2_4: Version = Version(2, 4, 0)\n  val GDS_2_5: Version = Version(2, 5, 0)\n  val NEO4J_4_4: Version = Version(4, 4, 0)\n  val NEO4J_5: Version = Version(5, 0, 0)\n  val NEO4J_5_13: Version = Version(5, 13, 0)\n\n}\n\nobject TestUtil {\n\n  def neo4jImage(): DockerImageName = {\n    val image = Option(System.getenv(\"NEO4J_TEST_IMAGE\"))\n      .map(_.trim)\n      .filter(_.nonEmpty) // avoids Java 11-only isBlank\n      .getOrElse(throw new IllegalArgumentException(\"NEO4J_TEST_IMAGE environment variable is not defined!\"))\n    DockerImageName.parse(image).asCompatibleSubstituteFor(\"neo4j\")\n  }\n\n  def gdsVersion(session: Session): Version = {\n    Version.parse(session.run(\n      \"CALL gds.debug.sysInfo() YIELD key, value WHERE key = 'gdsVersion' RETURN value\"\n    ).single().get(0).asString())\n  }\n\n  def neo4jVersion(session: Session): Version = {\n    Version.parse(session.run(\n      \"CALL dbms.components() YIELD name, versions WHERE name = 'Neo4j Kernel' RETURN versions[0]\"\n    ).single().get(0).asString())\n  }\n\n  def hasApoc(session: Session): Boolean = {\n    val result = session.run(\n      \"SHOW PROCEDURES YIELD name RETURN any(x IN collect(name) WHERE x STARTS WITH 'apoc.') AS hasApoc\"\n    )\n    result.single().get(\"hasApoc\").asBoolean()\n  }\n\n  def closeSafely(autoCloseable: AutoCloseable, logger: Logger = null): Unit = {\n    try {\n      autoCloseable match {\n        case s: Session     => if (s.isOpen) s.close()\n        case t: Transaction => if (t.isOpen) t.close()\n        case null           => ()\n        case _              => autoCloseable.close()\n      }\n    } catch {\n      case t: Throwable => if (logger != null) {\n          t.printStackTrace()\n          logger.warn(s\"Cannot close ${autoCloseable.getClass.getSimpleName} because of the following exception:\", t)\n        }\n    }\n  }\n\n}\n"
  },
  {
    "path": "test-support/src/test/scala/org/neo4j/spark/VersionTest.scala",
    "content": "/*\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [https://neo4j.com]\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.neo4j.spark\n\nimport org.junit.Assert.assertEquals\nimport org.junit.Test\n\nclass VersionTest {\n\n  @Test\n  def parses_versions(): Unit = {\n    assertEquals(Version(5, 26, 399), Version.parse(\"5.26.399\"))\n    assertEquals(Version(2025, 11, 0), Version.parse(\"2025.11.0-41865\"))\n  }\n}\n"
  }
]