private void importSchema()

in core/src/main/java/com/jetbrains/youtrackdb/internal/core/db/tool/DatabaseImport.java [497:753]


  private void importSchema(boolean collectionsImported) throws IOException, ParseException {
    if (!collectionsImported) {
      removeDefaultCollections();
    }

    listener.onMessage("\nImporting database schema...");

    jsonReader.readNext(JSONReader.BEGIN_OBJECT);
    @SuppressWarnings("unused")
    var schemaVersion =
        jsonReader
            .readNext(JSONReader.FIELD_ASSIGNMENT)
            .checkContent("\"version\"")
            .readNumber(JSONReader.ANY_NUMBER, true);
    jsonReader.readNext(JSONReader.COMMA_SEPARATOR);
    jsonReader.readNext(JSONReader.FIELD_ASSIGNMENT);
    // This can be removed after the M1 expires
    if (jsonReader.getValue().equals("\"globalProperties\"")) {
      jsonReader.readNext(JSONReader.BEGIN_COLLECTION);
      do {
        jsonReader.readNext(JSONReader.BEGIN_OBJECT);
        jsonReader.readNext(JSONReader.FIELD_ASSIGNMENT).checkContent("\"name\"");
        jsonReader.readString(JSONReader.NEXT_IN_OBJECT);
        jsonReader.readNext(JSONReader.FIELD_ASSIGNMENT).checkContent("\"global-id\"");
        jsonReader.readString(JSONReader.NEXT_IN_OBJECT);
        jsonReader.readNext(JSONReader.FIELD_ASSIGNMENT).checkContent("\"type\"");
        jsonReader.readString(JSONReader.NEXT_IN_OBJECT);
        jsonReader.readNext(JSONReader.NEXT_IN_ARRAY);
      } while (jsonReader.lastChar() == ',');
      jsonReader.readNext(JSONReader.COMMA_SEPARATOR);
      jsonReader.readNext(JSONReader.FIELD_ASSIGNMENT);
    }

    if (jsonReader.getValue().equals("\"blob-collections\"") ||
        jsonReader.getValue().equals("\"blob-clusters\"")) {
      var blobCollectionIds = jsonReader.readString(JSONReader.END_COLLECTION, true).trim();
      blobCollectionIds = blobCollectionIds.substring(1, blobCollectionIds.length() - 1);

      if (!blobCollectionIds.isEmpty()) {
        // READ BLOB COLLECTION IDS
        for (var i :
            StringSerializerHelper.split(
                blobCollectionIds, StringSerializerHelper.RECORD_SEPARATOR)) {
          var collection = Integer.parseInt(i.trim());
          if (!ArrayUtils.contains(session.getBlobCollectionIds(), collection)) {
            var name = session.getCollectionNameById(collection);
            session.addBlobCollection(name);
          }
        }
      }

      jsonReader.readNext(JSONReader.COMMA_SEPARATOR);
      jsonReader.readNext(JSONReader.FIELD_ASSIGNMENT);
    }

    jsonReader.checkContent("\"classes\"").readNext(JSONReader.BEGIN_COLLECTION);

    long classImported = 0;

    try {

      // creating V and E classes ahead of time, because they have to exist
      // before we start creating other vertex or edge classes.
      // we tried to fix this by making the export tool write these classes first,
      // but if the dump was created by an older version of the export tool,
      // it won't work.
      final var schema = session.getMetadata().getSchema();
      final var vertexClass = schema.existsClass(Vertex.CLASS_NAME) ?
          schema.getClass(Vertex.CLASS_NAME) : schema.createClass(Vertex.CLASS_NAME);
      final var edgeClass = schema.existsClass(Edge.CLASS_NAME) ?
          schema.getClass(Edge.CLASS_NAME) : schema.createClass(Edge.CLASS_NAME);
      do {
        jsonReader.readNext(JSONReader.BEGIN_OBJECT);
        var className =
            jsonReader
                .readNext(JSONReader.FIELD_ASSIGNMENT)
                .checkContent("\"name\"")
                .readString(JSONReader.COMMA_SEPARATOR);

        final var collectionIdsTag =
            exporterVersion >= 14 ? "\"collection-ids\"" : "\"cluster-ids\"";
        final var collectionIdsStr = jsonReader
            .readNext(JSONReader.FIELD_ASSIGNMENT)
            .checkContent(collectionIdsTag)
            .readString(JSONReader.END_COLLECTION, true)
            .trim();

        final var originalCollectionIds =
            StringSerializerHelper.splitIntArray(
                collectionIdsStr.substring(1, collectionIdsStr.length() - 1));

        // it's important to use previously created collections here because later the indexes
        // are created on collections (not on classes).
        final var newCollectionIds =
            Arrays.stream(originalCollectionIds)
                .map(collectionToCollectionMapping::get)
                .filter(cid -> cid != COLLECTION_NOT_FOUND_VALUE)
                .toArray();

        jsonReader.readNext(JSONReader.NEXT_IN_OBJECT);
        if (className.contains(".")) {
          // MIGRATE OLD NAME WITH . TO _
          final var newClassName = className.replace('.', '_');
          listener.onMessage(
              "\nWARNING: class '" + className + "' has been renamed in '" + newClassName + "'\n");

          className = newClassName;
        }

        Boolean strictMode = null;
        Boolean isAbstract = null;
        var isVertex = false;
        var isEdge = false;
        Map<String, String> customFields = null;
        List<Map<String, Object>> propertiesRaw = null;

        String value;
        while (jsonReader.lastChar() == ',') {
          jsonReader.readNext(JSONReader.FIELD_ASSIGNMENT);
          value = jsonReader.getValue();

          switch (value) {
            case "\"strictMode\"" -> strictMode = jsonReader.readBoolean(JSONReader.NEXT_IN_OBJECT);
            case "\"abstract\"" -> isAbstract = jsonReader.readBoolean(JSONReader.NEXT_IN_OBJECT);
            case "\"super-class\"" -> {
              // @compatibility <2.1 SINGLE CLASS ONLY
              final var classSuper = jsonReader.readString(JSONReader.NEXT_IN_OBJECT);

              if (SchemaClass.VERTEX_CLASS_NAME.equals(classSuper)) {
                isVertex = true;
              } else if (SchemaClass.EDGE_CLASS_NAME.equals(classSuper)) {
                isEdge = true;
              } else {
                final List<String> superClassNames = new ArrayList<>();
                superClassNames.add(classSuper);
                superClasses.put(className, superClassNames);
              }
            }
            case "\"super-classes\"" -> {
              // MULTIPLE CLASSES
              jsonReader.readNext(JSONReader.BEGIN_COLLECTION);

              final List<String> superClassNames = new ArrayList<>();
              while (jsonReader.lastChar() != ']') {
                jsonReader.readNext(JSONReader.NEXT_IN_ARRAY);

                final var clsName =
                    IOUtils.getStringContent(StringUtils.trim(jsonReader.getValue()));

                if (SchemaClass.VERTEX_CLASS_NAME.equals(clsName)) {
                  isVertex = true;
                } else if (SchemaClass.EDGE_CLASS_NAME.equals(clsName)) {
                  isEdge = true;
                } else {
                  superClassNames.add(clsName);
                }
              }

              if (!superClassNames.isEmpty()) {
                superClasses.put(className, superClassNames);
              }
              jsonReader.readNext(JSONReader.NEXT_IN_OBJECT);
            }
            case "\"properties\"" -> {
              propertiesRaw = new ArrayList<>();
              // GET PROPERTIES
              jsonReader.readNext(JSONReader.BEGIN_COLLECTION);

              while (jsonReader.lastChar() != ']') {
                final var pRaw = jsonReader.readNext(JSONReader.NEXT_IN_ARRAY).getValue();
                if (StringUtils.isNotBlank(pRaw)) {
                  final var pMap = jsonSerializer.mapFromJson(pRaw);
                  propertiesRaw.add(pMap);
                }
              }
              jsonReader.readNext(JSONReader.NEXT_IN_OBJECT);
            }
            case "\"cluster-selection\"" ->
              // ignoring old property
                jsonReader.readNext(JSONReader.NEXT_IN_OBJECT);
            case "\"customFields\"" -> {
              customFields = importCustomFields();
            }
          }
        }

        if (isVertex && isEdge) {
          throw new DatabaseImportException(
              "Class '" + className + "' cannot be both vertex and edge.");
        }

        var cls = schema.getClass(className);

        if (cls != null) {
          if (isVertex && !cls.isVertexType()) {
            throw new DatabaseImportException("Class '" + className
                + "' exists but is not a vertex class. It can't be made a vertex class.");
          } else if (isEdge && !cls.isEdgeType()) {
            throw new DatabaseImportException("Class '" + className
                + "' exists but is not an edge class. It can't be made an edge class."
            );
          }
        } else {
          if (collectionsImported) {
            // other superclasses will be added later.
            final var superClassesToAdd =
                isVertex ? new SchemaClass[]{vertexClass} :
                    isEdge ? new SchemaClass[]{edgeClass} :
                        new SchemaClass[]{};
            cls = schema.createClass(className, newCollectionIds, superClassesToAdd);
          } else if (className.equalsIgnoreCase("ORestricted")) {
            cls = schema.createAbstractClass(className);
          } else {
            cls = schema.createClass(className);
          }
        }

        if (strictMode != null) {
          cls.setStrictMode(strictMode);
        }
        if (isAbstract != null) {
          cls.setAbstract(isAbstract);
        }

        if (propertiesRaw != null) {
          for (var propRaw : propertiesRaw) {
            importProperty((SchemaClassInternal) cls, propRaw);
          }
        }

        if (customFields != null) {
          for (var cf : customFields.entrySet()) {
            cls.setCustom(cf.getKey(), cf.getValue());
          }
        }

        classImported++;

        jsonReader.readNext(JSONReader.NEXT_IN_ARRAY);
      } while (jsonReader.lastChar() == ',');

      this.rebuildCompleteClassInheritance();
      this.setLinkedClasses();

      if (exporterVersion < 11) {
        var role = session.getMetadata().getSchema().getClass(Role.CLASS_NAME);
        role.dropProperty("rules");
      }

      listener.onMessage("OK (" + classImported + " classes)");
      jsonReader.readNext(JSONReader.END_OBJECT);
      jsonReader.readNext(JSONReader.COMMA_SEPARATOR);
    } catch (final Exception e) {
      LogManager.instance().error(this, "Error on importing schema", e);
      listener.onMessage("ERROR (" + classImported + " entries): " + e);
    }
  }